diff options
Diffstat (limited to 'doc/rfc/rfc7811.txt')
-rw-r--r-- | doc/rfc/rfc7811.txt | 6611 |
1 files changed, 6611 insertions, 0 deletions
diff --git a/doc/rfc/rfc7811.txt b/doc/rfc/rfc7811.txt new file mode 100644 index 0000000..fb7051c --- /dev/null +++ b/doc/rfc/rfc7811.txt @@ -0,0 +1,6611 @@ + + + + + + +Internet Engineering Task Force (IETF) G. Enyedi +Request for Comments: 7811 A. Csaszar +Category: Standards Track Ericsson +ISSN: 2070-1721 A. Atlas + C. Bowers + Juniper Networks + A. Gopalan + University of Arizona + June 2016 + + + An Algorithm for Computing IP/LDP Fast Reroute + Using Maximally Redundant Trees (MRT-FRR) + +Abstract + + This document supports the solution put forth in "An Architecture for + IP/LDP Fast Reroute Using Maximally Redundant Trees (MRT-FRR)" + (RFC 7812) by defining the associated MRT Lowpoint algorithm that is + used in the Default MRT Profile to compute both the necessary + Maximally Redundant Trees with their associated next hops and the + alternates to select for MRT-FRR. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc7811. + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 1] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +Copyright Notice + + Copyright (c) 2016 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Requirements Language . . . . . . . . . . . . . . . . . . . . 5 + 3. Terminology and Definitions . . . . . . . . . . . . . . . . . 5 + 4. Algorithm Key Concepts . . . . . . . . . . . . . . . . . . . 6 + 4.1. Partial Ordering for Disjoint Paths . . . . . . . . . . . 7 + 4.2. Finding an Ear and the Correct Direction . . . . . . . . 8 + 4.3. Lowpoint Values and Their Uses . . . . . . . . . . . . . 11 + 4.4. Blocks in a Graph . . . . . . . . . . . . . . . . . . . . 14 + 4.5. Determining Localroot and Assigning Block-ID . . . . . . 16 + 5. MRT Lowpoint Algorithm Specification . . . . . . . . . . . . 18 + 5.1. Interface Ordering . . . . . . . . . . . . . . . . . . . 18 + 5.2. MRT Island Identification . . . . . . . . . . . . . . . . 21 + 5.3. GADAG Root Selection . . . . . . . . . . . . . . . . . . 21 + 5.4. Initialization . . . . . . . . . . . . . . . . . . . . . 22 + 5.5. Constructing the GADAG Using Lowpoint Inheritance . . . . 23 + 5.6. Augmenting the GADAG by Directing All Links . . . . . . . 25 + 5.7. Compute MRT Next Hops . . . . . . . . . . . . . . . . . . 29 + 5.7.1. MRT Next Hops to All Nodes Ordered with Respect to + the Computing Node . . . . . . . . . . . . . . . . . 29 + 5.7.2. MRT Next Hops to All Nodes Not Ordered with Respect + to the Computing Node . . . . . . . . . . . . . . . . 30 + 5.7.3. Computing Redundant Tree Next Hops in a 2-Connected + Graph . . . . . . . . . . . . . . . . . . . . . . . . 31 + 5.7.4. Generalizing for a Graph That Isn't 2-Connected . . . 33 + 5.7.5. Complete Algorithm to Compute MRT Next Hops . . . . . 34 + 5.8. Identify MRT Alternates . . . . . . . . . . . . . . . . . 36 + 5.9. Named Proxy-Nodes . . . . . . . . . . . . . . . . . . . . 44 + 5.9.1. Determining Proxy-Node Attachment Routers . . . . . . 45 + 5.9.2. Computing If an Island Neighbor (IN) Is Loop-Free . . 45 + 5.9.3. Computing MRT Next Hops for Proxy-Nodes . . . . . . . 47 + 5.9.4. Computing MRT Alternates for Proxy-Nodes . . . . . . 53 + + + +Enyedi, et al. Standards Track [Page 2] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + 6. MRT Lowpoint Algorithm: Next-Hop Conformance . . . . . . . . 61 + 7. Broadcast Interfaces . . . . . . . . . . . . . . . . . . . . 61 + 7.1. Computing MRT Next Hops on Broadcast Networks . . . . . . 62 + 7.2. Using MRT Next Hops as Alternates in the Event of + Failures on Broadcast Networks . . . . . . . . . . . . . 63 + 8. Evaluation of Alternative Methods for Constructing GADAGs . . 64 + 9. Operational Considerations . . . . . . . . . . . . . . . . . 66 + 9.1. GADAG Root Selection . . . . . . . . . . . . . . . . . . 67 + 9.2. Destination-Rooted GADAGs . . . . . . . . . . . . . . . . 67 + 10. Security Considerations . . . . . . . . . . . . . . . . . . . 67 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 68 + 11.1. Normative References . . . . . . . . . . . . . . . . . . 68 + 11.2. Informative References . . . . . . . . . . . . . . . . . 68 + Appendix A. Python Implementation of MRT Lowpoint Algorithm . . 70 + Appendix B. Constructing a GADAG Using SPFs . . . . . . . . . . 110 + Appendix C. Constructing a GADAG Using a Hybrid Method . . . . . 115 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 117 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 118 + +1. Introduction + + MRT Fast Reroute requires that packets can be forwarded not only on + the shortest-path tree, but also on two Maximally Redundant Trees + (MRTs), referred to as the MRT-Blue and the MRT-Red. A router that + experiences a local failure must also have predetermined which + alternate to use. This document defines how to compute these three + things for use in MRT-FRR and describes the algorithm design + decisions and rationale. The algorithm is based on those presented + in [MRTLinear] and expanded in [EnyediThesis]. The MRT Lowpoint + algorithm is required for implementation when the Default MRT Profile + is implemented. + + The MRT Lowpoint Algorithm defined in this document, when used for + MRT Fast-Reroute as described in [RFC7812], guarantees 100% recovery + for single failures when the network is 2-connected. This guaranteed + coverage does not depend on the link metrics, which an operator may + be using to traffic-engineer the IP network. Thus, the link metrics + and general network topology are largely decoupled from the + guaranteed coverage. + + Just as packets routed on a hop-by-hop basis require that each router + compute a shortest-path tree that is consistent, it is necessary for + each router to compute the MRT-Blue next hops and MRT-Red next hops + in a consistent fashion. This document defines the MRT Lowpoint + algorithm to be used as a standard in the Default MRT Profile for + MRT-FRR. + + + + + +Enyedi, et al. Standards Track [Page 3] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + A router's Forwarding Information Base (FIB) will continue to contain + primary next hops for the current shortest-path tree for forwarding + traffic. In addition, a router's FIB will contain primary next hops + for the MRT-Blue for forwarding received traffic on the MRT-Blue and + primary next hops for the MRT-Red for forwarding received traffic on + the MRT-Red. + + What alternate next hops a Point of Local Repair (PLR) selects need + not be consistent -- but loops must be prevented. To reduce + congestion, it is possible for multiple alternate next hops to be + selected; in the context of MRT alternates, each of those alternate + next hops would be equal-cost paths. + + This document defines an algorithm for selecting an appropriate MRT + alternate for consideration. Other alternates, e.g., Loop-Free + Alternates (LFAs) that are downstream paths, may be preferred when + available. See the "Operational Considerations" section of [RFC7812] + for a more detailed discussion of combining MRT alternates with those + produced by other FRR technologies. + + [E]---[D]---| [E]<--[D]<--| [E]-->[D]---| + | | | | ^ | | | + | | | V | | V V + [R] [F] [C] [R] [F] [C] [R] [F] [C] + | | | ^ ^ ^ | | + | | | | | | V | + [A]---[B]---| [A]-->[B]---| [A]<--[B]<--| + + (a) (b) (c) + A 2-connected graph MRT-Blue towards R MRT-Red towards R + + Figure 1 + + The MRT Lowpoint algorithm can handle arbitrary network topologies + where the whole network graph is not 2-connected, as in Figure 2, as + well as the easier case where the network graph is 2-connected + (Figure 1). Each MRT is a spanning tree. The pair of MRTs provide + two paths from every node X to the root of the MRTs. Those paths + share the minimum number of nodes and the minimum number of links. + Each such shared node is a cut-vertex. Any shared links are cut- + links. + + + + + + + + + + +Enyedi, et al. Standards Track [Page 4] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + [E]---[D]---| |---[J] + | | | | | + | | | | | + [R] [F] [C]---[G] | + | | | | | + | | | | | + [A]---[B]---| |---[H] + + (a) a graph that is not 2-connected + + [E]<--[D]<--| [J] [E]-->[D]---| |---[J] + | ^ | | | | | ^ + V | | | V V V | + [R] [F] [C]<--[G] | [R] [F] [C]<--[G] | + ^ ^ ^ | ^ | | | + | | | V | V | | + [A]-->[B]---| |---[H] [A]<--[B]<--| [H] + + (b) MRT-Blue towards R (c) MRT-Red towards R + + Figure 2: A Network That Is Not 2-Connected + +2. Requirements Language + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +3. Terminology and Definitions + + Please see the Terminology section of [RFC7812] for a complete list + of terminology relevant to this document. The list below does not + repeat terminology introduced in that RFC. + + spanning tree: A tree that contains links and that connects all + nodes in the network graph. + + back-edge: In the context of a spanning tree computed via a depth- + first search, a back-edge is a link that connects a descendant of + a node x with an ancestor of x. + + partial ADAG: A subset of an Almost Directed Acyclic Graph (ADAG) + that doesn't yet contain all the nodes in the block. A partial + ADAG is created during the MRT Lowpoint algorithm and then + expanded until all nodes in the block are included and it becomes + an ADAG. + + DFS: Depth-First Search + + + +Enyedi, et al. Standards Track [Page 5] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + DFS ancestor: A node n is a DFS ancestor of x if n is on the DFS- + tree path from the DFS root to x. + + DFS descendant: A node n is a DFS descendant of x if x is on the + DFS-tree path from the DFS root to n. + + ear: A path along nodes that are not yet included in the Generalized + ADAG (GADAG) that starts at a node that is already included in the + GADAG and that ends at a node that is already included in the + GADAG. The starting and ending nodes may be the same node if it + is a cut-vertex. + + X>>Y or Y<<X: Indicates the relationship between X and Y in a + partial order, such as found in a GADAG. X>>Y means that X is + higher in the partial order than Y. Y<<X means that Y is lower in + the partial order than X. + + X>Y or Y<X: Indicates the relationship between X and Y in the total + order, such as found via a topological sort. X>Y means that X is + higher in the total order than Y. Y<X means that Y is lower in + the total order than X. + + X ?? Y: Indicates that X is unordered with respect to Y in the + partial order. + + UNDIRECTED: In the GADAG, each link is marked as OUTGOING, INCOMING, + or both. Until the directionality of the link is determined, the + link is marked as UNDIRECTED to indicate that its direction hasn't + been determined. + + OUTGOING: A link marked as OUTGOING has direction in the GADAG from + the interface's router to the remote end. + + INCOMING: A link marked as INCOMING has direction in the GADAG from + the remote end to the interface's router. + +4. Algorithm Key Concepts + + There are five key concepts that are critical for understanding the + MRT Lowpoint algorithm. The first is the idea of partially ordering + the nodes in a network graph with regard to each other and to the + GADAG root. The second is the idea of finding an ear of nodes and + adding them in the correct direction. The third is the idea of a + Lowpoint value and how it can be used to identify cut-vertices and to + find a second path towards the root. The fourth is the idea that a + non-2-connected graph is made up of blocks, where a block is a + + + + + +Enyedi, et al. Standards Track [Page 6] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + 2-connected cluster, a cut-link or an isolated node. The fifth is + the idea of a localroot for each node; this is used to compute ADAGs + in each block. + +4.1. Partial Ordering for Disjoint Paths + + Given any two nodes X and Y in a graph, a particular total order + means that either X<Y or X>Y in that total order. An example would + be a graph where the nodes are ranked based upon their unique IP + loopback addresses. In a partial order, there may be some nodes for + which it can't be determined whether X<<Y or X>>Y. A partial order + can be captured in a directed graph, as shown in Figure 3. In a + graphical representation, a link directed from X to Y indicates that + X is a neighbor of Y in the network graph and X<<Y. + + [A]<---[R] [E] R << A << B << C << D << E + | ^ R << A << B << F << G << H << D << E + | | + V | Unspecified Relationships: + [B]--->[C]--->[D] C and F + | ^ C and G + | | C and H + V | + [F]--->[G]--->[H] + + + Figure 3: Directed Graph Showing a Partial Order + + To compute MRTs, the root of the MRTs is at both the very bottom and + the very top of the partial ordering. This means that from any node + X, one can pick nodes higher in the order until the root is reached. + Similarly, from any node X, one can pick nodes lower in the order + until the root is reached. For instance, in Figure 4, from G the + higher nodes picked can be traced by following the directed links and + are H, D, E, and R. Similarly, from G the lower nodes picked can be + traced by reversing the directed links and are F, B, A, and R. A + graph that represents this modified partial order is no longer a DAG; + it is termed an Almost DAG (ADAG) because if the links directed to + the root were removed, it would be a DAG. + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 7] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + [A]<---[R]<---[E] R << A << B << C << R + | ^ ^ R << A << B << C << D << E << R + | | | R << A << B << F << G << H << D << E << R + V | | + [B]--->[C]--->[D] Unspecified Relationships: + | ^ C and F + | | C and G + V | C and H + [F]--->[G]--->[H] + + + Figure 4: ADAG Showing a Partial Order with R Lowest and Highest + + Most importantly, if a node Y>>X, then Y can only appear on the + increasing path from X to the root and never on the decreasing path. + Similarly, if a node Z<<X, then Z can only appear on the decreasing + path from X to the root and never on the increasing path. + + When following the increasing paths, it is possible to pick multiple + higher nodes and still have the certainty that those paths will be + disjoint from the decreasing paths. For example, in the previous + example, node B has multiple possibilities to forward packets along + an increasing path: it can either forward packets to C or F. + +4.2. Finding an Ear and the Correct Direction + + For simplicity, the basic idea of creating a GADAG by adding ears is + described assuming that the network graph is a single 2-connected + cluster so that an ADAG is sufficient. Generalizing to multiple + blocks is done by considering the block-roots instead of the GADAG + root -- and the actual algorithm is given in Section 5.5. + + In order to understand the basic idea of finding an ADAG, first + suppose that we have already a partial ADAG, which doesn't contain + all the nodes in the block yet, and we want to extend it to cover all + the nodes. Suppose that we find a path from a node X to Y such that + X and Y are already contained by our partial ADAG, but all the + remaining nodes along the path are not added to the ADAG yet. We + refer to such a path as an "ear". + + Recall that our ADAG is closely related to a partial order. More + precisely, if we remove root R, the remaining DAG describes a partial + order of the nodes. If we suppose that neither X nor Y is the root, + we may be able to compare them. If one of them is definitely lesser + with respect to our partial order (say X<<Y), we can add the new path + to the ADAG in a direction from X to Y. As an example, consider + Figure 5. + + + + +Enyedi, et al. Standards Track [Page 8] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + E---D---| E<--D---| E<--D<--| + | | | | ^ | | ^ | + | | | V | | V | | + R F C R F C R F C + | | | | ^ | | ^ ^ + | | | V | | V | | + A---B---| A-->B---| A-->B---| + + (a) (b) (c) + + (a) A 2-connected graph + (b) Partial ADAG (C is not included) + (c) Resulting ADAG after adding path (or ear) B-C-D + + Figure 5 + + In this partial ADAG, node C is not yet included. However, we can + find path B-C-D, where both endpoints are contained by this partial + ADAG (we say those nodes are "ready" in the following text), and the + remaining node (node C) is not contained yet. If we remove R, the + remaining DAG defines a partial order, and with respect to this + partial order, we can say that B<<D; so, we can add the path to the + ADAG in the direction from B to D (arcs B->C and C->D are added). If + B>>D, we would add the same path in reverse direction. + + If, in the partial order where an ear's two ends are X and Y, X<<Y, + then there must already be a directed path from X to Y in the ADAG. + The ear must be added in a direction such that it doesn't create a + cycle; therefore, the ear must go from X to Y. + + In the case when X and Y are not ordered with each other, we can + select either direction for the ear. We have no restriction since + neither of the directions can result in a cycle. In the corner case + when one of the endpoints of an ear, say X, is the root (recall that + the two endpoints must be different), we could use both directions + again for the ear because the root can be considered both as smaller + and as greater than Y. However, we strictly pick that direction in + which the root is lower than Y. The logic for this decision is + explained in Section 5.7 + + A partial ADAG is started by finding a cycle from the root R back to + itself. This can be done by selecting a non-ready neighbor N of R + and then finding a path from N to R that doesn't use any links + between R and N. The direction of the cycle can be assigned either + way since it is starting the ordering. + + + + + + +Enyedi, et al. Standards Track [Page 9] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Once a partial ADAG is already present, it will always have a node + that is not the root R in it. The following is a brief proof that a + partial ADAG can always have ears added to it: just select a non- + ready neighbor N of a ready node Q, such that Q is not the root R, + find a path from N to the root R in the graph with Q removed. This + path is an ear where the first node of the ear is Q, the next is N, + then the path until the first ready node the path reached (that ready + node is the other endpoint of the path). Since the graph is + 2-connected, there must be a path from N to R without Q. + + It is always possible to select a non-ready neighbor N of a ready + node Q so that Q is not the root R. Because the network is + 2-connected, N must be connected to two different nodes and only one + can be R. Because the initial cycle has already been added to the + ADAG, there are ready nodes that are not R. Since the graph is + 2-connected, while there are non-ready nodes, there must be a non- + ready neighbor N of a ready node that is not R. + + Generic_Find_Ears_ADAG(root) + Create an empty ADAG. Add root to the ADAG. + Mark root as IN_GADAG. + Select an arbitrary cycle containing root. + Add the arbitrary cycle to the ADAG. + Mark cycle's nodes as IN_GADAG. + Add cycle's non-root nodes to process_list. + While there exist connected nodes in graph that are not IN_GADAG + Select a new ear. Let its endpoints be X and Y. + If Y is root or (Y<<X) + Add the ear towards X to the ADAG + Else // (a) X is root, or (b) X<<Y, or (c) X, Y not ordered + Add the ear towards Y to the ADAG + + Figure 6: Generic Algorithm to Find Ears and Their Direction in + 2-Connected Graph + + The algorithm in Figure 6 merely requires that a cycle or ear be + selected without specifying how. Regardless of the method for + selecting the path, we will get an ADAG. The method used for finding + and selecting the ears is important; shorter ears result in shorter + paths along the MRTs. The MRT Lowpoint algorithm uses the Lowpoint + Inheritance method for constructing an ADAG (and ultimately a GADAG). + This method is defined in Section 5.5. Other methods for + constructing GADAGs are described in Appendices B and C. An + evaluation of these different methods is given in Section 8. + + As an example, consider Figure 5 again. First, we select the + shortest cycle containing R, which can be R-A-B-F-D-E (uniform link + costs were assumed), so we get to the situation depicted in + + + +Enyedi, et al. Standards Track [Page 10] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Figure 5(b). Finally, we find a node next to a ready node; that must + be node C and assume we reached it from ready node B. We search a + path from C to R without B in the original graph. The first ready + node along this is node D, so the open ear is B-C-D. Since B<<D, we + add arc B->C and C->D to the ADAG. Since all the nodes are ready, we + stop at this point. + +4.3. Lowpoint Values and Their Uses + + A basic way of computing a spanning tree on a network graph is to run + a DFS, such as given in Figure 7. This tree has the important + property that if there is a link (x, n), then either n is a DFS + ancestor of x or n is a DFS descendant of x. In other words, either + n is on the path from the root to x or x is on the path from the root + to n. + + global_variable: dfs_number + + DFS_Visit(node x, node parent) + D(x) = dfs_number + dfs_number += 1 + x.dfs_parent = parent + for each link (x, w) + if D(w) is not set + DFS_Visit(w, x) + + Run_DFS(node gadag_root) + dfs_number = 0 + DFS_Visit(gadag_root, NONE) + + Figure 7: Basic DFS Algorithm + + Given a node x, one can compute the minimal DFS number of the + neighbors of x, i.e., min( D(w) if (x,w) is a link). This gives the + earliest attachment point neighboring x. What is interesting, + though, is the earliest attachment point from x and x's descendants. + This is what is determined by computing the Lowpoint value. + + In order to compute the low point value, the network is traversed + using DFS and the vertices are numbered based on the DFS walk. Let + this number be represented as DFS(x). All the edges that lead to + already-visited nodes during DFS walk are back-edges. The back-edges + are important because they give information about reachability of a + node via another path. + + + + + + + +Enyedi, et al. Standards Track [Page 11] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + The low point number is calculated by finding: + + Low(x) = Minimum of ( (DFS(x), + Lowest DFS(n, x->n is a back-edge), + Lowest Low(n, x->n is tree edge in DFS walk) ). + + A detailed algorithm for computing the lowpoint value is given in + Figure 8. Figure 9 illustrates how the Lowpoint algorithm applies to + an example graph. + + global_variable: dfs_number + + Lowpoint_Visit(node x, node parent, interface p_to_x) + D(x) = dfs_number + L(x) = D(x) + dfs_number += 1 + x.dfs_parent = parent + x.dfs_parent_intf = p_to_x.remote_intf + x.lowpoint_parent = NONE + for each ordered_interface intf of x + if D(intf.remote_node) is not set + Lowpoint_Visit(intf.remote_node, x, intf) + if L(intf.remote_node) < L(x) + L(x) = L(intf.remote_node) + x.lowpoint_parent = intf.remote_node + x.lowpoint_parent_intf = intf + else if intf.remote_node is not parent + if D(intf.remote_node) < L(x) + L(x) = D(intf.remote_node) + x.lowpoint_parent = intf.remote_node + x.lowpoint_parent_intf = intf + + Run_Lowpoint(node gadag_root) + dfs_number = 0 + Lowpoint_Visit(gadag_root, NONE, NONE) + + Figure 8: Computing Lowpoint Value + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 12] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + [E]---| [J]-------[I] [P]---[O] + | | | | | | + | | | | | | + [R] [D]---[C]--[F] [H]---[K] [N] + | | | | | | + | | | | | | + [A]--------[B] [G]---| [L]---[M] + + (a) a non-2-connected graph + + [E]----| [J]---------[I] [P]------[O] + (5, ) | (10, ) (9, ) (16, ) (15, ) + | | | | | | + | | | | | | + [R] [D]---[C]---[F] [H]----[K] [N] + (0, ) (4, ) (3, ) (6, ) (8, ) (11, ) (14, ) + | | | | | | + | | | | | | + [A]---------[B] [G]----| [L]------[M] + (1, ) (2, ) (7, ) (12, ) (13, ) + + (b) with DFS values assigned (D(x), L(x)) + + [E]----| [J]---------[I] [P]------[O] + (5,0) | (10,3) (9,3) (16,11) (15,11) + | | | | | | + | | | | | | + [R] [D]---[C]---[F] [H]----[K] [N] + (0,0) (4,0) (3,0) (6,3) (8,3) (11,11) (14,11) + | | | | | | + | | | | | | + [A]---------[B] [G]----| [L]------[M] + (1,0) (2,0) (7,3) (12,11) (13,11) + + (c) with lowpoint values assigned (D(x), L(x)) + + Figure 9: Example Lowpoint Value Computation + + From the lowpoint value and lowpoint parent, there are three very + useful things that motivate our computation. + + First, if there is a child c of x such that L(c) >= D(x), then there + are no paths in the network graph that go from c or its descendants + to an ancestor of x; therefore, x is a cut-vertex. In Figure 9, this + can be seen by looking at the DFS children of C. C has two children, + D and F and L(F) = 3 = D(C); so, it is clear that C is a cut-vertex + and F is in a block where C is the block's root. L(D) = 0<3 = D(C), + so D has a path to the ancestors of C; in this case, D can go via E + + + +Enyedi, et al. Standards Track [Page 13] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + to reach R. Comparing the lowpoint values of all a node's DFS- + children with the node's DFS-value is very useful because it allows + identification of the cut-vertices and thus the blocks. + + Second, by repeatedly following the path given by lowpoint_parent, + there is a path from x back to an ancestor of x that does not use the + link [x, x.dfs_parent] in either direction. The full path need not + be taken, but this gives a way of finding an initial cycle and then + ears. + + Third, as seen in Figure 9, even if L(x)<D(x), there may be a block + that contains both the root and a DFS-child of a node while other + DFS-children might be in different blocks. In this example, C's + child D is in the same block as R while F is not. It is important to + realize that the root of a block may also be the root of another + block. + +4.4. Blocks in a Graph + + A key idea for the MRT Lowpoint algorithm is that any non-2-connected + graph is made up by blocks (e.g., 2-connected clusters, cut-links, + and/or isolated nodes). To compute GADAGs and thus MRTs, computation + is done in each block to compute ADAGs or Redundant Trees and then + those ADAGs or Redundant Trees are combined into a GADAG or MRT. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 14] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + [E]---| [J]-------[I] [P]---[O] + | | | | | | + | | | | | | + [R] [D]---[C]--[F] [H]---[K] [N] + | | | | | | + | | | | | | + [A]--------[B] [G]---| [L]---[M] + + (a) A graph with four blocks: + three 2-connected clusters + and one cut-link + + + [E]<--| [J]<------[I] [P]<--[O] + | | | ^ | ^ + V | V | V | + [R] [D]<--[C] [F] [H]<---[K] [N] + ^ | ^ ^ + | V | | + [A]------->[B] [G]---| [L]-->[M] + + (b) MRT-Blue for destination R + + + [E]---| [J]-------->[I] [P]-->[O] + | | | + V V V + [R] [D]-->[C]<---[F] [H]<---[K] [N] + ^ | ^ | ^ | + | V | | | V + [A]<-------[B] [G]<--| [L]<--[M] + + (c) MRT-Red for destination R + + + Figure 10 + + Consider the example depicted in Figure 10 (a). In this figure, a + special graph is presented, showing us all the ways 2-connected + clusters can be connected. It has four blocks: block 1 contains R, + A, B, C, D, E; block 2 contains C, F, G, H, I, J; block 3 contains K, + L, M, N, O, P; and block 4 is a cut-link containing H and K. As can + be observed, the first two blocks have one common node (node C) and + blocks 2 and 3 do not have any common node, but they are connected + through a cut-link that is block 4. No two blocks can have more than + one common node, since two blocks with at least two common nodes + would qualify as a single 2-connected cluster. + + + + +Enyedi, et al. Standards Track [Page 15] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Moreover, observe that if we want to get from one block to another, + we must use a cut-vertex (the cut-vertices in this graph are C, H, + K), regardless of the path selected, so we can say that all the paths + from block 3 along the MRTs rooted at R will cross K first. This + observation means that if we want to find a pair of MRTs rooted at R, + then we need to build up a pair of RTs in block 3 with K as a root. + Similarly, we need to find another pair of RTs in block 2 with C as a + root, and finally, we need the last pair of RTs in block 1 with R as + a root. When all the trees are selected, we can simply combine them; + when a block is a cut-link (as in block 4), that cut-link is added in + the same direction to both of the trees. The resulting trees are + depicted in Figure 10 (b) and (c). + + Similarly, to create a GADAG it is sufficient to compute ADAGs in + each block and connect them. + + It is necessary, therefore, to identify the cut-vertices, the blocks + and identify the appropriate localroot to use for each block. + +4.5. Determining Localroot and Assigning Block-ID + + Each node in a network graph has a localroot, which is the cut-vertex + (or root) in the same block that is closest to the root. The + localroot is used to determine whether two nodes share a common + block. + + Compute_Localroot(node x, node localroot) + x.localroot = localroot + for each DFS child node c of x + if L(c) < D(x) //x is not a cut-vertex + Compute_Localroot(c, x.localroot) + else + mark x as cut-vertex + Compute_Localroot(c, x) + + Compute_Localroot(gadag_root, gadag_root) + + Figure 11: A Method for Computing Localroots + + There are two different ways of computing the localroot for each + node. The stand-alone method is given in Figure 11 and better + illustrates the concept; it is used by the GADAG construction methods + given in Appendices B and C. The MRT Lowpoint algorithm computes the + localroot for a block as part of computing the GADAG using lowpoint + inheritance; the essence of this computation is given in Figure 12. + Both methods for computing the localroot produce the same results. + + + + + +Enyedi, et al. Standards Track [Page 16] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Get the current node, s. + Compute an ear (either through lowpoint inheritance + or by following dfs parents) from s to a ready node e. + (Thus, s is not e, if there is such ear.) + if s is e + for each node x in the ear that is not s + x.localroot = s + else + for each node x in the ear that is not s or e + x.localroot = e.localroot + + Figure 12: Ear-Based Method for Computing Localroots + + Once the localroots are known, two nodes X and Y are in a common + block if and only if one of the following three conditions apply. + + o Y's localroot is X's localroot : They are in the same block and + neither is the cut-vertex closest to the root. + + o Y's localroot is X: X is the cut-vertex closest to the root for + Y's block + + o Y is X's localroot: Y is the cut-vertex closest to the root for + X's block + + Once we have computed the localroot for each node in the network + graph, we can assign for each node, a Block-ID that represents the + block in which the node is present. This computation is shown in + Figure 13. + + global_var: max_block_id + + Assign_Block_ID(x, cur_block_id) + x.block_id = cur_block_id + foreach DFS child c of x + if (c.local_root is x) + max_block_id += 1 + Assign_Block_ID(c, max_block_id) + else + Assign_Block_ID(c, cur_block_id) + + max_block_id = 0 + Assign_Block_ID(gadag_root, max_block_id) + + Figure 13: Assigning Block-ID to Identify Blocks + + + + + + +Enyedi, et al. Standards Track [Page 17] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +5. MRT Lowpoint Algorithm Specification + + The MRT Lowpoint algorithm computes one GADAG that is then used by a + router to determine its MRT-Blue and MRT-Red next hops to all + destinations. Finally, based upon that information, alternates are + selected for each next hop to each destination. The different parts + of this algorithm are described below. + + o Order the interfaces in the network graph. See Section 5.1. + + o Compute the local MRT Island for the particular MRT Profile. See + Section 5.2. + + o Select the root to use for the GADAG. See Section 5.3. + + o Initialize all interfaces to UNDIRECTED. See Section 5.4. + + o Compute the DFS value, e.g., D(x), and lowpoint value, L(x). See + Figure 8. + + o Construct the GADAG. See Section 5.5. + + o Assign directions to all interfaces that are still UNDIRECTED. + See Section 5.6. + + o From the computing router x, compute the next hops for the MRT- + Blue and MRT-Red. See Section 5.7. + + o Identify alternates for each next hop to each destination by + determining which one of the MRT-Blue and the MRT-Red the + computing router x should select. See Section 5.8. + + A Python implementation of this algorithm is given in Appendix A. + +5.1. Interface Ordering + + To ensure consistency in computation, all routers MUST order + interfaces identically down to the set of links with the same metric + to the same neighboring node. This is necessary for the DFS in + Lowpoint_Visit in Section 4.3, where the selection order of the + interfaces to explore results in different trees. Consistent + interface ordering is also necessary for computing the GADAG, where + the selection order of the interfaces to use to form ears can result + in different GADAGs. It is also necessary for the topological sort + described in Section 5.8, where different topological sort orderings + can result in undirected links being added to the GADAG in different + directions. + + + + +Enyedi, et al. Standards Track [Page 18] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + The required ordering between two interfaces from the same router x + is given in Figure 14. + + Interface_Compare(interface a, interface b) + if a.metric < b.metric + return A_LESS_THAN_B + if b.metric < a.metric + return B_LESS_THAN_A + if a.neighbor.mrt_node_id < b.neighbor.mrt_node_id + return A_LESS_THAN_B + if b.neighbor.mrt_node_id < a.neighbor.mrt_node_id + return B_LESS_THAN_A + // Same metric to same node, so the order doesn't matter for + // interoperability. + return A_EQUAL_TO_B + + + Figure 14: Rules for Ranking Multiple Interfaces (Order Is from Low + to High) + + In Figure 14, if two interfaces on a router connect to the same + remote router with the same metric, the Interface_Compare function + returns A_EQUAL_TO_B. This is because the order in which those + interfaces are initially explored does not affect the final GADAG + produced by the algorithm described here. While only one of the + links will be added to the GADAG in the initial traversal, the other + parallel links will be added to the GADAG with the same direction + assigned during the procedure for assigning direction to UNDIRECTED + links described in Section 5.6. An implementation is free to apply + some additional criteria to break ties in interface ordering in this + situation, but those criteria are not specified here since they will + not affect the final GADAG produced by the algorithm. + + The Interface_Compare function in Figure 14 relies on the + interface.metric and the interface.neighbor.mrt_node_id values to + order interfaces. The exact source of these values for different + IGPs and applications is specified in Figure 15. The metric and + mrt_node_id values for OSPFv2, OSPFv3, and IS-IS provided here is + normative. The metric and mrt_node_id values for IS-IS Path Control + and Reservation (PCR) in this table should be considered + informational. The normative values are specified in [IEEE8021Qca]. + + + + + + + + + + +Enyedi, et al. Standards Track [Page 19] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + +--------------+-----------------------+-----------------------------+ + | IGP/flooding | mrt_node_id | metric of | + | protocol | of neighbor | interface | + | and | on interface | | + | application | | | + +--------------+-----------------------+-----------------------------+ + | OSPFv2 for | 4-octet Neighbor | 2-octet Metric field | + | IP/LDP FRR | Router ID in | for corresponding | + | | Link ID field for | point-to-point link | + | | corresponding | in Router-LSA | + | | point-to-point link | | + | | in Router-LSA | | + +--------------+-----------------------+-----------------------------+ + | OSPFv3 for | 4-octet Neighbor | 2-octet Metric field | + | IP/LDP FRR | Router ID field | for corresponding | + | | for corresponding | point-to-point link | + | | point-to-point link | in Router-LSA | + | | in Router-LSA | | + +--------------+-----------------------+-----------------------------+ + | IS-IS for | 7-octet neighbor | 3-octet metric field | + | IP/LDP FRR | system ID and | in Extended IS | + | | pseudonode number | Reachability TLV (type 22) | + | | in Extended IS | or Multi-Topology | + | | Reachability TLV (type| IS Neighbor TLV (type 222) | + | | 22) or Multi-Topology | | + | | IS Neighbor TLV (type | | + | | 222) | | + +--------------+-----------------------+-----------------------------+ + | IS-IS PCR for| 8-octet Bridge ID | 3-octet SPB-LINK-METRIC in | + | protection | created from 2-octet | SPB-Metric sub-TLV (type 29)| + | of traffic | Bridge Priority in | in Extended IS Reachability | + | in bridged | Shortest Path Bridging| TLV (type 22) or | + | |SPB Instance sub-TLV | Multi-Topology | + | networks | (type 1) carried in | Intermediate Systems | + | | MT-Capability TLV | TLV (type 222). In the case| + | | (type 144) and 6-octet| of asymmetric link metrics, | + | | neighbor system ID in | the larger link metric | + | | Extended IS | is used for both link | + | | Reachability TLV (type| directions. | + | | 22) or Multi-Topology | (informational) | + | | Intermediate Systems | | + | | TLV (type 222) | | + | | (informational) | | + +--------------+-----------------------+-----------------------------+ + + Figure 15: Value of interface.neighbor.mrt_node_id and + interface.metric to Be Used for Ranking Interfaces, for Different + Flooding Protocols and Applications + + + +Enyedi, et al. Standards Track [Page 20] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + The metrics are unsigned integers and MUST be compared as unsigned + integers. The results of mrt_node_id comparisons MUST be the same as + would be obtained by converting the mrt_node_ids to unsigned integers + using network byte order and performing the comparison as unsigned + integers. In the case of IS-IS for IP/LDP FRR with point-to-point + links, the pseudonode number (the 7th octet) is zero. Broadcast + interfaces will be discussed in Section 7. + +5.2. MRT Island Identification + + The local MRT Island for a particular MRT profile can be determined + by starting from the computing router in the network graph and doing + a breadth-first-search (BFS). The BFS explores only links that are + in the same area/level, are not IGP-excluded, and are not MRT- + ineligible. The BFS explores only nodes that support the particular + MRT profile. See Section 7 of [RFC7812] for more-precise definitions + of these criteria. + + MRT_Island_Identification(topology, computing_rtr, profile_id, area) + for all routers in topology + rtr.IN_MRT_ISLAND = FALSE + computing_rtr.IN_MRT_ISLAND = TRUE + explore_list = { computing_rtr } + while (explore_list is not empty) + next_rtr = remove_head(explore_list) + for each intf in next_rtr + if (not intf.IN_MRT_ISLAND + and not intf.MRT-ineligible + and not intf.remote_intf.MRT-ineligible + and not intf.IGP-excluded and (intf in area) + and (intf.remote_node supports profile_id) ) + intf.IN_MRT_ISLAND = TRUE + intf.remote_intf.IN_MRT_ISLAND = TRUE + if (not intf.remote_node.IN_MRT_ISLAND)) + intf.remote_node.IN_MRT_ISLAND = TRUE + add_to_tail(explore_list, intf.remote_node) + + Figure 16: MRT Island Identification + +5.3. GADAG Root Selection + + In Section 8.3 of [RFC7812], the GADAG Root Selection Policy is + described for the Default MRT Profile. This selection policy allows + routers to consistently select a common GADAG Root inside the local + MRT Island, based on advertised priority values. The MRT Lowpoint + algorithm simply requires that all routers in the MRT Island MUST + select the same GADAG Root; the mechanism can vary based upon the MRT + profile description. Before beginning computation, the network graph + + + +Enyedi, et al. Standards Track [Page 21] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + is reduced to contain only the set of routers that support the + specific MRT profile whose MRTs are being computed. + + As noted in Section 7, pseudonodes MUST NOT be considered for GADAG + root selection. + + It is expected that an operator will designate a set of routers as + good choices for selection as GADAG root by setting the GADAG Root + Selection Priority for that set of routers to lower (more preferred) + numerical values. For guidance on setting the GADAG Root Selection + Priority values, refer to Section 9.1. + +5.4. Initialization + + Before running the algorithm, there is the standard type of + initialization to be done, such as clearing any computed DFS-values, + lowpoint-values, DFS parents, lowpoint-parents, any MRT-computed next + hops, and flags associated with algorithm. + + It is assumed that a regular SPF computation has been run so that the + primary next hops from the computing router to each destination are + known. This is required for determining alternates at the last step. + + Initially, all interfaces MUST be initialized to UNDIRECTED. Whether + they are OUTGOING, INCOMING, or both is determined when the GADAG is + constructed and augmented. + + It is possible that some links and nodes will be marked using + standard IGP mechanisms to discourage or prevent transit traffic. + Section 7.3.1 of [RFC7812] describes how those links and nodes are + excluded from MRT Island formation. + + MRT-FRR also has the ability to advertise links MRT-Ineligible, as + described in Section 7.3.2 of [RFC7812]. These links are excluded + from the MRT Island and the GADAG. Computation of MRT next hops will + therefore not use any MRT-ineligible links. The MRT Lowpoint + algorithm does still need to consider MRT-ineligible links when + computing FRR alternates, because an MRT-ineligible link can still be + the shortest-path next hop to reach a destination. + + When a broadcast interface is advertised as MRT-ineligible, then the + pseudonode representing the entire broadcast network MUST NOT be + included in the MRT Island. This is equivalent to excluding all of + the broadcast interfaces on that broadcast network from the MRT + Island. + + + + + + +Enyedi, et al. Standards Track [Page 22] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +5.5. Constructing the GADAG Using Lowpoint Inheritance + + As discussed in Section 4.2, it is necessary to find ears from a node + x that is already in the GADAG (known as IN_GADAG). Two different + methods are used to find ears in the algorithm. The first is by + going to a DFS-child that is not IN_GADAG and then following the + chain of lowpoint parents until an IN_GADAG node is found. The + second is by going to a neighbor that is not IN_GADAG and then + following the chain of DFS parents until an IN_GADAG node is found. + As an ear is found, the associated interfaces are marked based on the + direction taken. The nodes in the ear are marked as IN_GADAG. In + the algorithm, first the ears via DFS-children are found and then the + ears via DFS-neighbors are found. + + By adding both types of ears when an IN_GADAG node is processed, all + ears that connect to that node are found. The order in which the + IN_GADAG nodes are processed is, of course, key to the algorithm. + The order is a stack of ears so the most recent ear is found at the + top of the stack. Of course, the stack stores nodes and not ears, so + an ordered list of nodes, from the first node in the ear to the last + node in the ear, is created as the ear is explored and then that list + is pushed onto the stack. + + Each ear represents a partial order (see Figure 4) and processing the + nodes in order along each ear ensures that all ears connecting to a + node are found before a node higher in the partial order has its ears + explored. This means that the direction of the links in the ear is + always from the node x being processed towards the other end of the + ear. Additionally, by using a stack of ears, this means that any + unprocessed nodes in previous ears can only be ordered higher than + nodes in the ears below it on the stack. + + In this algorithm that depends upon Lowpoint inheritance, it is + necessary that every node has a lowpoint parent that is not itself. + If a node is a cut-vertex, that may not yet be the case. Therefore, + any nodes without a lowpoint parent will have their lowpoint parent + set to their DFS parent and their lowpoint value set to the DFS-value + of their parent. This assignment also properly allows an ear between + two cut-vertices. + + Finally, the algorithm simultaneously computes each node's localroot, + as described in Figure 12. This is further elaborated as follows. + The localroot can be inherited from the node at the end of the ear + unless the end of the ear is x itself, in which case the localroot + for all the nodes in the ear would be x. This is because whenever + the first cycle is found in a block, or an ear involving a bridge is + computed, the cut-vertex closest to the root would be x itself. In + all other scenarios, the properties of lowpoint/dfs parents ensure + + + +Enyedi, et al. Standards Track [Page 23] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + that the end of the ear will be in the same block, and thus + inheriting its localroot would be the correct localroot for all newly + added nodes. + + The pseudocode for the GADAG algorithm (assuming that the adjustment + of lowpoint for cut-vertices has been made) is shown in Figure 17. + + Construct_Ear(x, Stack, intf, ear_type) + ear_list = empty + cur_node = intf.remote_node + cur_intf = intf + not_done = true + + while not_done + cur_intf.UNDIRECTED = false + cur_intf.OUTGOING = true + cur_intf.remote_intf.UNDIRECTED = false + cur_intf.remote_intf.INCOMING = true + + if cur_node.IN_GADAG is false + cur_node.IN_GADAG = true + add_to_list_end(ear_list, cur_node) + if ear_type is CHILD + cur_intf = cur_node.lowpoint_parent_intf + cur_node = cur_node.lowpoint_parent + else // ear_type must be NEIGHBOR + cur_intf = cur_node.dfs_parent_intf + cur_node = cur_node.dfs_parent + else + not_done = false + + if (ear_type is CHILD) and (cur_node is x) + // x is a cut-vertex and the local root for + // the block in which the ear is computed + x.IS_CUT_VERTEX = true + localroot = x + else + // Inherit localroot from the end of the ear + localroot = cur_node.localroot + while ear_list is not empty + y = remove_end_item_from_list(ear_list) + y.localroot = localroot + push(Stack, y) + + Construct_GADAG_via_Lowpoint(topology, gadag_root) + gadag_root.IN_GADAG = true + gadag_root.localroot = None + Initialize Stack to empty + + + +Enyedi, et al. Standards Track [Page 24] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + push gadag_root onto Stack + while (Stack is not empty) + x = pop(Stack) + foreach ordered_interface intf of x + if ((intf.remote_node.IN_GADAG == false) and + (intf.remote_node.dfs_parent is x)) + Construct_Ear(x, Stack, intf, CHILD) + foreach ordered_interface intf of x + if ((intf.remote_node.IN_GADAG == false) and + (intf.remote_node.dfs_parent is not x)) + Construct_Ear(x, Stack, intf, NEIGHBOR) + + Construct_GADAG_via_Lowpoint(topology, gadag_root) + + Figure 17: Lowpoint Inheritance GADAG Algorithm + +5.6. Augmenting the GADAG by Directing All Links + + The GADAG, regardless of the method used to construct it, at this + point could be used to find MRTs, but the topology does not include + all links in the network graph. That has two impacts. First, there + might be shorter paths that respect the GADAG partial ordering and so + the alternate paths would not be as short as possible. Second, there + may be additional paths between a router x and the root that are not + included in the GADAG. Including those provides potentially more + bandwidth to traffic flowing on the alternates and may reduce + congestion compared to just using the GADAG as currently constructed. + + The goal is thus to assign direction to every remaining link marked + as UNDIRECTED to improve the paths and number of paths found when the + MRTs are computed. + + To do this, we need to establish a total order that respects the + partial order described by the GADAG. This can be done using Kahn's + topological sort [Kahn_1962_topo_sort], which essentially assigns a + number to a node x only after all nodes before it (e.g., with a link + incoming to x) have had their numbers assigned. The only issue with + the topological sort is that it works on DAGs and not ADAGs or + GADAGs. + + To convert a GADAG to a DAG, it is necessary to remove all links that + point to a root of block from within that block. That provides the + necessary conversion to a DAG and then a topological sort can be + done. When adding undirected links to the GADAG, links connecting + the block root to other nodes in that block need special handling + because the topological order will not always give the right answer + for those links. There are three cases to consider. If the + undirected link in question has another parallel link between the + + + +Enyedi, et al. Standards Track [Page 25] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + same two nodes that is already directed, then the direction of the + undirected link can be inherited from the previously directed link. + In the case of parallel cut links, we set all of the parallel links + to both INCOMING and OUTGOING. Otherwise, the undirected link in + question is set to OUTGOING from the block root node. A cut-link can + then be identified by the fact that it will be directed both INCOMING + and OUTGOING in the GADAG. The exact details of this whole process + are captured in Figure 18. + + Add_Undirected_Block_Root_Links(topo, gadag_root) + foreach node x in topo + if x.IS_CUT_VERTEX or x is gadag_root + foreach interface i of x + if (i.remote_node.localroot is not x + or i.PROCESSED ) + continue + Initialize bundle_list to empty + bundle.UNDIRECTED = true + bundle.OUTGOING = false + bundle.INCOMING = false + foreach interface i2 in x + if i2.remote_node is i.remote_node + add_to_list_end(bundle_list, i2) + if not i2.UNDIRECTED: + bundle.UNDIRECTED = false + if i2.INCOMING: + bundle.INCOMING = true + if i2.OUTGOING: + bundle.OUTGOING = true + if bundle.UNDIRECTED + foreach interface i3 in bundle_list + i3.UNDIRECTED = false + i3.remote_intf.UNDIRECTED = false + i3.PROCESSED = true + i3.remote_intf.PROCESSED = true + i3.OUTGOING = true + i3.remote_intf.INCOMING = true + else + if (bundle.OUTGOING and bundle.INCOMING) + foreach interface i3 in bundle_list + i3.UNDIRECTED = false + i3.remote_intf.UNDIRECTED = false + i3.PROCESSED = true + i3.remote_intf.PROCESSED = true + i3.OUTGOING = true + i3.INCOMING = true + i3.remote_intf.INCOMING = true + i3.remote_intf.OUTGOING = true + + + +Enyedi, et al. Standards Track [Page 26] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + else if bundle.OUTGOING + foreach interface i3 in bundle_list + i3.UNDIRECTED = false + i3.remote_intf.UNDIRECTED = false + i3.PROCESSED = true + i3.remote_intf.PROCESSED = true + i3.OUTGOING = true + i3.remote_intf.INCOMING = true + else if bundle.INCOMING + foreach interface i3 in bundle_list + i3.UNDIRECTED = false + i3.remote_intf.UNDIRECTED = false + i3.PROCESSED = true + i3.remote_intf.PROCESSED = true + i3.INCOMING = true + i3.remote_intf.OUTGOING = true + + Modify_Block_Root_Incoming_Links(topo, gadag_root) + foreach node x in topo + if x.IS_CUT_VERTEX or x is gadag_root + foreach interface i of x + if i.remote_node.localroot is x + if i.INCOMING: + i.INCOMING = false + i.INCOMING_STORED = true + i.remote_intf.OUTGOING = false + i.remote_intf.OUTGOING_STORED = true + + Revert_Block_Root_Incoming_Links(topo, gadag_root) + foreach node x in topo + if x.IS_CUT_VERTEX or x is gadag_root + foreach interface i of x + if i.remote_node.localroot is x + if i.INCOMING_STORED + i.INCOMING = true + i.remote_intf.OUTGOING = true + i.INCOMING_STORED = false + i.remote_intf.OUTGOING_STORED = false + + Run_Topological_Sort_GADAG(topo, gadag_root) + Modify_Block_Root_Incoming_Links(topo, gadag_root) + foreach node x in topo + node.unvisited = 0 + foreach interface i of x + if (i.INCOMING) + node.unvisited += 1 + Initialize working_list to empty + Initialize topo_order_list to empty + + + +Enyedi, et al. Standards Track [Page 27] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + add_to_list_end(working_list, gadag_root) + while working_list is not empty + y = remove_start_item_from_list(working_list) + add_to_list_end(topo_order_list, y) + foreach ordered_interface i of y + if intf.OUTGOING + i.remote_node.unvisited -= 1 + if i.remote_node.unvisited is 0 + add_to_list_end(working_list, i.remote_node) + next_topo_order = 1 + while topo_order_list is not empty + y = remove_start_item_from_list(topo_order_list) + y.topo_order = next_topo_order + next_topo_order += 1 + Revert_Block_Root_Incoming_Links(topo, gadag_root) + + def Set_Other_Undirected_Links_Based_On_Topo_Order(topo) + foreach node x in topo + foreach interface i of x + if i.UNDIRECTED: + if x.topo_order < i.remote_node.topo_order + i.OUTGOING = true + i.UNDIRECTED = false + i.remote_intf.INCOMING = true + i.remote_intf.UNDIRECTED = false + else + i.INCOMING = true + i.UNDIRECTED = false + i.remote_intf.OUTGOING = true + i.remote_intf.UNDIRECTED = false + + Add_Undirected_Links(topo, gadag_root) + Add_Undirected_Block_Root_Links(topo, gadag_root) + Run_Topological_Sort_GADAG(topo, gadag_root) + Set_Other_Undirected_Links_Based_On_Topo_Order(topo) + + Add_Undirected_Links(topo, gadag_root) + + Figure 18: Assigning Direction to UNDIRECTED Links + + Proxy-nodes do not need to be added to the network graph. They + cannot be transited and do not affect the MRTs that are computed. + The details of how the MRT-Blue and MRT-Red next hops are computed + for proxy-nodes and how the appropriate alternate next hops are + selected is given in Section 5.9. + + + + + + +Enyedi, et al. Standards Track [Page 28] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +5.7. Compute MRT Next Hops + + As was discussed in Section 4.1, once an ADAG is found, it is + straightforward to find the next hops from any node X to the ADAG + root. However, in this algorithm, we will reuse the common GADAG and + find not only the one pair of MRTs rooted at the GADAG root with it, + but find a pair rooted at each node. This is useful since it is + significantly faster to compute. + + The method for computing differently rooted MRTs from the common + GADAG is based on two ideas. First, if two nodes X and Y are ordered + with respect to each other in the partial order, then an SPF along + OUTGOING links (an increasing-SPF) and an SPF along INCOMING links (a + decreasing-SPF) can be used to find the increasing and decreasing + paths. Second, if two nodes X and Y aren't ordered with respect to + each other in the partial order, then intermediary nodes can be used + to create the paths by increasing/decreasing to the intermediary and + then decreasing/increasing to reach Y. + + As usual, the two basic ideas will be discussed assuming the network + is 2-connected. The generalization to multiple blocks is discussed + in Section 5.7.4. The full algorithm is given in Section 5.7.5. + +5.7.1. MRT Next Hops to All Nodes Ordered with Respect to the Computing + Node + + Finding two node-disjoint paths from the computing router X to any + node Y depends upon whether Y>>X or Y<<X. As shown in Figure 19, if + Y>>X, then there is an increasing path that goes from X to Y without + crossing R; this contains nodes in the interval [X,Y]. There is also + a decreasing path that decreases towards R and then decreases from R + to Y; this contains nodes in the interval [X,R-small] or [R-great,Y]. + The two paths cannot have common nodes other than X and Y. + + + [Y]<---(Cloud 2)<--- [X] + | ^ + | | + V | + (Cloud 3)--->[R]--->(Cloud 1) + + MRT-Blue path: X->Cloud 2->Y + MRT-Red path: X->Cloud 1->R->Cloud 3->Y + + Figure 19: Y>>X + + + + + + +Enyedi, et al. Standards Track [Page 29] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Similar logic applies if Y<<X, as shown in Figure 20. In this case, + the increasing path from X increases to R and then increases from R + to Y to use nodes in the intervals [X,R-great] and [R-small, Y]. The + decreasing path from X reaches Y without crossing R and uses nodes in + the interval [Y,X]. + + + [X]<---(Cloud 2)<--- [Y] + | ^ + | | + V | + (Cloud 3)--->[R]--->(Cloud 1) + + MRT-Blue path: X->Cloud 3->R->Cloud 1->Y + MRT-Red path: X->Cloud 2->Y + + Figure 20: Y<<X + +5.7.2. MRT Next Hops to All Nodes Not Ordered with Respect to the + Computing Node + + When X and Y are not ordered, the first path should increase until we + get to a node G, where G>>Y. At G, we need to decrease to Y. The + other path should be just the opposite: we must decrease until we get + to a node H, where H<<Y, and then increase. Since R is smaller and + greater than Y, such G and H must exist. It is also easy to see that + these two paths must be node disjoint: the first path contains nodes + in interval [X,G] and [Y,G], while the second path contains nodes in + interval [H,X] and [H,Y]. This is illustrated in Figure 21. It is + necessary to decrease and then increase for the MRT-Blue and increase + and then decrease for the MRT-Red; if one simply increased for one + and decreased for the other, then both paths would go through the + root R. + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 30] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + (Cloud 6)<---[Y]<---(Cloud 5)<------------| + | | + | | + V | + [G]--->(Cloud 4)--->[R]--->(Cloud 1)--->[H] + ^ | + | | + | | + (Cloud 3)<---[X]<---(Cloud 2)<-----------| + + MRT-Blue path: decrease to H and increase to Y + X->Cloud 2->H->Cloud 5->Y + MRT-Red path: increase to G and decrease to Y + X->Cloud 3->G->Cloud 6->Y + + Figure 21: X and Y Unordered + + This gives disjoint paths as long as G and H are not the same node. + Since G>>Y and H<<Y, if G and H could be the same node, that would + have to be the root R. This is not possible because there is only + one incoming interface to the root R that is created when the initial + cycle is found. Recall from Figure 6 that whenever an ear was found + to have an end that was the root R, the ear was directed from R so + that the associated interface on R is outgoing and not incoming. + Therefore, there must be exactly one node M that is the largest one + before R, so the MRT-Red path will never reach R; it will turn at M + and decrease to Y. + +5.7.3. Computing Redundant Tree Next Hops in a 2-Connected Graph + + The basic ideas for computing RT next hops in a 2-connected graph + were given in Sections 5.7.1 and 5.7.2. Given these two ideas, how + can we find the trees? + + If some node X only wants to find the next hops (which is usually the + case for IP networks), it is enough to find which nodes are greater + and less than X, and which are not ordered; this can be done by + running an increasing-SPF and a decreasing-SPF rooted at X and not + exploring any links from the ADAG root. + + In principle, a traversal method other than SPF could be used to + traverse the GADAG in the process of determining blue and red next + hops that result in maximally redundant trees. This will be the case + as long as one traversal uses the links in the direction specified by + the GADAG and the other traversal uses the links in the direction + opposite of that specified by the GADAG. However, a different + traversal algorithm will generally result in different blue and red + + + + +Enyedi, et al. Standards Track [Page 31] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + next hops. Therefore, the algorithm specified here requires the use + of SPF to traverse the GADAG to generate MRT blue and red next hops, + as described below. + + An increasing-SPF rooted at X and not exploring links from the root + will find the increasing next hops to all Y>>X. Those increasing + next hops are X's next hops on the MRT-Blue to reach Y. A + decreasing-SPF rooted at X and not exploring links from the root will + find the decreasing next hops to all Z<<X. Those decreasing next + hops are X's next hops on the MRT-Red to reach Z. Since the root R + is both greater than and less than X, after this increasing-SPF and + decreasing-SPF, X's next hops on the MRT-Blue and on the MRT-Red to + reach R are known. For every node Y>>X, X's next hops on the MRT-Red + to reach Y are set to those on the MRT-Red to reach R. For every + node Z<<X, X's next hops on the MRT-Blue to reach Z are set to those + on the MRT-Blue to reach R. + + For those nodes that were not reached by either the increasing-SPF or + the decreasing-SPF, we can determine the next hops as well. The + increasing MRT-Blue next hop for a node that is not ordered with + respect to X is the next hop along the decreasing MRT-Red towards R, + and the decreasing MRT-Red next hop is the next hop along the + increasing MRT-Blue towards R. Naturally, since R is ordered with + respect to all the nodes, there will always be an increasing and a + decreasing path towards it. This algorithm does not provide the + complete specific path taken but just the appropriate next hops to + use. The identities of G and H are not determined by the computing + node X. + + The final case to consider is when the GADAG root R computes its own + next hops. Since the GADAG root R is << all other nodes, running an + increasing-SPF rooted at R will reach all other nodes; the MRT-Blue + next hops are those found with this increasing-SPF. Similarly, since + the GADAG root R is >> all other nodes, running a decreasing-SPF + rooted at R will reach all other nodes; the MRT-Red next hops are + those found with this decreasing-SPF. + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 32] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + E---D---| E<--D<--| + | | | | ^ | + | | | V | | + R F C R F C + | | | | ^ ^ + | | | V | | + A---B---| A-->B---| + + (a) (b) + A 2-connected graph A spanning ADAG rooted at R + + Figure 22 + + As an example, consider the situation depicted in Figure 22. Node C + runs an increasing-SPF and a decreasing-SPF on the ADAG. The + increasing-SPF reaches D, E, and R; the decreasing-SPF reaches B, A, + and R. E>>C. So, towards E the MRT-Blue next hop is D, since E was + reached on the increasing path through D. The MRT-Red next hop + towards E is B, since R was reached on the decreasing path through B. + Since E>>D, D will similarly compute its MRT-Blue next hop to be E, + ensuring that a packet on MRT-Blue will use path C-D-E. B, A, and R + will similarly compute the MRT-Red next hops towards E (which is + ordered less than B, A and R), ensuring that a packet on MRT-Red will + use path C-B-A-R-E. + + C can determine the next hops towards F as well. Since F is not + ordered with respect to C, the MRT-Blue next hop is the decreasing + one towards R (which is B) and the MRT-Red next hop is the increasing + one towards R (which is D). Since F>>B, for its MRT-Blue next hop + towards F, B will use the real increasing next hop towards F. So a + packet forwarded to B on MRT-Blue will get to F on path C-B-F. + Similarly, D will use the real decreasing next hop towards F as its + MRT-Red next hop, a packet on MRT-Red will use path C-D-F. + +5.7.4. Generalizing for a Graph That Isn't 2-Connected + + If a graph isn't 2-connected, then the basic approach given in + Section 5.7.3 needs some extensions to determine the appropriate MRT + next hops to use for destinations outside the computing router X's + blocks. In order to find a pair of maximally redundant trees in that + graph, we need to find a pair of RTs in each of the blocks (the root + of these trees will be discussed later) and combine them. + + + + + + + + + +Enyedi, et al. Standards Track [Page 33] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + When computing the MRT next hops from a router X, there are three + basic differences: + + 1. Only nodes in a common block with X should be explored in the + increasing-SPF and decreasing-SPF. + + 2. Instead of using the GADAG root, X's localroot should be used. + This has the following implications: + + A. The links from X's localroot should not be explored. + + B. If a node is explored in the outgoing SPF so Y>>X, then X's + MRT-Red next hops to reach Y uses X's MRT-Red next hops to + reach X's localroot and if Z<<X, then X's MRT-Blue next hops + to reach Z uses X's MRT-Blue next hops to reach X's + localroot. + + C. If a node W in a common block with X was not reached in the + increasing-SPF or decreasing-SPF, then W is unordered with + respect to X. X's MRT-Blue next hops to W are X's decreasing + (aka MRT-Red) next hops to X's localroot. X's MRT-Red next + hops to W are X's increasing (aka MRT-Blue) next hops to X's + localroot. + + 3. For nodes in different blocks, the next hops must be inherited + via the relevant cut-vertex. + + These are all captured in the detailed algorithm given in + Section 5.7.5. + +5.7.5. Complete Algorithm to Compute MRT Next Hops + + The complete algorithm to compute MRT Next Hops for a particular + router X is given in Figure 23. In addition to computing the MRT- + Blue next hops and MRT-Red next hops used by X to reach each node Y, + the algorithm also stores an "order_proxy", which is the proper cut- + vertex to reach Y if it is outside the block, and which is used later + in deciding whether the MRT-Blue or the MRT-Red can provide an + acceptable alternate for a particular primary next hop. + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 34] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + In_Common_Block(x, y) + if ( (x.block_id is y.block_id) + or (x is y.localroot) or (y is x.localroot) ) + return true + return false + + Store_Results(y, direction) + if direction is FORWARD + y.higher = true + y.blue_next_hops = y.next_hops + if direction is REVERSE + y.lower = true + y.red_next_hops = y.next_hops + + SPF_No_Traverse_Block_Root(spf_root, block_root, direction) + Initialize spf_heap to empty + Initialize nodes' spf_metric to infinity and next_hops to empty + spf_root.spf_metric = 0 + insert(spf_heap, spf_root) + while (spf_heap is not empty) + min_node = remove_lowest(spf_heap) + Store_Results(min_node, direction) + if ((min_node is spf_root) or (min_node is not block_root)) + foreach interface intf of min_node + if ( ( ((direction is FORWARD) and intf.OUTGOING) or + ((direction is REVERSE) and intf.INCOMING) ) + and In_Common_Block(spf_root, intf.remote_node) ) + path_metric = min_node.spf_metric + intf.metric + if path_metric < intf.remote_node.spf_metric + intf.remote_node.spf_metric = path_metric + if min_node is spf_root + intf.remote_node.next_hops = make_list(intf) + else + intf.remote_node.next_hops = min_node.next_hops + insert_or_update(spf_heap, intf.remote_node) + else if path_metric == intf.remote_node.spf_metric + if min_node is spf_root + add_to_list(intf.remote_node.next_hops, intf) + else + add_list_to_list(intf.remote_node.next_hops, + min_node.next_hops) + + SetEdge(y) + if y.blue_next_hops is empty and y.red_next_hops is empty + SetEdge(y.localroot) + y.blue_next_hops = y.localroot.blue_next_hops + y.red_next_hops = y.localroot.red_next_hops + y.order_proxy = y.localroot.order_proxy + + + +Enyedi, et al. Standards Track [Page 35] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Compute_MRT_NextHops(x, gadag_root) + foreach node y + y.higher = y.lower = false + clear y.red_next_hops and y.blue_next_hops + y.order_proxy = y + SPF_No_Traverse_Block_Root(x, x.localroot, FORWARD) + SPF_No_Traverse_Block_Root(x, x.localroot, REVERSE) + + // red and blue next hops are stored to x.localroot as different + // paths are found via the SPF and reverse-SPF. + // Similarly, any node whose localroot is x will have its + // red_next_hops and blue_next_hops already set. + + // Handle nodes in the same block that aren't the localroot + foreach node y + if (y.IN_MRT_ISLAND and (y is not x) and + (y.block_id is x.block_id) ) + if y.higher + y.red_next_hops = x.localroot.red_next_hops + else if y.lower + y.blue_next_hops = x.localroot.blue_next_hops + else + y.blue_next_hops = x.localroot.red_next_hops + y.red_next_hops = x.localroot.blue_next_hops + + // Inherit next hops and order_proxies to other components + if (x is not gadag_root) and (x.localroot is not gadag_root) + gadag_root.blue_next_hops = x.localroot.blue_next_hops + gadag_root.red_next_hops = x.localroot.red_next_hops + gadag_root.order_proxy = x.localroot + foreach node y + if (y is not gadag_root) and (y is not x) and y.IN_MRT_ISLAND + SetEdge(y) + + max_block_id = 0 + Assign_Block_ID(gadag_root, max_block_id) + Compute_MRT_NextHops(x, gadag_root) + + Figure 23: Complete Algorithm to Compute MRT Next Hops + +5.8. Identify MRT Alternates + + At this point, a computing router S knows its MRT-Blue next hops and + MRT-Red next hops for each destination in the MRT Island. The + primary next hops along the SPT are also known. It remains to + determine for each primary next hop to a destination D, which MRT + avoids the primary next-hop node F. This computation depends upon + data set in Compute_MRT_NextHops such as each node y's + + + +Enyedi, et al. Standards Track [Page 36] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + y.blue_next_hops, y.red_next_hops, y.order_proxy, y.higher, y.lower, + and topo_orders. Recall that any router knows only which are the + nodes greater and lesser than itself, but it cannot decide the + relation between any two given nodes easily; that is why we need + topological ordering. + + For each primary next-hop node F to each destination D, S can call + Select_Alternates(S, D, F, primary_intf) to determine whether to use + the MRT-Blue or MRT-Red next hops as the alternate next hop(s) for + that primary next hop. The algorithm is given in Figure 24 and + discussed afterwards. + + Select_Alternates_Internal(D, F, primary_intf, + D_lower, D_higher, D_topo_order): + if D_higher and D_lower + if F.HIGHER and F.LOWER + if F.topo_order < D_topo_order + return USE_RED + else + return USE_BLUE + if F.HIGHER + return USE_RED + if F.LOWER + return USE_BLUE + //F unordered wrt S + return USE_RED_OR_BLUE + + else if D_higher + if F.HIGHER and F.LOWER + return USE_BLUE + if F.LOWER + return USE_BLUE + if F.HIGHER + if (F.topo_order > D_topo_order) + return USE_BLUE + if (F.topo_order < D_topo_order) + return USE_RED + //F unordered wrt S + return USE_RED_OR_BLUE + + else if D_lower + if F.HIGHER and F.LOWER + return USE_RED + if F.HIGHER + return USE_RED + if F.LOWER + if F.topo_order > D_topo_order + return USE_BLUE + + + +Enyedi, et al. Standards Track [Page 37] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if F.topo_order < D_topo_order + return USE_RED + //F unordered wrt S + return USE_RED_OR_BLUE + + else //D is unordered wrt S + if F.HIGHER and F.LOWER + if primary_intf.OUTGOING and primary_intf.INCOMING + return USE_RED_OR_BLUE + if primary_intf.OUTGOING + return USE_BLUE + if primary_intf.INCOMING + return USE_RED + //primary_intf not in GADAG + return USE_RED + if F.LOWER + return USE_RED + if F.HIGHER + return USE_BLUE + //F unordered wrt S + if F.topo_order > D_topo_order: + return USE_BLUE + else: + return USE_RED + + Select_Alternates(D, F, primary_intf) + if not In_Common_Block(F, S) + return PRIM_NH_IN_DIFFERENT_BLOCK + if (D is F) or (D.order_proxy is F) + return PRIM_NH_IS_D_OR_OP_FOR_D + D_lower = D.order_proxy.LOWER + D_higher = D.order_proxy.HIGHER + D_topo_order = D.order_proxy.topo_order + return Select_Alternates_Internal(D, F, primary_intf, + D_lower, D_higher, D_topo_order) + + Figure 24: Select_Alternates() and Select_Alternates_Internal() + + It is useful to first handle the case where F is also D, or F is the + order proxy for D. In this case, only link protection is possible. + The MRT that doesn't use the failed primary next hop is used. If + both MRTs use the primary next hop, then the primary next hop must be + a cut-link, so either MRT could be used but the set of MRT next hops + must be pruned to avoid the failed primary next-hop interface. To + indicate this case, Select_Alternates returns + PRIM_NH_IS_D_OR_OP_FOR_D. Explicit pseudocode to handle the three + sub-cases above is not provided. + + + + +Enyedi, et al. Standards Track [Page 38] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + The logic behind Select_Alternates_Internal() is described in + Figure 25. As an example, consider the first case described in the + table, where the D>>S and D<<S. If this is true, then either S or D + must be the block root, R. If F>>S and F<<S, then S is the block + root. So the blue path from S to D is the increasing path to D, and + the red path S to D is the decreasing path to D. If the + F.topo_order>D.topo_order, then either F is ordered higher than D or + F is unordered with respect to D. Therefore, F is either on a + decreasing path from S to D, or it is on neither an increasing nor a + decreasing path from S to D. In either case, it is safe to take an + increasing path from S to D to avoid F. We know that when S is R, + the increasing path is the blue path, so it is safe to use the blue + path to avoid F. + + If instead F.topo_order<D.topo_order, then either F is ordered lower + than D, or F is unordered with respect to D. Therefore, F is either + on an increasing path from S to D, or it is on neither an increasing + nor a decreasing path from S to D. In either case, it is safe to + take a decreasing path from S to D to avoid F. We know that when S + is R, the decreasing path is the red path, so it is safe to use the + red path to avoid F. + + If F>>S or F<<S (but not both), then D is the block root. We then + know that the blue path from S to D is the increasing path to R, and + the red path is the decreasing path to R. When F>>S, we deduce that + F is on an increasing path from S to R. So in order to avoid F, we + use a decreasing path from S to R, which is the red path. Instead, + when F<<S, we deduce that F is on a decreasing path from S to R. So + in order to avoid F, we use an increasing path from S to R, which is + the blue path. + + All possible cases are systematically described in the same manner in + the rest of the table. + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 39] + +RFC 7811 MRT-FRR Algorithm June 2016 + + ++------+------------+------+------------------------------+------------+ +| D | MRT blue | F | additional | F | Alternate | +| wrt | and red | wrt | criteria | wrt | | +| S | path | S | | MRT | | +| | properties | | | (deduced) | | ++------+------------+------+-----------------+------------+------------+ +| D>>S | Blue path: | F>>S | additional | F on an | Use Red | +| and | Increasing | only | criteria | increasing | to avoid | +| D<<S,| path to R. | | not needed | path from | F | +| D is | Red path: | | | S to R | | +| R, | Decreasing +------+-----------------+------------+------------+ +| | path to R. | F<<S | additional | F on a | Use Blue | +| | | only | criteria | decreasing | to avoid | +| | | | not needed | path from | F | +| or | | | | S to R | | +| | +------+-----------------+------------+------------+ +| | | F>>S | topo(F)>topo(D) | F on a | Use Blue | +| S is | Blue path: | and | implies that | decreasing | to avoid | +| R | Increasing | F<<S,| F>>D or F??D | path from | F | +| | path to D. | | | S to D or | | +| | Red path: | | | neither | | +| | Decreasing | +-----------------+------------+------------+ +| | path to D. | | topo(F)<topo(D) | F on an | Use Red | +| | | | implies that | increasing | to avoid | +| | | | F<<D or F??D | path from | F | +| | | | | S to D or | | +| | | | | neither | | +| | +------+-----------------+------------+------------+ +| | | F??S | Can only occur | F is on | Use Red | +| | | | when link | neither | or Blue | +| | | | between | increasing | to avoid | +| | | | F and S | nor decr. | F | +| | | | is marked | path from | | +| | | | MRT_INELIGIBLE | S to D or R| | + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 40] + +RFC 7811 MRT-FRR Algorithm June 2016 + + ++------+------------+------+-----------------+------------+------------+ +| D>>S | Blue path: | F<<S | additional | F on | Use Blue | +| only | Increasing | only | criteria | decreasing | to avoid | +| | shortest | | not needed | path from | F | +| | path from | | | S to R | | +| | S to D. +------+-----------------+------------+------------+ +| | Red path: | F>>S | topo(F)>topo(D) | F on | Use Blue | +| | Decreasing | only | implies that | decreasing | to avoid | +| | shortest | | F>>D or F??D | path from | F | +| | path from | | | R to D | | +| | S to R, | | | or | | +| | then | | | neither | | +| | decreasing | +-----------------+------------+------------+ +| | shortest | | topo(F)<topo(D) | F on | Use Red | +| | path from | | implies that | increasing | to avoid | +| | R to D. | | F<<D or F??D | path from | F | +| | | | | S to D | | +| | | | | or | | +| | | | | neither | | +| | +------+-----------------+------------+------------+ +| | | F>>S | additional | F on Red | Use Blue | +| | | and | criteria | | to avoid | +| | | F<<S,| not needed | | F | +| | | F is | | | | +| | | R | | | | +| | +------+-----------------+------------+------------+ +| | | F??S | Can only occur | F is on | Use Red | +| | | | when link | neither | or Blue | +| | | | between | increasing | to avoid | +| | | | F and S | nor decr. | F | +| | | | is marked | path from | | +| | | | MRT_INELIGIBLE | S to D or R| | + + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 41] + +RFC 7811 MRT-FRR Algorithm June 2016 + + ++------+------------+------+-----------------+------------+------------+ +| D<<S | Blue path: | F>>S | additional | F on | Use Red | +| only | Increasing | only | criteria | increasing | to avoid | +| | shortest | | not needed | path from | F | +| | path from | | | S to R | | +| | S to R, +------+-----------------+------------+------------+ +| | then | F<<S | topo(F)>topo(D) | F on | Use Blue | +| | increasing | only | implies that | decreasing | to avoid | +| | shortest | | F>>D or F??D | path from | F | +| | path from | | | R to D | | +| | R to D. | | | or | | +| | Red path: | | | neither | | +| | Decreasing | +-----------------+------------+------------+ +| | shortest | | topo(F)<topo(D) | F on | Use Red | +| | path from | | implies that | increasing | to avoid | +| | S to D. | | F<<D or F??D | path from | F | +| | | | | S to D | | +| | | | | or | | +| | | | | neither | | +| | +------+-----------------+------------+------------+ +| | | F>>S | additional | F on Blue | Use Red | +| | | and | criteria | | to avoid | +| | | F<<S,| not | | F | +| | | F is | needed | | | +| | | R | | | | +| | +------+-----------------+------------+------------+ +| | | F??S | Can only occur | F is on | Use Red | +| | | | when link | neither | or Blue | +| | | | between | increasing | to avoid | +| | | | F and S | nor decr. | F | +| | | | is marked | path from | | +| | | | MRT_INELIGIBLE | S to D or R| | ++------+------------+------+-----------------+------------+------------+ +| D??S | Blue path: | F<<S | additional | F on a | Use Red | +| | Decr. from | only | criteria | decreasing | to avoid | +| | S to first | | not needed | path from | F | +| | node K<<D, | | | S to K. | | +| | then incr. +------+-----------------+------------+------------+ +| | to D. | F>>S | additional | F on an | Use Blue | +| | Red path: | only | criteria | increasing | to avoid | +| | Incr. from | | not needed | path from | F | +| | S to first | | | S to L | | +| | node L>>D, | | | | | +| | then decr. | | | | | + + + + + + + +Enyedi, et al. Standards Track [Page 42] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +| | +------+-----------------+------------+------------+ +| | | F??S | topo(F)>topo(D) | F on decr. | Use Blue | +| | | | implies that | path from | to avoid | +| | | | F>>D or F??D | L to D or | F | +| | | | | neither | | +| | | +-----------------+------------+------------+ +| | | | topo(F)<topo(D) | F on incr. | Use Red | +| | | | implies that | path from | to avoid | +| | | | F<<D or F??D | K to D or | F | +| | | | | neither | | +| | +------+-----------------+------------+------------+ +| | | F>>S | GADAG link | F on an | Use Blue | +| | | and | direction | incr. path | to avoid | +| | | F<<S,| S->F | from S | F | +| | | F is +-----------------+------------+------------+ +| | | R | GADAG link | F on a | Use Red | +| | | | direction | decr. path | to avoid | +| | | | S<-F | from S | F | +| | | +-----------------+------------+------------+ +| | | | GADAG link | Either F is the order | +| | | | direction | proxy for D (case | +| | | | S<-->F | already handled) or D | +| | | | | is in a different block | +| | | | | from F, in which case | +| | | | | Red or Blue avoids F | +| | | +-----------------+-------------------------+ +| | | | S-F link not | Relies on special | +| | | | in GADAG, | construction of GADAG | +| | | | only when | to demonstrate that | +| | | | S-F link is | using Red avoids F | +| | | | MRT_INELIGIBLE | (see text) | ++------+------------+------+-----------------+-------------------------+ + + Determining MRT next hops and alternates based on the partial order + and topological sort relationships between the source(S), + destination(D), primary next hop(F), and block root(R). topo(N) + indicates the topological sort value of node N. X??Y indicates that + node X is unordered with respect to node Y. It is assumed that the + case where F is D, or where F is the order proxy for D, has already + been handled. + + Figure 25: Determining MRT Next Hops and Alternates + + The last case in Figure 25 requires additional explanation. The fact + that the red path from S to D in this case avoids F relies on a + special property of the GADAGs that we have constructed in this + algorithm, a property not shared by all GADAGs in general. When D is + unordered with respect to S, and F is the localroot for S, it can + + + +Enyedi, et al. Standards Track [Page 43] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + occur that the link between S and F is not in the GADAG only when + that link has been marked MRT_INELIGIBLE. For an arbitrary GADAG, S + doesn't have enough information based on the computed order + relationships to determine if the red path or blue path will hit F + (which is also the localroot) before hitting K or L, and making it + safely to D. However, the GADAGs that we construct using the + algorithm in this document are not arbitrary GADAGs. They have the + additional property that incoming links to a localroot come from only + one other node in the same block. This is a result of the method of + construction. This additional property guarantees that the red path + from S to D will never pass through the localroot of S. (That would + require the localroot to play the role of L, the first node in the + path ordered higher than D, which would in turn require the localroot + to have two incoming links in the GADAG, which cannot happen.) + Therefore, it is safe to use the red path to avoid F with these + specially constructed GADAGs. + + As an example of how Select_Alternates_Internal() operates, consider + the ADAG depicted in Figure 26 and first suppose that G is the + source, D is the destination, and H is the failed next hop. Since + D>>G, we need to compare H.topo_order and D.topo_order. Since + D.topo_order>H.topo_order, D must be either higher than H or + unordered with respect to H, so we should select the decreasing path + towards the root. If, however, the destination were instead J, we + must find that H.topo_order>J.topo_order, so we must choose the + increasing Blue next hop to J, which is I. In the case, when instead + the destination is C, we find that we need to first decrease to avoid + using H, so the Blue, first decreasing then increasing, path is + selected. + + [E]<-[D]<-[H]<-[J] + | ^ ^ ^ + V | | | + [R] [C] [G]->[I] + | ^ ^ ^ + V | | | + [A]->[B]->[F]---| + + + Figure 26: ADAG Rooted at R for a 2-Connected Graph + +5.9. Named Proxy-Nodes + + As discussed in Section 11.2 of [RFC7812], it is necessary to find + MRT-Blue and MRT-Red next hops and MRT-FRR alternates for named + proxy-nodes. An example use case is for a router that is not part of + that local MRT Island, when there is only partial MRT support in the + domain. + + + +Enyedi, et al. Standards Track [Page 44] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +5.9.1. Determining Proxy-Node Attachment Routers + + Section 11.2 of [RFC7812] discusses general considerations for + determining the two proxy-node attachment routers for a given proxy- + node, corresponding to a prefix. A router in the MRT Island that + advertises the prefix is a candidate for being a proxy-node + attachment router, with the associated named-proxy-cost equal to the + advertised cost to the prefix. + + An Island Border Router (IBR) is a router in the MRT Island that is + connected to an Island Neighbor (IN), which is a router not in the + MRT Island but in the same area/level. An (IBR,IN) pair is a + candidate for being a proxy-node attachment router, if the shortest + path from the IN to the prefix does not enter the MRT Island. A + method for identifying such Loop-Free Island Neighbors (LFINs) is + given below. The named-proxy-cost assigned to each (IBR, IN) pair is + cost(IBR, IN) + D_opt(IN, prefix). + + From the set of prefix-advertising routers and the set of IBRs with + at least one LFIN, the two routers with the lowest named-proxy-cost + are selected. Ties are broken based upon the lowest Router ID. For + ease of discussion, the two selected routers will be referred to as + proxy-node attachment routers. + +5.9.2. Computing If an Island Neighbor (IN) Is Loop-Free + + As discussed above, the IN needs to be loop-free with respect to the + whole MRT Island for the destination. This can be accomplished by + running the usual SPF algorithm while keeping track of which shortest + paths have passed through the MRT island. Pseudocode for this is + shown in Figure 27. The Island_Marking_SPF() is run for each IN that + needs to be evaluated for the loop-free condition, with the IN as the + spf_root. Whether or not an IN is loop-free with respect to the MRT + island can then be determined by evaluating node.PATH_HITS_ISLAND for + each destination of interest. + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 45] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Island_Marking_SPF(spf_root) + Initialize spf_heap to empty + Initialize nodes' spf_metric to infinity and next_hops to empty + and PATH_HITS_ISLAND to false + spf_root.spf_metric = 0 + insert(spf_heap, spf_root) + while (spf_heap is not empty) + min_node = remove_lowest(spf_heap) + foreach interface intf of min_node + path_metric = min_node.spf_metric + intf.metric + if path_metric < intf.remote_node.spf_metric + intf.remote_node.spf_metric = path_metric + if min_node is spf_root + intf.remote_node.next_hops = make_list(intf) + else + intf.remote_node.next_hops = min_node.next_hops + if intf.remote_node.IN_MRT_ISLAND + intf.remote_node.PATH_HITS_ISLAND = true + else + intf.remote_node.PATH_HITS_ISLAND = + min_node.PATH_HITS_ISLAND + insert_or_update(spf_heap, intf.remote_node) + else if path_metric == intf.remote_node.spf_metric + if min_node is spf_root + add_to_list(intf.remote_node.next_hops, intf) + else + add_list_to_list(intf.remote_node.next_hops, + min_node.next_hops) + if intf.remote_node.IN_MRT_ISLAND + intf.remote_node.PATH_HITS_ISLAND = true + else + intf.remote_node.PATH_HITS_ISLAND = + min_node.PATH_HITS_ISLAND + + Figure 27: Island_Marking_SPF() for Determining If an Island Neighbor + Is Loop-Free + + It is also possible that a given prefix is originated by a + combination of non-island routers and island routers. The results of + the Island_Marking_SPF() computation can be used to determine if the + shortest path from an IN to reach that prefix hits the MRT Island. + The shortest path for the IN to reach prefix P is determined by the + total cost to reach prefix P, which is the sum of the cost for the IN + to reach a prefix-advertising node and the cost with which that node + advertises the prefix. The path with the minimum total cost to + prefix P is chosen. If the prefix-advertising node for that minimum + total cost path has PATH_HITS_ISLAND set to True, then the IN is not + loop-free with respect to the MRT Island for reaching prefix P. If + + + +Enyedi, et al. Standards Track [Page 46] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + there are multiple minimum total cost paths to reach prefix P, then + all of the prefix-advertising routers involved in the minimum total + cost paths MUST have PATH_HITS_ISLAND set to False for the IN to be + considered loop-free to reach P. + + Note that there are other computations that could be used to + determine if paths from a given IN _might_ pass through the MRT + Island for a given prefix or destination. For example, a previous + draft version of this document specified running the SPF algorithm on + modified topology that treats the MRT Island as a single node (with + intra-island links set to zero cost) in order to provide input to + computations to determine if the path from IN to non-island + destination hits the MRT Island in this modified topology. This + computation is enough to guarantee that a path will not hit the MRT + Island in the original topology. However, it is possible that a path + that is disqualified for hitting the MRT Island in the modified + topology will not actually hit the MRT Island in the original + topology. The algorithm described in Island_Marking_SPF() above does + not modify the original topology, and will only disqualify a path if + the actual path does in fact hit the MRT Island. + + Since all routers need to come to the same conclusion about which + routers qualify as LFINs, this specification requires that all + routers computing LFINs MUST use an algorithm whose result is + identical to that of the Island_Marking_SPF() in Figure 27. + +5.9.3. Computing MRT Next Hops for Proxy-Nodes + + Determining the MRT next hops for a proxy-node in the degenerate case + where the proxy-node is attached to only one node in the GADAG is + trivial, as all needed information can be derived from that proxy- + node attachment router. If there are multiple interfaces connecting + the proxy-node to the single proxy-node attachment router, then some + can be assigned to MRT-Red and others to MRT_Blue. + + Now, consider the proxy-node P that is attached to two proxy-node + attachment routers. The pseudocode for Select_Proxy_Node_NHs(P,S) in + Figure 28 specifies how a computing-router S MUST compute the MRT red + and blue next hops to reach proxy-node P. The proxy-node attachment + router with the lower value of mrt_node_id (as defined in Figure 15) + is assigned to X, and the other proxy-node attachment router is + assigned to Y. We will be using the relative order of X,Y, and S in + the partial order defined by the GADAG to determine the MRT red and + blue next hops to reach P, so we also define A and B as the order + proxies for X and Y, respectively, with respect to S. The order + proxies for all nodes with respect to S were already computed in + Compute_MRT_NextHops(). + + + + +Enyedi, et al. Standards Track [Page 47] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + def Select_Proxy_Node_NHs(P,S): + if P.pnar1.node.node_id < P.pnar2.node.node_id: + X = P.pnar1.node + Y = P.pnar2.node + else: + X = P.pnar2.node + Y = P.pnar1.node + P.pnar_X = X + P.pnar_Y = Y + A = X.order_proxy + B = Y.order_proxy + if (A is S.localroot + and B is S.localroot): + // case 1.0 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if (A is S.localroot + and B is not S.localroot): + // case 2.0 + if B.LOWER: + // case 2.1 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if B.HIGHER: + // case 2.2 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + // case 2.3 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if (A is not S.localroot + and B is S.localroot): + // case 3.0 + if A.LOWER: + // case 3.1 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if A.HIGHER: + // case 3.2 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + + + +Enyedi, et al. Standards Track [Page 48] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + else: + // case 3.3 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if (A is not S.localroot + and B is not S.localroot): + // case 4.0 + if (S is A.localroot or S is B.localroot): + // case 4.05 + if A.topo_order < B.topo_order: + // case 4.05.1 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + // case 4.05.2 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if A.LOWER: + // case 4.1 + if B.HIGHER: + // case 4.1.1 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if B.LOWER: + // case 4.1.2 + if A.topo_order < B.topo_order: + // case 4.1.2.1 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + // case 4.1.2.2 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + // case 4.1.3 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if A.HIGHER: + // case 4.2 + + + + + +Enyedi, et al. Standards Track [Page 49] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if B.HIGHER: + // case 4.2.1 + if A.topo_order < B.topo_order: + // case 4.2.1.1 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + // case 4.2.1.2 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if B.LOWER: + // case 4.2.2 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + // case 4.2.3 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + // case 4.3 + if B.LOWER: + // case 4.3.1 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if B.HIGHER: + // case 4.3.2 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + // case 4.3.3 + if A.topo_order < B.topo_order: + // case 4.3.3.1 + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + + + + + + + + + + +Enyedi, et al. Standards Track [Page 50] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + else: + // case 4.3.3.2 + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + assert(False) + + Figure 28: Select_Proxy_Node_NHs() + + It is useful to understand up front that the blue next hops to reach + proxy-node P produced by Select_Proxy_Node_NHs() will always be the + next hops that reach proxy-node attachment router X, while the red + next hops to reach proxy-node P will always be the next hops that + reach proxy-node attachment router Y. This is different from the red + and blue next hops produced by Compute_MRT_NextHops() where, for + example, blue next hops to a destination that is ordered with respect + to the source will always correspond to an INCREASING next hop on the + GADAG. The exact choice of which next hops chosen by + Select_Proxy_Node_NHs() as the blue next hops to reach P (which will + necessarily go through X on its way to P) does depend on the GADAG, + but the relationship is more complex than was the case with + Compute_MRT_NextHops(). + + There are 21 different relative order relationships between A, B, and + S that Select_Proxy_Node_NHs() uses to determine red and blue next + hops to P. This document does not attempt to provide an exhaustive + description of each case considered in Select_Proxy_Node_NHs(). + Instead, we provide a high-level overview of the different cases, and + we consider a few cases in detail to give an example of the reasoning + that can be used to understand each case. + + At the highest level, Select_Proxy_Node_NHs() distinguishes between + four different cases depending on whether or not A or B is the + localroot for S. For example, for case 4.0, neither A nor B is the + localroot for S. Case 4.05 addresses the case where S is the + localroot for either A or B, while cases 4.1, 4.2, and 4.3 address + the cases where A is ordered lower than S, A is ordered higher than + S, or A is unordered with respect to S on the GADAG. In general, + each of these cases is then further subdivided into whether or not B + is ordered lower than S, B is ordered higher than S, or B is + unordered with respect to S. In some cases, we also need a further + level of discrimination, where we use the topological sort order of A + with respect to B. + + As a detailed example, let's consider case 4.1 and all of its sub- + cases, and explain why the red and blue next hops to reach P are + chosen as they are in Select_Proxy_Node_NHs(). In case 4.1, neither + A nor B is the localroot for S, S is not the localroot for A or B, + + + +Enyedi, et al. Standards Track [Page 51] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + and A is ordered lower than S on the GADAG. In this situation, we + know that the red path to reach X (as computed in + Compute_MRT_NextHops()) will follow DECREASING next hops towards A, + while the blue path to reach X will follow INCREASING next hops to + the localroot, and then INCREASING next hops to A. + + Now consider sub-case 4.1.1 where B is ordered higher than S. In + this situation, we know that the blue path to reach Y will follow + INCREASING next hops towards B, while the red next hops to reach Y + will follow DECREASING next hops to the localroot, and then + DECREASING next hops to B. So, to reach X and Y by two disjoint + paths, we can choose the red next hops to X and the blue next hops to + Y. We have chosen the convention that blue next hops to P are those + that pass through X, and red next hops to P are those that pass + through Y, so we can see that case 4.1.1 produces the desired result. + Choosing blue to X and red to Y does not produce disjoint paths + because the paths intersect at least at the localroot. + + Now consider sub-case 4.1.2 where B is ordered lower than S. In this + situation, we know that the red path to reach Y will follow + DECREASING next hops towards B, while the BLUE next hops to reach Y + will follow INCREASING next hops to the localroot, and then + INCREASING next hops to A. The choice here is more difficult than in + 4.1.1 because A and B are both on the DECREASING path from S towards + the localroot. We want to use the direct DECREASING(red) path to the + one that is nearer to S on the GADAG. We get this extra information + by comparing the topological sort order of A and B. If + A.topo_order<B.topo_order, then we use red to Y and blue to X, since + the red path to Y will DECREASE to B without hitting A, and the blue + path to X will INCREASE to A without hitting B. Instead, if + A.topo_order>B.topo_order, then we use red to X and blue to Y. + + Note that when A is unordered with respect to B, the result of + comparing A.topo_order with B.topo_order could be greater than or + less than. In this case, the result doesn't matter because either + choice (red to Y and blue to X or red to X and blue to Y) would work. + What is required is that all nodes in the network give the same + result when comparing A.topo_order with B.topo_order. This is + guaranteed by having all nodes run the same algorithm + (Run_Topological_Sort_GADAG()) to compute the topological sort order. + + Finally, we consider case 4.1.3, where B is unordered with respect to + S. In this case, the blue path to reach Y will follow the DECREASING + next hops towards the localroot until it reaches some node (K) which + is ordered less than B, after which it will take INCREASING next hops + to B. The red path to reach Y will follow the INCREASING next hops + towards the localroot until it reaches some node (L) which is ordered + greater than B, after which it will take DECREASING next hops to B. + + + +Enyedi, et al. Standards Track [Page 52] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Both K and A are reached by DECREASING from S, but we don't have + information about whether or not that DECREASING path will hit K or A + first. Instead, we do know that the INCREASING path from S will hit + L before reaching A. Therefore, we use the red path to reach Y and + the red path to reach X. + + Similar reasoning can be applied to understand the other 17 cases + used in Select_Proxy_Node_NHs(). However, cases 2.3 and 3.3 deserve + special attention because the correctness of the solution for these + two cases relies on a special property of the GADAGs that we have + constructed in this algorithm, a property not shared by all GADAGs in + general. Focusing on case 2.3, we consider the case where A is the + localroot for S, while B is not, and B is unordered with respect to + S. The red path to X DECREASES from S to the localroot A, while the + blue path to X INCREASES from S to the localroot A. The blue path to + Y DECREASES towards the localroot A until it reaches some node (K) + which is ordered less than B, after which the path INCREASES to B. + The red path to Y INCREASES towards the localroot A until it reaches + some node (L) which is ordered greater than B, after which the path + DECREASES to B. It can be shown that for an arbitrary GADAG, with + only the ordering relationships computed so far, we don't have enough + information to choose a pair of paths to reach X and Y that are + guaranteed to be disjoint. In some topologies, A will play the role + of K, the first node ordered less than B on the blue path to Y. In + other topologies, A will play the role of L, the first node ordered + greater than B on the red path to Y. The basic problem is that we + cannot distinguish between these two cases based on the ordering + relationships. + + As discussed Section 5.8, the GADAGs that we construct using the + algorithm in this document are not arbitrary GADAGs. They have the + additional property that incoming links to a localroot come from only + one other node in the same block. This is a result of the method of + construction. This additional property guarantees that localroot A + will never play the role of L in the red path to Y, since L must have + at least two incoming links from different nodes in the same block in + the GADAG. This, in turn, allows Select_Proxy_Node_NHs() to choose + the red path to Y and the red path to X as the disjoint MRT paths to + reach P. + +5.9.4. Computing MRT Alternates for Proxy-Nodes + + After finding the red and the blue next hops for a given proxy-node + P, it is necessary to know which one of these to use in the case of + failure. This can be done by Select_Alternates_Proxy_Node(), as + shown in the pseudocode in Figure 29. + + + + + +Enyedi, et al. Standards Track [Page 53] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + def Select_Alternates_Proxy_Node(P,F,primary_intf): + S = primary_intf.local_node + X = P.pnar_X + Y = P.pnar_Y + A = X.order_proxy + B = Y.order_proxy + if F is A and F is B: + return 'PRIM_NH_IS_OP_FOR_BOTH_X_AND_Y' + if F is A: + return 'USE_RED' + if F is B: + return 'USE_BLUE' + + if not In_Common_Block(A, B): + if In_Common_Block(F, A): + return 'USE_RED' + elif In_Common_Block(F, B): + return 'USE_BLUE' + else: + return 'USE_RED_OR_BLUE' + if (not In_Common_Block(F, A) + and not In_Common_Block(F, A) ): + return 'USE_RED_OR_BLUE' + + alt_to_X = Select_Alternates(X, F, primary_intf) + alt_to_Y = Select_Alternates(Y, F, primary_intf) + + if (alt_to_X == 'USE_RED_OR_BLUE' + and alt_to_Y == 'USE_RED_OR_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED_OR_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED_OR_BLUE': + return 'USE_RED' + + if (A is S.localroot + and B is S.localroot): + // case 1.0 + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if (A is S.localroot + and B is not S.localroot): + // case 2.0 + + + +Enyedi, et al. Standards Track [Page 54] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if B.LOWER: + // case 2.1 + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if B.HIGHER: + // case 2.2 + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + else: + // case 2.3 + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if (A is not S.localroot + and B is S.localroot): + // case 3.0 + if A.LOWER: + // case 3.1 + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if A.HIGHER: + // case 3.2 + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + + + +Enyedi, et al. Standards Track [Page 55] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + else: + // case 3.3 + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if (A is not S.localroot + and B is not S.localroot): + // case 4.0 + if (S is A.localroot or S is B.localroot): + // case 4.05 + if A.topo_order < B.topo_order: + // case 4.05.1 + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + // case 4.05.2 + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if A.LOWER: + // case 4.1 + if B.HIGHER: + // case 4.1.1 + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if B.LOWER: + // case 4.1.2 + if A.topo_order < B.topo_order: + // case 4.1.2.1 + if (alt_to_X == 'USE_BLUE' + + + +Enyedi, et al. Standards Track [Page 56] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + // case 4.1.2.2 + if (alt_to_X == 'USE_RED' + and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + else: + // case 4.1.3 + if (F.LOWER and not F.HIGHER + and F.topo_order > A.topo_order): + // case 4.1.3.1 + return 'USE_RED' + else: + // case 4.1.3.2 + return 'USE_BLUE' + if A.HIGHER: + // case 4.2 + if B.HIGHER: + // case 4.2.1 + if A.topo_order < B.topo_order: + // case 4.2.1.1 + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + // case 4.2.1.2 + if (alt_to_X == 'USE_RED' + and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + + + +Enyedi, et al. Standards Track [Page 57] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + return 'USE_RED' + assert(False) + if B.LOWER: + // case 4.2.2 + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + // case 4.2.3 + if (F.HIGHER and not F.LOWER + and F.topo_order < A.topo_order): + return 'USE_RED' + else: + return 'USE_BLUE' + else: + // case 4.3 + if B.LOWER: + // case 4.3.1 + if (F.LOWER and not F.HIGHER + and F.topo_order > B.topo_order): + return 'USE_BLUE' + else: + return 'USE_RED' + if B.HIGHER: + // case 4.3.2 + if (F.HIGHER and not F.LOWER + and F.topo_order < B.topo_order): + return 'USE_BLUE' + else: + return 'USE_RED' + else: + // case 4.3.3 + if A.topo_order < B.topo_order: + // case 4.3.3.1 + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + + + + +Enyedi, et al. Standards Track [Page 58] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + else: + // case 4.3.3.2 + if (alt_to_X == 'USE_RED' + and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + assert(False) + + Figure 29: Select_Alternates_Proxy_Node() + + Select_Alternates_Proxy_Node(P,F,primary_intf) determines whether it + is safe to use the blue path to P (which goes through X), the red + path to P (which goes through Y), or either, when the primary_intf to + node F (and possibly node F) fails. The basic approach is to run + Select_Alternates(X,F,primary_intf) and + Select_Alternates(Y,F,primary_intf) to determine which of the two MRT + paths to X and which of the two MRT paths to Y is safe to use in the + event of the failure of F. In general, we will find that if it is + safe to use a particular path to X or Y when F fails, and + Select_Proxy_Node_NHs() used that path when constructing the red or + blue path to reach P, then it will also be safe to use that path to + reach P when F fails. This rule has one exception which is covered + below. First, we give a concrete example of how + Select_Alternates_Proxy_Node() works in the common case. + + The 21 ordering relationships used in Select_Proxy_Node_NHs() are + repeated in Select_Alternates_Proxy_Node(). We focus on case 4.1.1 + to give a detailed example of the reasoning used in + Select_Alternates_Proxy_Node(). In Select_Proxy_Node_NHs(), we + determined for case 4.1.1 that the red next hops to X and the blue + next hops to Y allow us to reach X and Y by disjoint paths, and are + thus the blue and red next hops to reach P. Therefore, if + Select_Alternates(X, F, primary_intf) is run and we find that it is + safe to USE_RED to reach X, then we also conclude that it is safe to + use the MRT path through X to reach P (the blue path to P) when F + fails. Similarly, if we run Select_Alternates(Y, F, primary_intf) + and we find that it is safe to USE_BLUE to reach Y, then we also + conclude that it is safe to use the MRT path through Y to reach P + (the red path to P) when F fails. If both of the paths that were + used in Select_Proxy_Node_NHs() to construct the blue and red paths + to P are found to be safe to use to use to reach X and Y, t then we + conclude that we can use either the red or the blue path to P. + + + + + +Enyedi, et al. Standards Track [Page 59] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + This simple reasoning gives the correct answer in most of the cases. + However, additional logic is needed when either A or B (but not both + A and B) is unordered with respect to S. This applies to cases + 4.1.3, 4.2.3, 4.3.1, and 4.3.2. Looking at case 4.1.3 in more + detail, A is ordered less than S, but B is unordered with respect to + S. In the discussion of case 4.1.3 above, we saw that + Select_Proxy_Node_NHs() chose the red path to reach Y and the red + path to reach X. We also saw that the red path to reach Y will + follow the INCREASING next hops towards the localroot until it + reaches some node (L) which is ordered greater than B, after which it + will take DECREASING next hops to B. The problem is that the red + path to reach P (the one that goes through Y) won't necessarily be + the same as the red path to reach Y. This is because the next hop + that node L computes for its red next hop to reach P may be different + from the next hop it computes for its red next hop to reach Y. This + is because B is ordered lower than L, so L applies case 4.1.2 of + Select_Proxy_Node_NHs() in order to determine its next hops to reach + P. If A.topo_order<B.topo_order (case 4.1.2.1), then L will choose + DECREASING next hops directly to B, which is the same result that L + computes in Compute_MRT_NextHops() to reach Y. However, if + A.topo_order>B.topo_order (case 4.1.2.2), then L will choose + INCREASING next hops to reach B, which is different from what L + computes in Compute_MRT_NextHops() to reach Y. So, testing the + safety of the path for S to reach Y on failure of F as a surrogate + for the safety of using the red path to reach P is not reliable in + this case. It is possible construct topologies where the red path to + P hits F even though the red path to Y does not hit F. + + Fortunately, there is enough information in the order relationships + that we have already computed to still figure out which alternate to + choose in these four cases. The basic idea is to always choose the + path involving the ordered node, unless that path would hit F. + Returning to case 4.1.3, we see that since A is ordered lower than S, + the only way for S to hit F using a simple DECREASING path to A is + for F to lie between A and S on the GADAG. This scenario is covered + by requiring that F be lower than S (but not also higher than S) and + that F.topo_order>A.topo_order in case 4.1.3.1. + + We just need to confirm that it is safe to use the path involving B + in this scenario. In case 4.1.3.1, either F is between A and S on + the GADAG, or F is unordered with respect to A and lies on the + DECREASING path from S to the localroot. When F is between A and S + on the GADAG, then the path through B chosen to avoid A in + Select_Proxy_Node_NHs() will also avoid F. When F is unordered with + respect to A and lies on the DECREASING path from S to the localroot, + then we consider two cases. Either F.topo_order<B.topo_order or + F.topo_order>B.topo_order. In the first case, since + F.topo_order<B.topo_order and F.topo_order>A.topo_order, it must be + + + +Enyedi, et al. Standards Track [Page 60] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + the case that A.topo_order<B.topo_order. Therefore, L will choose + DECREASING next hops directly to B (case 4.1.2.1), which cannot hit F + since F.topo_order<B.topo_order. In the second case, where + F.topo_order>B.topo_order, the only way for the path involving B to + hit F is if it DECREASES from L to B through F, i.e., it must be that + L>>F>>B. However, since S>>F, this would imply that S>>B. However, + we know that S is unordered with respect to B, so the second case + cannot occur. So we have demonstrated that the red path to P (which + goes via B and Y) is safe to use under the conditions of 4.1.3.1. + Similar reasoning can be applied to the other three special cases + where either A or B is unordered with respect to S. + +6. MRT Lowpoint Algorithm: Next-Hop Conformance + + This specification defines the MRT Lowpoint algorithm, which includes + the construction of a common GADAG and the computation of MRT-Red and + MRT-Blue next hops to each node in the graph. An implementation MAY + select any subset of next hops for MRT-Red and MRT-Blue that respect + the available nodes that are described in Section 5.7 for each of the + MRT-Red and MRT-Blue and the selected next hops are further along in + the interval of allowed nodes towards the destination. + + For example, the MRT-Blue next hops used when the destination Y >> X, + the computing router, MUST be one or more nodes, T, whose topo_order + is in the interval [X.topo_order, Y.topo_order] and where Y >> T or Y + is T. Similarly, the MRT-Red next hops MUST be have a topo_order in + the interval [R-small.topo_order, X.topo_order] or [Y.topo_order, + R-big.topo_order]. + + Implementations SHOULD implement the Select_Alternates() function to + pick an MRT-FRR alternate. + +7. Broadcast Interfaces + + When broadcast interfaces are used to connect nodes, the broadcast + network MUST be represented as a pseudonode, where each real node + connects to the pseudonode. The interface metric in the direction + from real node to pseudonode is the non-zero interface metric, while + the interface metric in the direction from the pseudonode to the real + node is set to zero. This is consistent with the way that broadcast + interfaces are represented as pseudonodes in IS-IS and OSPF. + + Pseudonodes MUST be treated as equivalent to real nodes in the + network graph used in the MRT Lowpoint algorithm with a few + exceptions detailed below. + + The pseudonodes MUST be included in the computation of the GADAG. + The neighbors of the pseudonode need to know the mrt_node_id of the + + + +Enyedi, et al. Standards Track [Page 61] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + pseudonode in order to consistently order interfaces, which is needed + to compute the GADAG. The mrt_node_id for IS-IS is the 7-octet + neighbor system ID and pseudonode number in TLV 22 or TLV 222. The + mrt_node_id for OSPFv2 is the 4-octet interface address of the + Designated Router found in the Link ID field for the link type 2 + (transit network) in the Router-LSA. The mrt_node_id for OSPFv3 is + the 4 octet interface address of the Designated Router found in the + Neighbor Interface ID field for the link type 2 (transit network) in + the Router-LSA. Note that this is different from the Neighbor Router + ID field used for the mrt_node_id for point-to-point links in OSPFv3 + Router-LSAs given in Figure 15. + + Pseudonodes MUST NOT be considered candidates for selection as GADAG + root. This rule is intended to result in a more stable network-wide + selection of GADAG root by removing the possibility that the change + of Designated Router or Designated Intermediate System on a broadcast + network can result in a change of GADAG root. + +7.1. Computing MRT Next Hops on Broadcast Networks + + The pseudonode does not correspond to a real node, so it is not + actually involved in forwarding. A real node on a broadcast network + cannot simply forward traffic to the broadcast network. It must + specify another real node on the broadcast network as the next hop. + On a network graph where a broadcast network is represented by a + pseudonode, this means that if a real node determines that the next + hop to reach a given destination is a pseudonode, it must also + determine the next-next-hop for that destination in the network + graph, which corresponds to a real node attached to the broadcast + network. + + It is interesting to note that this issue is not unique to the MRT + algorithm, but is also encountered in normal SPF computations for + IGPs. Section 16.1.1 of [RFC2328] describes how this is done for + OSPF. When OSPF runs its shortest-path tree calculation, it deals + with pseudonodes in the following manner. Whenever the calculating + router finds a shorter path to reach a real destination node and the + shorter path to the destination is a single pseudonode hop, then the + next hop for that destination is taken from the interface IP address + in the Router-LSA correspond to the link to the real destination + node. + + For IS-IS, in the example pseudocode implementation of Dijkstra's + algorithm in Annex C of [ISO10589-Second-Edition], whenever the + algorithm encounters an adjacency from a real node to a pseudonode, + it gets converted to a set of adjacencies from the real node to the + neighbors of the pseudonode. In this way, the computed next hops + point all the way to the real node, and not the pseudonode. + + + +Enyedi, et al. Standards Track [Page 62] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + We could avoid the problem of determining next hops across + pseudonodes in MRT by converting the pseudonode representation of + broadcast networks to a full mesh of links between real nodes on the + same network. However, if we make that conversion before computing + the GADAG, we lose information about which links actually correspond + to a single physical interface into the broadcast network. This + could result computing red and blue next hops that use the same + broadcast interface, in which case neither the red nor the blue next + hop would be usable as an alternate on failure of the broadcast + interface. + + Instead, we take the following approach, which maintains the property + that either the red and blue next hop will avoid the broadcast + network, if topologically allowed. We run the MRT Lowpoint algorithm + treating the pseudonodes as equivalent to real nodes in the network + graph, with the exceptions noted above. In addition to running the + MRT Lowpoint algorithm from the point of view of itself, a computing + router connected to a pseudonode MUST also run the MRT Lowpoint + algorithm from the point of view of each of its pseudonode neighbors. + For example, if a computing router S determines that its MRT red next + hop to reach a destination D is a pseudonode P, S looks at its MRT + Lowpoint algorithm computation from P's point of view to determine + P's red next hop to reach D, say interface 1 on node X. S now knows + that its real red next hop to reach D is interface 1 on node X on the + broadcast network represented by P, and it can install the + corresponding entry in its FIB. + +7.2. Using MRT Next Hops as Alternates in the Event of Failures on + Broadcast Networks + + In the previous section, we specified how to compute MRT next hops + when broadcast networks are involved. In this section, we discuss + how a PLR can use those MRT next hops in the event of failures + involving broadcast networks. + + A PLR attached to a broadcast network running only OSPF or IS-IS with + large Hello intervals has limited ability to quickly detect failures + on a broadcast network. The only failure mode that can be quickly + detected is the failure of the physical interface connecting the PLR + to the broadcast network. For the failure of the interface + connecting the PLR to the broadcast network, the alternate that + avoids the broadcast network can be computed by using the broadcast + network pseudonode as F, the primary next-hop node, in + Select_Alternates(). This will choose an alternate path that avoids + the broadcast network. However, the alternate path will not + necessarily avoid all of the real nodes connected to the broadcast + network. This is because we have used the pseudonode to represent + the broadcast network. And we have enforced the node-protecting + + + +Enyedi, et al. Standards Track [Page 63] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + property of MRT on the pseudonode to provide protection against + failure of the broadcast network, not the real next-hop nodes on the + broadcast network. This is the best that we can hope to do if + failure of the broadcast interface is the only failure mode that the + PLR can respond to. + + We can improve on this if the PLR also has the ability to quickly + detect a lack of connectivity across the broadcast network to a given + IP-layer node. This can be accomplished by running BFD between all + pairs of IGP neighbors on the broadcast network. Note that in the + case of OSPF, this would require establishing BFD sessions between + all pairs of neighbors in the 2-WAY state. When the PLR can quickly + detect the failure of a particular next hop across a broadcast + network, the PLR can be more selective in its choice of alternates. + For example, when the PLR observes that connectivity to an IP-layer + node on a broadcast network has failed, the PLR may choose to still + use the broadcast network to reach other IP-layer nodes that are + still reachable. Or, if the PLR observes that connectivity has + failed to several IP-layer nodes on the same broadcast network, it + may choose to treat the entire broadcast network as failed. The + choice of MRT alternates by a PLR for a particular set of failure + conditions is a local decision, since it does not require + coordination with other nodes. + +8. Evaluation of Alternative Methods for Constructing GADAGs + + This document specifies the MRT Lowpoint algorithm. One component of + the algorithm involves constructing a common GADAG based on the + network topology. The MRT Lowpoint algorithm computes the GADAG + using the method described in Section 5.5. This method aims to + minimize the amount of computation required to compute the GADAG. In + the process of developing the MRT Lowpoint algorithm, two alternative + methods for constructing GADAGs were also considered. These + alternative methods are described in Appendices B and C. In general, + these other two methods require more computation to compute the + GADAG. The analysis below was performed to determine if the + alternative GADAG construction methods produce shorter MRT alternate + paths in real network topologies, and if so, to what extent. + + Figure 30 compares results obtained using the three different methods + for constructing GADAGs on five different service provider network + topologies. MRT_LOWPOINT indicates the method specified in + Section 5.5, while MRT_SPF and MRT_HYBRID indicate the methods + specified in Appendices B and C, respectively. The columns on the + right present the distribution of alternate path lengths for each + GADAG construction method. Each MRT computation was performed using + a same GADAG root chosen based on centrality. + + + + +Enyedi, et al. Standards Track [Page 64] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + For three of the topologies analyzed (T201, T206, and T211), the use + of MRT_SPF or MRT_HYBRID methods does not appear to provide a + significantly shorter alternate path lengths compared to the + MRT_LOWPOINT method. However, for two of the topologies (T216 and + T219), the use of the MRT_SPF method resulted in noticeably shorter + alternate path lengths than the use of the MRT_LOWPOINT or MRT_HYBRID + methods. + + It was decided to use the MRT_LOWPOINT method to construct the GADAG + in the algorithm specified in this document, in order to initially + offer an algorithm with lower computational requirements. These + results indicate that in the future it may be useful to evaluate and + potentially specify other MRT Lowpoint algorithm variants that use + different GADAG construction methods. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 65] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + +-------------------------------------------------------------------+ + | Topology name | percentage of failure scenarios | + | | protected by an alternate N hops | + | GADAG construction | longer than the primary path | + | method +------------------------------------+ + | | | | | | | | | | no | + | | | | | | |10 |12 |14 | alt| + | |0-1|2-3|4-5|6-7|8-9|-11|-13|-15| <16| + +------------------------------+---+---+---+---+---+---+---+---+----+ + | T201(avg primary hops=3.5) | | | | | | | | | | + | MRT_HYBRID | 33| 26| 23| 6| 3| | | | | + | MRT_SPF | 33| 36| 23| 6| 3| | | | | + | MRT_LOWPOINT | 33| 36| 23| 6| 3| | | | | + +------------------------------+---+---+---+---+---+---+---+---+----+ + | T206(avg primary hops=3.7) | | | | | | | | | | + | MRT_HYBRID | 50| 35| 13| 2| | | | | | + | MRT_SPF | 50| 35| 13| 2| | | | | | + | MRT_LOWPOINT | 55| 32| 13| | | | | | | + +------------------------------+---+---+---+---+---+---+---+---+----+ + | T211(avg primary hops=3.3) | | | | | | | | | | + | MRT_HYBRID | 86| 14| | | | | | | | + | MRT_SPF | 86| 14| | | | | | | | + | MRT_LOWPOINT | 85| 15| 1| | | | | | | + +------------------------------+---+---+---+---+---+---+---+---+----+ + | T216(avg primary hops=5.2) | | | | | | | | | | + | MRT_HYBRID | 23| 22| 18| 13| 10| 7| 4| 2| 2| + | MRT_SPF | 35| 32| 19| 9| 3| 1| | | | + | MRT_LOWPOINT | 28| 25| 18| 11| 7| 6| 3| 2| 1| + +------------------------------+---+---+---+---+---+---+---+---+----+ + | T219(avg primary hops=7.7) | | | | | | | | | | + | MRT_HYBRID | 20| 16| 13| 10| 7| 5| 5| 5| 3| + | MRT_SPF | 31| 23| 19| 12| 7| 4| 2| 1| | + | MRT_LOWPOINT | 19| 14| 15| 12| 10| 8| 7| 6| 10| + +------------------------------+---+---+---+---+---+---+---+---+----+ + + + Figure 30: The Length of Alternate Paths for Various GADAG + Construction Methods + +9. Operational Considerations + + This section discusses operational considerations related to the MRT + Lowpoint algorithm and other potential MRT algorithm variants. For a + discussion of operational considerations related to MRT-FRR in + general, see the "Operational Considerations" section of [RFC7812]. + + + + + + +Enyedi, et al. Standards Track [Page 66] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +9.1. GADAG Root Selection + + The Default MRT Profile uses the GADAG Root Selection Priority + advertised by routers as the primary criterion for selecting the + GADAG root. It is RECOMMENDED that an operator designate a set of + routers as good choices for selection as GADAG root by setting the + GADAG Root Selection Priority for that set of routers to lower (more + preferred) numerical values. Criteria for making this designation + are discussed below. + + Analysis has shown that the centrality of a router can have a + significant impact on the lengths of the alternate paths computed. + Therefore, it is RECOMMENDED that off-line analysis that considers + the centrality of a router be used to help determine how good a + choice a particular router is for the role of GADAG root. + + If the router currently selected as GADAG root becomes unreachable in + the IGP topology, then a new GADAG root will be selected. Changing + the GADAG root can change the overall structure of the GADAG as well + the paths of the red and MRT-Blue trees built using that GADAG. In + order to minimize change in the associated red and MRT-Blue + forwarding entries that can result from changing the GADAG root, it + is RECOMMENDED that operators prioritize for selection as GADAG root + those routers that are expected to consistently remain part of the + IGP topology. + +9.2. Destination-Rooted GADAGs + + The MRT Lowpoint algorithm constructs a single GADAG rooted at a + single node selected as the GADAG root. It is also possible to + construct a different GADAG for each destination, with the GADAG + rooted at the destination. A router can compute the MRT-Red and MRT- + Blue next hops for that destination based on the GADAG rooted at that + destination. Building a different GADAG for each destination is + computationally more expensive, but it may give somewhat shorter + alternate paths. Using destination-rooted GADAGs would require a new + MRT profile to be created with a new MRT algorithm specification, + since all routers in the MRT Island would need to use destination- + rooted GADAGs. + +10. Security Considerations + + The algorithm described in this document does not introduce new + security concerns beyond those already discussed in the document + describing the MRT FRR architecture [RFC7812]. + + + + + + +Enyedi, et al. Standards Track [Page 67] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +11. References + +11.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + <http://www.rfc-editor.org/info/rfc2119>. + + [RFC7812] Atlas, A., Bowers, C., and G. Enyedi, "An Architecture for + IP/LDP Fast Reroute Using Maximally Redundant Trees + (MRT-FRR)", RFC 7812, DOI 10.17487/RFC7812, June 2016, + <http://www.rfc-editor.org/info/rfc7812>. + +11.2. Informative References + + [EnyediThesis] + Enyedi, G., "Novel Algorithms for IP Fast Reroute", + Department of Telecommunications and Media Informatics, + Budapest University of Technology and Economics Ph.D. + Thesis, February 2011, + <https://repozitorium.omikk.bme.hu/bitstream/ + handle/10890/1040/ertekezes.pdf>. + + [IEEE8021Qca] + IEEE, "IEEE Standard for Local and metropolitan area + networks - Bridges and Bridged Networks - Amendment 24: + Path Control and Reservation", IEEE 802.1Qca-2015, + DOI 10.1109/IEEESTD.2016.7434544, 2016, + <https://standards.ieee.org/findstds/ + standard/802.1Qca-2015.html>. + + [ISO10589-Second-Edition] + International Organization for Standardization, + "Intermediate system to Intermediate system intra-domain + routeing information exchange protocol for use in + conjunction with the protocol for providing the + connectionless-mode Network Service (ISO 8473)", ISO/ + IEC 10589:2002, Second Edition, November 2002. + + [Kahn_1962_topo_sort] + Kahn, A., "Topological sorting of large networks", + Communications of the ACM, Volume 5, Issue 11 DOI + 10.1145/368996.369025, November 1962, + <http://dl.acm.org/citation.cfm?doid=368996.369025>. + + + + + + +Enyedi, et al. Standards Track [Page 68] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + [MRTLinear] + Enyedi, G., Retvari, G., and A. Csaszar, "On Finding + Maximally Redundant Trees in Strictly Linear Time", IEEE + Symposium on Computers and Communications (ISCC), 2009, + <http://opti.tmit.bme.hu/~enyedi/ipfrr/ + distMaxRedTree.pdf>. + + [RFC2328] Moy, J., "OSPF Version 2", STD 54, RFC 2328, + DOI 10.17487/RFC2328, April 1998, + <http://www.rfc-editor.org/info/rfc2328>. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 69] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +Appendix A. Python Implementation of MRT Lowpoint Algorithm + + Below is Python code implementing the MRT Lowpoint algorithm + specified in this document. The code is also posted on GitHub + <https://github.com/cbowers/draft-ietf-rtgwg-mrt-frr- + algorithm/blob/python_code_RFC7811/src/mrt_lowpoint_draft_text.py>. + + While this Python code is believed to correctly implement the + pseudocode description of the algorithm, in the event of a + difference, the pseudocode description should be considered + normative. + +<CODE BEGINS> +# This program has been tested to run on Python 2.6 and 2.7 +# (specifically Python 2.6.6 and 2.7.8 were tested). +# The program has known incompatibilities with Python 3.X. + +# When executed, this program will generate a text file describing +# an example topology. It then reads that text file back in as input +# to create the example topology, and runs the MRT Lowpoint algorithm. +# This was done to simplify the inclusion of the program as a single +# text file that can be extracted from the RFC. + +# The output of the program is four text files containing a description +# of the GADAG, the blue and MRT-Reds for all destinations, and the +# MRT alternates for all failures. + +import random +import os.path +import heapq + +# simple Class definitions allow structure-like dot notation for +# variables and a convenient place to initialize those variables. +class Topology: + def __init__(self): + self.gadag_root = None + self.node_list = [] + self.node_dict = {} + self.test_gr = None + self.island_node_list_for_test_gr = [] + self.stored_named_proxy_dict = {} + self.init_new_computing_router() + def init_new_computing_router(self): + self.island_node_list = [] + self.named_proxy_dict = {} + + + + + + +Enyedi, et al. Standards Track [Page 70] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +class Node: + def __init__(self): + self.node_id = None + self.intf_list = [] + self.profile_id_list = [0] + self.GR_sel_priority = 128 + self.blue_next_hops_dict = {} + self.red_next_hops_dict = {} + self.blue_to_green_nh_dict = {} + self.red_to_green_nh_dict = {} + self.prefix_cost_dict = {} + self.pnh_dict = {} + self.alt_dict = {} + self.init_new_computing_router() + def init_new_computing_router(self): + self.island_intf_list = [] + self.IN_MRT_ISLAND = False + self.IN_GADAG = False + self.dfs_number = None + self.dfs_parent = None + self.dfs_parent_intf = None + self.dfs_child_list = [] + self.lowpoint_number = None + self.lowpoint_parent = None + self.lowpoint_parent_intf = None + self.localroot = None + self.block_id = None + self.IS_CUT_VERTEX = False + self.blue_next_hops = [] + self.red_next_hops = [] + self.primary_next_hops = [] + self.alt_list = [] + +class Interface: + def __init__(self): + self.metric = None + self.area = None + self.MRT_INELIGIBLE = False + self.IGP_EXCLUDED = False + self.SIMULATION_OUTGOING = False + self.init_new_computing_router() + def init_new_computing_router(self): + self.UNDIRECTED = True + self.INCOMING = False + self.OUTGOING = False + self.INCOMING_STORED = False + self.OUTGOING_STORED = False + self.IN_MRT_ISLAND = False + + + +Enyedi, et al. Standards Track [Page 71] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + self.PROCESSED = False + +class Bundle: + def __init__(self): + self.UNDIRECTED = True + self.OUTGOING = False + self.INCOMING = False + +class Alternate: + def __init__(self): + self.failed_intf = None + self.red_or_blue = None + self.nh_list = [] + self.fec = 'NO_ALTERNATE' + self.prot = 'NO_PROTECTION' + self.info = 'NONE' + +class Proxy_Node_Attachment_Router: + def __init__(self): + self.prefix = None + self.node = None + self.named_proxy_cost = None + self.min_lfin = None + self.nh_intf_list = [] + +class Named_Proxy_Node: + def __init__(self): + self.node_id = None #this is the prefix_id + self.node_prefix_cost_list = [] + self.lfin_list = [] + self.pnar1 = None + self.pnar2 = None + self.pnar_X = None + self.pnar_Y = None + self.blue_next_hops = [] + self.red_next_hops = [] + self.primary_next_hops = [] + self.blue_next_hops_dict = {} + self.red_next_hops_dict = {} + self.pnh_dict = {} + self.alt_dict = {} + +def Interface_Compare(intf_a, intf_b): + if intf_a.metric < intf_b.metric: + return -1 + if intf_b.metric < intf_a.metric: + return 1 + if intf_a.remote_node.node_id < intf_b.remote_node.node_id: + + + +Enyedi, et al. Standards Track [Page 72] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + return -1 + if intf_b.remote_node.node_id < intf_a.remote_node.node_id: + return 1 + return 0 + +def Sort_Interfaces(topo): + for node in topo.island_node_list: + node.island_intf_list.sort(Interface_Compare) + +def Reset_Computed_Node_and_Intf_Values(topo): + topo.init_new_computing_router() + for node in topo.node_list: + node.init_new_computing_router() + for intf in node.intf_list: + intf.init_new_computing_router() + +# This function takes a file with links represented by 2-digit +# numbers in the format: +# 01,05,10 +# 05,02,30 +# 02,01,15 +# which represents a triangle topology with nodes 01, 05, and 02 +# and symmetric metrics of 10, 30, and 15. + +# Inclusion of a fourth column makes the metrics for the link +# asymmetric. An entry of: +# 02,07,10,15 +# creates a link from node 02 to 07 with metrics 10 and 15. +def Create_Topology_From_File(filename): + topo = Topology() + node_id_set= set() + cols_list = [] + # on first pass just create nodes + with open(filename + '.csv') as topo_file: + for line in topo_file: + line = line.rstrip('\r\n') + cols=line.split(',') + cols_list.append(cols) + nodea_node_id = int(cols[0]) + nodeb_node_id = int(cols[1]) + if (nodea_node_id > 999 or nodeb_node_id > 999): + print("node_id must be between 0 and 999.") + print("exiting.") + exit() + node_id_set.add(nodea_node_id) + node_id_set.add(nodeb_node_id) + for node_id in node_id_set: + node = Node() + + + +Enyedi, et al. Standards Track [Page 73] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + node.node_id = node_id + topo.node_list.append(node) + topo.node_dict[node_id] = node + # on second pass create interfaces + for cols in cols_list: + nodea_node_id = int(cols[0]) + nodeb_node_id = int(cols[1]) + metric = int(cols[2]) + reverse_metric = int(cols[2]) + if len(cols) > 3: + reverse_metric=int(cols[3]) + nodea = topo.node_dict[nodea_node_id] + nodeb = topo.node_dict[nodeb_node_id] + nodea_intf = Interface() + nodea_intf.metric = metric + nodea_intf.area = 0 + nodeb_intf = Interface() + nodeb_intf.metric = reverse_metric + nodeb_intf.area = 0 + nodea_intf.remote_intf = nodeb_intf + nodeb_intf.remote_intf = nodea_intf + nodea_intf.remote_node = nodeb + nodeb_intf.remote_node = nodea + nodea_intf.local_node = nodea + nodeb_intf.local_node = nodeb + nodea_intf.link_data = len(nodea.intf_list) + nodeb_intf.link_data = len(nodeb.intf_list) + nodea.intf_list.append(nodea_intf) + nodeb.intf_list.append(nodeb_intf) + return topo + +def MRT_Island_Identification(topo, computing_rtr, profile_id, area): + if profile_id in computing_rtr.profile_id_list: + computing_rtr.IN_MRT_ISLAND = True + explore_list = [computing_rtr] + else: + return + while explore_list != []: + next_rtr = explore_list.pop() + for intf in next_rtr.intf_list: + if ( (not intf.IN_MRT_ISLAND) + and (not intf.MRT_INELIGIBLE) + and (not intf.remote_intf.MRT_INELIGIBLE) + and (not intf.IGP_EXCLUDED) and intf.area == area + and (profile_id in intf.remote_node.profile_id_list)): + intf.IN_MRT_ISLAND = True + intf.remote_intf.IN_MRT_ISLAND = True + if (not intf.remote_node.IN_MRT_ISLAND): + + + +Enyedi, et al. Standards Track [Page 74] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + intf.remote_INTF.IN_MRT_ISLAND = True + explore_list.append(intf.remote_node) + +def Compute_Island_Node_List_For_Test_GR(topo, test_gr): + Reset_Computed_Node_and_Intf_Values(topo) + topo.test_gr = topo.node_dict[test_gr] + MRT_Island_Identification(topo, topo.test_gr, 0, 0) + for node in topo.node_list: + if node.IN_MRT_ISLAND: + topo.island_node_list_for_test_gr.append(node) + +def Set_Island_Intf_and_Node_Lists(topo): + for node in topo.node_list: + if node.IN_MRT_ISLAND: + topo.island_node_list.append(node) + for intf in node.intf_list: + if intf.IN_MRT_ISLAND: + node.island_intf_list.append(intf) + +global_dfs_number = None + +def Lowpoint_Visit(x, parent, intf_p_to_x): + global global_dfs_number + x.dfs_number = global_dfs_number + x.lowpoint_number = x.dfs_number + global_dfs_number += 1 + x.dfs_parent = parent + if intf_p_to_x == None: + x.dfs_parent_intf = None + else: + x.dfs_parent_intf = intf_p_to_x.remote_intf + x.lowpoint_parent = None + if parent != None: + parent.dfs_child_list.append(x) + for intf in x.island_intf_list: + if intf.remote_node.dfs_number == None: + Lowpoint_Visit(intf.remote_node, x, intf) + if intf.remote_node.lowpoint_number < x.lowpoint_number: + x.lowpoint_number = intf.remote_node.lowpoint_number + x.lowpoint_parent = intf.remote_node + x.lowpoint_parent_intf = intf + else: + if intf.remote_node is not parent: + if intf.remote_node.dfs_number < x.lowpoint_number: + x.lowpoint_number = intf.remote_node.dfs_number + x.lowpoint_parent = intf.remote_node + x.lowpoint_parent_intf = intf + + + + +Enyedi, et al. Standards Track [Page 75] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +def Run_Lowpoint(topo): + global global_dfs_number + global_dfs_number = 0 + Lowpoint_Visit(topo.gadag_root, None, None) + +max_block_id = None + +def Assign_Block_ID(x, cur_block_id): + global max_block_id + x.block_id = cur_block_id + for c in x.dfs_child_list: + if (c.localroot is x): + max_block_id += 1 + Assign_Block_ID(c, max_block_id) + else: + Assign_Block_ID(c, cur_block_id) + +def Run_Assign_Block_ID(topo): + global max_block_id + max_block_id = 0 + Assign_Block_ID(topo.gadag_root, max_block_id) + +def Construct_Ear(x, stack, intf, ear_type): + ear_list = [] + cur_intf = intf + not_done = True + while not_done: + cur_intf.UNDIRECTED = False + cur_intf.OUTGOING = True + cur_intf.remote_intf.UNDIRECTED = False + cur_intf.remote_intf.INCOMING = True + if cur_intf.remote_node.IN_GADAG == False: + cur_intf.remote_node.IN_GADAG = True + ear_list.append(cur_intf.remote_node) + if ear_type == 'CHILD': + cur_intf = cur_intf.remote_node.lowpoint_parent_intf + else: + assert ear_type == 'NEIGHBOR' + cur_intf = cur_intf.remote_node.dfs_parent_intf + else: + not_done = False + + if ear_type == 'CHILD' and cur_intf.remote_node is x: + # x is a cut-vertex and the local root for the block + # in which the ear is computed + x.IS_CUT_VERTEX = True + localroot = x + else: + + + +Enyedi, et al. Standards Track [Page 76] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + # inherit local root from the end of the ear + localroot = cur_intf.remote_node.localroot + + while ear_list != []: + y = ear_list.pop() + y.localroot = localroot + stack.append(y) + +def Construct_GADAG_via_Lowpoint(topo): + gadag_root = topo.gadag_root + gadag_root.IN_GADAG = True + gadag_root.localroot = None + stack = [] + stack.append(gadag_root) + while stack != []: + x = stack.pop() + for intf in x.island_intf_list: + if ( intf.remote_node.IN_GADAG == False + and intf.remote_node.dfs_parent is x ): + Construct_Ear(x, stack, intf, 'CHILD' ) + for intf in x.island_intf_list: + if (intf.remote_node.IN_GADAG == False + and intf.remote_node.dfs_parent is not x): + Construct_Ear(x, stack, intf, 'NEIGHBOR') + +def Assign_Remaining_Lowpoint_Parents(topo): + for node in topo.island_node_list: + if ( node is not topo.gadag_root + and node.lowpoint_parent == None ): + node.lowpoint_parent = node.dfs_parent + node.lowpoint_parent_intf = node.dfs_parent_intf + node.lowpoint_number = node.dfs_parent.dfs_number + +def Add_Undirected_Block_Root_Links(topo): + for node in topo.island_node_list: + if node.IS_CUT_VERTEX or node is topo.gadag_root: + for intf in node.island_intf_list: + if ( intf.remote_node.localroot is not node + or intf.PROCESSED ): + continue + bundle_list = [] + bundle = Bundle() + for intf2 in node.island_intf_list: + if intf2.remote_node is intf.remote_node: + bundle_list.append(intf2) + if not intf2.UNDIRECTED: + bundle.UNDIRECTED = False + if intf2.INCOMING: + + + +Enyedi, et al. Standards Track [Page 77] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + bundle.INCOMING = True + if intf2.OUTGOING: + bundle.OUTGOING = True + if bundle.UNDIRECTED: + for intf3 in bundle_list: + intf3.UNDIRECTED = False + intf3.remote_intf.UNDIRECTED = False + intf3.PROCESSED = True + intf3.remote_intf.PROCESSED = True + intf3.OUTGOING = True + intf3.remote_intf.INCOMING = True + else: + if (bundle.OUTGOING and bundle.INCOMING): + for intf3 in bundle_list: + intf3.UNDIRECTED = False + intf3.remote_intf.UNDIRECTED = False + intf3.PROCESSED = True + intf3.remote_intf.PROCESSED = True + intf3.OUTGOING = True + intf3.INCOMING = True + intf3.remote_intf.INCOMING = True + intf3.remote_intf.OUTGOING = True + elif bundle.OUTGOING: + for intf3 in bundle_list: + intf3.UNDIRECTED = False + intf3.remote_intf.UNDIRECTED = False + intf3.PROCESSED = True + intf3.remote_intf.PROCESSED = True + intf3.OUTGOING = True + intf3.remote_intf.INCOMING = True + elif bundle.INCOMING: + for intf3 in bundle_list: + intf3.UNDIRECTED = False + intf3.remote_intf.UNDIRECTED = False + intf3.PROCESSED = True + intf3.remote_intf.PROCESSED = True + intf3.INCOMING = True + intf3.remote_intf.OUTGOING = True + +def Modify_Block_Root_Incoming_Links(topo): + for node in topo.island_node_list: + if ( node.IS_CUT_VERTEX == True or node is topo.gadag_root ): + for intf in node.island_intf_list: + if intf.remote_node.localroot is node: + if intf.INCOMING: + intf.INCOMING = False + intf.INCOMING_STORED = True + intf.remote_intf.OUTGOING = False + + + +Enyedi, et al. Standards Track [Page 78] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + intf.remote_intf.OUTGOING_STORED = True + +def Revert_Block_Root_Incoming_Links(topo): + for node in topo.island_node_list: + if ( node.IS_CUT_VERTEX == True or node is topo.gadag_root ): + for intf in node.island_intf_list: + if intf.remote_node.localroot is node: + if intf.INCOMING_STORED: + intf.INCOMING = True + intf.remote_intf.OUTGOING = True + intf.INCOMING_STORED = False + intf.remote_intf.OUTGOING_STORED = False + +def Run_Topological_Sort_GADAG(topo): + Modify_Block_Root_Incoming_Links(topo) + for node in topo.island_node_list: + node.unvisited = 0 + for intf in node.island_intf_list: + if (intf.INCOMING == True): + node.unvisited += 1 + working_list = [] + topo_order_list = [] + working_list.append(topo.gadag_root) + while working_list != []: + y = working_list.pop(0) + topo_order_list.append(y) + for intf in y.island_intf_list: + if ( intf.OUTGOING == True): + intf.remote_node.unvisited -= 1 + if intf.remote_node.unvisited == 0: + working_list.append(intf.remote_node) + next_topo_order = 1 + while topo_order_list != []: + y = topo_order_list.pop(0) + y.topo_order = next_topo_order + next_topo_order += 1 + Revert_Block_Root_Incoming_Links(topo) + +def Set_Other_Undirected_Links_Based_On_Topo_Order(topo): + for node in topo.island_node_list: + for intf in node.island_intf_list: + if intf.UNDIRECTED: + if node.topo_order < intf.remote_node.topo_order: + intf.OUTGOING = True + intf.UNDIRECTED = False + intf.remote_intf.INCOMING = True + intf.remote_intf.UNDIRECTED = False + else: + + + +Enyedi, et al. Standards Track [Page 79] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + intf.INCOMING = True + intf.UNDIRECTED = False + intf.remote_intf.OUTGOING = True + intf.remote_intf.UNDIRECTED = False + +def Initialize_Temporary_Interface_Flags(topo): + for node in topo.island_node_list: + for intf in node.island_intf_list: + intf.PROCESSED = False + intf.INCOMING_STORED = False + intf.OUTGOING_STORED = False + +def Add_Undirected_Links(topo): + Initialize_Temporary_Interface_Flags(topo) + Add_Undirected_Block_Root_Links(topo) + Run_Topological_Sort_GADAG(topo) + Set_Other_Undirected_Links_Based_On_Topo_Order(topo) + +def In_Common_Block(x,y): + if ( (x.block_id == y.block_id) + or ( x is y.localroot) or (y is x.localroot) ): + return True + return False + +def Copy_List_Items(target_list, source_list): + del target_list[:] # Python idiom to remove all elements of a list + for element in source_list: + target_list.append(element) + +def Add_Item_To_List_If_New(target_list, item): + if item not in target_list: + target_list.append(item) + +def Store_Results(y, direction): + if direction == 'INCREASING': + y.HIGHER = True + Copy_List_Items(y.blue_next_hops, y.next_hops) + if direction == 'DECREASING': + y.LOWER = True + Copy_List_Items(y.red_next_hops, y.next_hops) + if direction == 'NORMAL_SPF': + y.primary_spf_metric = y.spf_metric + Copy_List_Items(y.primary_next_hops, y.next_hops) + if direction == 'MRT_ISLAND_SPF': + Copy_List_Items(y.mrt_island_next_hops, y.next_hops) + if direction == 'COLLAPSED_SPF': + y.collapsed_metric = y.spf_metric + Copy_List_Items(y.collapsed_next_hops, y.next_hops) + + + +Enyedi, et al. Standards Track [Page 80] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +# Note that the Python heapq function allows for duplicate items, +# so we use the 'spf_visited' property to only consider a node +# as min_node the first time it gets removed from the heap. +def SPF_No_Traverse_Block_Root(topo, spf_root, block_root, direction): + spf_heap = [] + for y in topo.island_node_list: + y.spf_metric = 2147483647 # 2^31-1 + y.next_hops = [] + y.spf_visited = False + spf_root.spf_metric = 0 + heapq.heappush(spf_heap, + (spf_root.spf_metric, spf_root.node_id, spf_root) ) + while spf_heap != []: + #extract third element of tuple popped from heap + min_node = heapq.heappop(spf_heap)[2] + if min_node.spf_visited: + continue + min_node.spf_visited = True + Store_Results(min_node, direction) + if ( (min_node is spf_root) or (min_node is not block_root) ): + for intf in min_node.island_intf_list: + if ( ( (direction == 'INCREASING' and intf.OUTGOING ) + or (direction == 'DECREASING' and intf.INCOMING ) ) + and In_Common_Block(spf_root, intf.remote_node) ) : + path_metric = min_node.spf_metric + intf.metric + if path_metric < intf.remote_node.spf_metric: + intf.remote_node.spf_metric = path_metric + if min_node is spf_root: + intf.remote_node.next_hops = [intf] + else: + Copy_List_Items(intf.remote_node.next_hops, + min_node.next_hops) + heapq.heappush(spf_heap, + ( intf.remote_node.spf_metric, + intf.remote_node.node_id, + intf.remote_node ) ) + elif path_metric == intf.remote_node.spf_metric: + if min_node is spf_root: + Add_Item_To_List_If_New( + intf.remote_node.next_hops,intf) + else: + for nh_intf in min_node.next_hops: + Add_Item_To_List_If_New( + intf.remote_node.next_hops,nh_intf) + +def Normal_SPF(topo, spf_root): + spf_heap = [] + for y in topo.node_list: + + + +Enyedi, et al. Standards Track [Page 81] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + y.spf_metric = 2147483647 # 2^31-1 as max metric + y.next_hops = [] + y.primary_spf_metric = 2147483647 + y.primary_next_hops = [] + y.spf_visited = False + spf_root.spf_metric = 0 + heapq.heappush(spf_heap, + (spf_root.spf_metric,spf_root.node_id,spf_root) ) + while spf_heap != []: + #extract third element of tuple popped from heap + min_node = heapq.heappop(spf_heap)[2] + if min_node.spf_visited: + continue + min_node.spf_visited = True + Store_Results(min_node, 'NORMAL_SPF') + for intf in min_node.intf_list: + path_metric = min_node.spf_metric + intf.metric + if path_metric < intf.remote_node.spf_metric: + intf.remote_node.spf_metric = path_metric + if min_node is spf_root: + intf.remote_node.next_hops = [intf] + else: + Copy_List_Items(intf.remote_node.next_hops, + min_node.next_hops) + heapq.heappush(spf_heap, + ( intf.remote_node.spf_metric, + intf.remote_node.node_id, + intf.remote_node ) ) + elif path_metric == intf.remote_node.spf_metric: + if min_node is spf_root: + Add_Item_To_List_If_New( + intf.remote_node.next_hops,intf) + else: + for nh_intf in min_node.next_hops: + Add_Item_To_List_If_New( + intf.remote_node.next_hops,nh_intf) + +def Set_Edge(y): + if (y.blue_next_hops == [] and y.red_next_hops == []): + Set_Edge(y.localroot) + Copy_List_Items(y.blue_next_hops,y.localroot.blue_next_hops) + Copy_List_Items(y.red_next_hops ,y.localroot.red_next_hops) + y.order_proxy = y.localroot.order_proxy + +def Compute_MRT_NH_For_One_Src_To_Island_Dests(topo,x): + for y in topo.island_node_list: + y.HIGHER = False + y.LOWER = False + + + +Enyedi, et al. Standards Track [Page 82] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + y.red_next_hops = [] + y.blue_next_hops = [] + y.order_proxy = y + SPF_No_Traverse_Block_Root(topo, x, x.localroot, 'INCREASING') + SPF_No_Traverse_Block_Root(topo, x, x.localroot, 'DECREASING') + for y in topo.island_node_list: + if ( y is not x and (y.block_id == x.block_id) ): + assert (not ( y is x.localroot or x is y.localroot) ) + assert(not (y.HIGHER and y.LOWER) ) + if y.HIGHER == True: + Copy_List_Items(y.red_next_hops, + x.localroot.red_next_hops) + elif y.LOWER == True: + Copy_List_Items(y.blue_next_hops, + x.localroot.blue_next_hops) + else: + Copy_List_Items(y.blue_next_hops, + x.localroot.red_next_hops) + Copy_List_Items(y.red_next_hops, + x.localroot.blue_next_hops) + + # Inherit x's MRT next hops to reach the GADAG root + # from x's MRT next hops to reach its local root, + # but first check if x is the gadag_root (in which case + # x does not have a local root) or if x's local root + # is the gadag root (in which case we already have the + # x's MRT next hops to reach the gadag root) + if x is not topo.gadag_root and x.localroot is not topo.gadag_root: + Copy_List_Items(topo.gadag_root.blue_next_hops, + x.localroot.blue_next_hops) + Copy_List_Items(topo.gadag_root.red_next_hops, + x.localroot.red_next_hops) + topo.gadag_root.order_proxy = x.localroot + + # Inherit next hops and order_proxies to other blocks + for y in topo.island_node_list: + if (y is not topo.gadag_root and y is not x ): + Set_Edge(y) + +def Store_MRT_Nexthops_For_One_Src_To_Island_Dests(topo,x): + for y in topo.island_node_list: + if y is x: + continue + x.blue_next_hops_dict[y.node_id] = [] + x.red_next_hops_dict[y.node_id] = [] + Copy_List_Items(x.blue_next_hops_dict[y.node_id], + y.blue_next_hops) + + + + +Enyedi, et al. Standards Track [Page 83] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Copy_List_Items(x.red_next_hops_dict[y.node_id], + y.red_next_hops) + +def Store_Primary_and_Alts_For_One_Src_To_Island_Dests(topo,x): + for y in topo.island_node_list: + x.pnh_dict[y.node_id] = [] + Copy_List_Items(x.pnh_dict[y.node_id], y.primary_next_hops) + x.alt_dict[y.node_id] = [] + Copy_List_Items(x.alt_dict[y.node_id], y.alt_list) + +def Store_Primary_NHs_For_One_Source_To_Nodes(topo,x): + for y in topo.node_list: + x.pnh_dict[y.node_id] = [] + Copy_List_Items(x.pnh_dict[y.node_id], y.primary_next_hops) + +def Store_MRT_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,x): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + x.blue_next_hops_dict[P.node_id] = [] + x.red_next_hops_dict[P.node_id] = [] + Copy_List_Items(x.blue_next_hops_dict[P.node_id], + P.blue_next_hops) + Copy_List_Items(x.red_next_hops_dict[P.node_id], + P.red_next_hops) + +def Store_Alts_For_One_Src_To_Named_Proxy_Nodes(topo,x): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + x.alt_dict[P.node_id] = [] + Copy_List_Items(x.alt_dict[P.node_id], + P.alt_list) + +def Store_Primary_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,x): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + x.pnh_dict[P.node_id] = [] + Copy_List_Items(x.pnh_dict[P.node_id], + P.primary_next_hops) + +def Select_Alternates_Internal(D, F, primary_intf, + D_lower, D_higher, D_topo_order): + if D_higher and D_lower: + if F.HIGHER and F.LOWER: + if F.topo_order > D_topo_order: + return 'USE_BLUE' + else: + return 'USE_RED' + if F.HIGHER: + + + +Enyedi, et al. Standards Track [Page 84] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + return 'USE_RED' + if F.LOWER: + return 'USE_BLUE' + assert(primary_intf.MRT_INELIGIBLE + or primary_intf.remote_intf.MRT_INELIGIBLE) + return 'USE_RED_OR_BLUE' + if D_higher: + if F.HIGHER and F.LOWER: + return 'USE_BLUE' + if F.LOWER: + return 'USE_BLUE' + if F.HIGHER: + if (F.topo_order > D_topo_order): + return 'USE_BLUE' + if (F.topo_order < D_topo_order): + return 'USE_RED' + assert(False) + assert(primary_intf.MRT_INELIGIBLE + or primary_intf.remote_intf.MRT_INELIGIBLE) + return 'USE_RED_OR_BLUE' + if D_lower: + if F.HIGHER and F.LOWER: + return 'USE_RED' + if F.HIGHER: + return 'USE_RED' + if F.LOWER: + if F.topo_order > D_topo_order: + return 'USE_BLUE' + if F.topo_order < D_topo_order: + return 'USE_RED' + assert(False) + assert(primary_intf.MRT_INELIGIBLE + or primary_intf.remote_intf.MRT_INELIGIBLE) + return 'USE_RED_OR_BLUE' + else: # D is unordered wrt S + if F.HIGHER and F.LOWER: + if primary_intf.OUTGOING and primary_intf.INCOMING: + # This can happen when F and D are in different blocks + return 'USE_RED_OR_BLUE' + if primary_intf.OUTGOING: + return 'USE_BLUE' + if primary_intf.INCOMING: + return 'USE_RED' + #This can occur when primary_intf is MRT_INELIGIBLE. + #This appears to be a case where the special + #construction of the GADAG allows us to choose red, + #whereas with an arbitrary GADAG, neither red nor blue + #is guaranteed to work. + + + +Enyedi, et al. Standards Track [Page 85] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + assert(primary_intf.MRT_INELIGIBLE + or primary_intf.remote_intf.MRT_INELIGIBLE) + return 'USE_RED' + if F.LOWER: + return 'USE_RED' + if F.HIGHER: + return 'USE_BLUE' + assert(primary_intf.MRT_INELIGIBLE + or primary_intf.remote_intf.MRT_INELIGIBLE) + if F.topo_order > D_topo_order: + return 'USE_BLUE' + else: + return 'USE_RED' + +def Select_Alternates(D, F, primary_intf): + S = primary_intf.local_node + if not In_Common_Block(F, S): + return 'PRIM_NH_IN_DIFFERENT_BLOCK' + if (D is F) or (D.order_proxy is F): + return 'PRIM_NH_IS_D_OR_OP_FOR_D' + D_lower = D.order_proxy.LOWER + D_higher = D.order_proxy.HIGHER + D_topo_order = D.order_proxy.topo_order + return Select_Alternates_Internal(D, F, primary_intf, + D_lower, D_higher, D_topo_order) + + +def Is_Remote_Node_In_NH_List(node, intf_list): + for intf in intf_list: + if node is intf.remote_node: + return True + return False + +def Select_Alts_For_One_Src_To_Island_Dests(topo,x): + Normal_SPF(topo, x) + for D in topo.island_node_list: + D.alt_list = [] + if D is x: + continue + for failed_intf in D.primary_next_hops: + alt = Alternate() + alt.failed_intf = failed_intf + cand_alt_list = [] + F = failed_intf.remote_node + #We need to test if F is in the island, as opposed + #to just testing if failed_intf is in island_intf_list, + #because failed_intf could be marked as MRT_INELIGIBLE. + if F in topo.island_node_list: + + + +Enyedi, et al. Standards Track [Page 86] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + alt.info = Select_Alternates(D, F, failed_intf) + else: + #The primary next hop is not in the MRT Island. + #Either red or blue will avoid the primary next hop, + #because the primary next hop is not even in the + #GADAG. + alt.info = 'USE_RED_OR_BLUE' + + if (alt.info == 'USE_RED_OR_BLUE'): + alt.red_or_blue = random.choice(['USE_RED','USE_BLUE']) + if (alt.info == 'USE_BLUE' + or alt.red_or_blue == 'USE_BLUE'): + Copy_List_Items(alt.nh_list, D.blue_next_hops) + alt.fec = 'BLUE' + alt.prot = 'NODE_PROTECTION' + if (alt.info == 'USE_RED' or alt.red_or_blue == 'USE_RED'): + Copy_List_Items(alt.nh_list, D.red_next_hops) + alt.fec = 'RED' + alt.prot = 'NODE_PROTECTION' + if (alt.info == 'PRIM_NH_IN_DIFFERENT_BLOCK'): + alt.fec = 'NO_ALTERNATE' + alt.prot = 'NO_PROTECTION' + if (alt.info == 'PRIM_NH_IS_D_OR_OP_FOR_D'): + if failed_intf.OUTGOING and failed_intf.INCOMING: + # cut-link: if there are parallel cut links, use + # the link(s) with lowest metric that are not + # primary intf or None + cand_alt_list = [None] + min_metric = 2147483647 + for intf in x.island_intf_list: + if ( intf is not failed_intf and + (intf.remote_node is + failed_intf.remote_node)): + if intf.metric < min_metric: + cand_alt_list = [intf] + min_metric = intf.metric + elif intf.metric == min_metric: + cand_alt_list.append(intf) + if cand_alt_list != [None]: + alt.fec = 'GREEN' + alt.prot = 'PARALLEL_CUTLINK' + else: + alt.fec = 'NO_ALTERNATE' + alt.prot = 'NO_PROTECTION' + Copy_List_Items(alt.nh_list, cand_alt_list) + + # Is_Remote_Node_In_NH_List() is used, as opposed + # to just checking if failed_intf is in D.red_next_hops, + + + +Enyedi, et al. Standards Track [Page 87] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + # because failed_intf could be marked as MRT_INELIGIBLE. + elif Is_Remote_Node_In_NH_List(F, D.red_next_hops): + Copy_List_Items(alt.nh_list, D.blue_next_hops) + alt.fec = 'BLUE' + alt.prot = 'LINK_PROTECTION' + elif Is_Remote_Node_In_NH_List(F, D.blue_next_hops): + Copy_List_Items(alt.nh_list, D.red_next_hops) + alt.fec = 'RED' + alt.prot = 'LINK_PROTECTION' + else: + alt.fec = random.choice(['RED','BLUE']) + alt.prot = 'LINK_PROTECTION' + + D.alt_list.append(alt) + +def Write_GADAG_To_File(topo, file_prefix): + gadag_edge_list = [] + for node in topo.node_list: + for intf in node.intf_list: + if intf.SIMULATION_OUTGOING: + local_node = "%04d" % (intf.local_node.node_id) + remote_node = "%04d" % (intf.remote_node.node_id) + intf_data = "%03d" % (intf.link_data) + edge_string=(local_node+','+remote_node+','+ + intf_data+'\n') + gadag_edge_list.append(edge_string) + gadag_edge_list.sort(); + filename = file_prefix + '_gadag.csv' + with open(filename, 'w') as gadag_file: + gadag_file.write('local_node,'\ + 'remote_node,local_intf_link_data\n') + for edge_string in gadag_edge_list: + gadag_file.write(edge_string); + +def Write_MRTs_For_All_Dests_To_File(topo, color, file_prefix): + edge_list = [] + for node in topo.island_node_list_for_test_gr: + if color == 'blue': + node_next_hops_dict = node.blue_next_hops_dict + elif color == 'red': + node_next_hops_dict = node.red_next_hops_dict + for dest_node_id in node_next_hops_dict: + for intf in node_next_hops_dict[dest_node_id]: + gadag_root = "%04d" % (topo.gadag_root.node_id) + dest_node = "%04d" % (dest_node_id) + local_node = "%04d" % (intf.local_node.node_id) + remote_node = "%04d" % (intf.remote_node.node_id) + intf_data = "%03d" % (intf.link_data) + + + +Enyedi, et al. Standards Track [Page 88] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + edge_string=(gadag_root+','+dest_node+','+local_node+ + ','+remote_node+','+intf_data+'\n') + edge_list.append(edge_string) + edge_list.sort() + filename = file_prefix + '_' + color + '_to_all.csv' + with open(filename, 'w') as mrt_file: + mrt_file.write('gadag_root,dest,'\ + 'local_node,remote_node,link_data\n') + for edge_string in edge_list: + mrt_file.write(edge_string); + +def Write_Both_MRTs_For_All_Dests_To_File(topo, file_prefix): + Write_MRTs_For_All_Dests_To_File(topo, 'blue', file_prefix) + Write_MRTs_For_All_Dests_To_File(topo, 'red', file_prefix) + +def Write_Alternates_For_All_Dests_To_File(topo, file_prefix): + edge_list = [] + for x in topo.island_node_list_for_test_gr: + for dest_node_id in x.alt_dict: + alt_list = x.alt_dict[dest_node_id] + for alt in alt_list: + for alt_intf in alt.nh_list: + gadag_root = "%04d" % (topo.gadag_root.node_id) + dest_node = "%04d" % (dest_node_id) + prim_local_node = \ + "%04d" % (alt.failed_intf.local_node.node_id) + prim_remote_node = \ + "%04d" % (alt.failed_intf.remote_node.node_id) + prim_intf_data = \ + "%03d" % (alt.failed_intf.link_data) + if alt_intf == None: + alt_local_node = "None" + alt_remote_node = "None" + alt_intf_data = "None" + else: + alt_local_node = \ + "%04d" % (alt_intf.local_node.node_id) + alt_remote_node = \ + "%04d" % (alt_intf.remote_node.node_id) + alt_intf_data = \ + "%03d" % (alt_intf.link_data) + edge_string = (gadag_root+','+dest_node+','+ + prim_local_node+','+prim_remote_node+','+ + prim_intf_data+','+alt_local_node+','+ + alt_remote_node+','+alt_intf_data+','+ + alt.fec +'\n') + edge_list.append(edge_string) + edge_list.sort() + + + +Enyedi, et al. Standards Track [Page 89] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + filename = file_prefix + '_alts_to_all.csv' + with open(filename, 'w') as alt_file: + alt_file.write('gadag_root,dest,'\ + 'prim_nh.local_node,prim_nh.remote_node,'\ + 'prim_nh.link_data,alt_nh.local_node,'\ + 'alt_nh.remote_node,alt_nh.link_data,'\ + 'alt_nh.fec\n') + for edge_string in edge_list: + alt_file.write(edge_string); + +def Raise_GADAG_Root_Selection_Priority(topo,node_id): + node = topo.node_dict[node_id] + node.GR_sel_priority = 255 + +def Lower_GADAG_Root_Selection_Priority(topo,node_id): + node = topo.node_dict[node_id] + node.GR_sel_priority = 128 + +def GADAG_Root_Compare(node_a, node_b): + if (node_a.GR_sel_priority > node_b.GR_sel_priority): + return 1 + elif (node_a.GR_sel_priority < node_b.GR_sel_priority): + return -1 + else: + if node_a.node_id > node_b.node_id: + return 1 + elif node_a.node_id < node_b.node_id: + return -1 + +def Set_GADAG_Root(topo,computing_router): + gadag_root_list = [] + for node in topo.island_node_list: + gadag_root_list.append(node) + gadag_root_list.sort(GADAG_Root_Compare) + topo.gadag_root = gadag_root_list.pop() + +def Add_Prefix_Advertisements_From_File(topo, filename): + prefix_filename = filename + '.prefix' + cols_list = [] + if not os.path.exists(prefix_filename): + return + with open(prefix_filename) as prefix_file: + for line in prefix_file: + line = line.rstrip('\r\n') + cols=line.split(',') + cols_list.append(cols) + prefix_id = int(cols[0]) + if prefix_id < 2000 or prefix_id >2999: + + + +Enyedi, et al. Standards Track [Page 90] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + print('skipping the following line of prefix file') + print('prefix id should be between 2000 and 2999') + print(line) + continue + prefix_node_id = int(cols[1]) + prefix_cost = int(cols[2]) + advertising_node = topo.node_dict[prefix_node_id] + advertising_node.prefix_cost_dict[prefix_id] = prefix_cost + +def Add_Prefixes_for_Non_Island_Nodes(topo): + for node in topo.node_list: + if node.IN_MRT_ISLAND: + continue + prefix_id = node.node_id + 1000 + node.prefix_cost_dict[prefix_id] = 0 + +def Add_Profile_IDs_from_File(topo, filename): + profile_filename = filename + '.profile' + for node in topo.node_list: + node.profile_id_list = [] + cols_list = [] + if os.path.exists(profile_filename): + with open(profile_filename) as profile_file: + for line in profile_file: + line = line.rstrip('\r\n') + cols=line.split(',') + cols_list.append(cols) + node_id = int(cols[0]) + profile_id = int(cols[1]) + this_node = topo.node_dict[node_id] + this_node.profile_id_list.append(profile_id) + else: + for node in topo.node_list: + node.profile_id_list = [0] + +def Island_Marking_SPF(topo,spf_root): + spf_root.isl_marking_spf_dict = {} + for y in topo.node_list: + y.spf_metric = 2147483647 # 2^31-1 as max metric + y.PATH_HITS_ISLAND = False + y.next_hops = [] + y.spf_visited = False + spf_root.spf_metric = 0 + spf_heap = [] + heapq.heappush(spf_heap, + (spf_root.spf_metric,spf_root.node_id,spf_root) ) + while spf_heap != []: + #extract third element of tuple popped from heap + + + +Enyedi, et al. Standards Track [Page 91] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + min_node = heapq.heappop(spf_heap)[2] + if min_node.spf_visited: + continue + min_node.spf_visited = True + spf_root.isl_marking_spf_dict[min_node.node_id] = \ + (min_node.spf_metric, min_node.PATH_HITS_ISLAND) + for intf in min_node.intf_list: + path_metric = min_node.spf_metric + intf.metric + if path_metric < intf.remote_node.spf_metric: + intf.remote_node.spf_metric = path_metric + if min_node is spf_root: + intf.remote_node.next_hops = [intf] + else: + Copy_List_Items(intf.remote_node.next_hops, + min_node.next_hops) + if (intf.remote_node.IN_MRT_ISLAND): + intf.remote_node.PATH_HITS_ISLAND = True + else: + intf.remote_node.PATH_HITS_ISLAND = \ + min_node.PATH_HITS_ISLAND + heapq.heappush(spf_heap, + ( intf.remote_node.spf_metric, + intf.remote_node.node_id, + intf.remote_node ) ) + elif path_metric == intf.remote_node.spf_metric: + if min_node is spf_root: + Add_Item_To_List_If_New( + intf.remote_node.next_hops,intf) + else: + for nh_intf in min_node.next_hops: + Add_Item_To_List_If_New( + intf.remote_node.next_hops,nh_intf) + if (intf.remote_node.IN_MRT_ISLAND): + intf.remote_node.PATH_HITS_ISLAND = True + else: + if (intf.remote_node.PATH_HITS_ISLAND + or min_node.PATH_HITS_ISLAND): + intf.remote_node.PATH_HITS_ISLAND = True + +def Create_Basic_Named_Proxy_Nodes(topo): + for node in topo.node_list: + for prefix in node.prefix_cost_dict: + prefix_cost = node.prefix_cost_dict[prefix] + if prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + P.node_prefix_cost_list.append((node,prefix_cost)) + else: + P = Named_Proxy_Node() + + + +Enyedi, et al. Standards Track [Page 92] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + topo.named_proxy_dict[prefix] = P + P.node_id = prefix + P.node_prefix_cost_list = [(node,prefix_cost)] + +def Compute_Loop_Free_Island_Neighbors_For_Each_Prefix(topo): + topo.island_nbr_set = set() + topo.island_border_set = set() + for node in topo.node_list: + if node.IN_MRT_ISLAND: + continue + for intf in node.intf_list: + if intf.remote_node.IN_MRT_ISLAND: + topo.island_nbr_set.add(node) + topo.island_border_set.add(intf.remote_node) + + for island_nbr in topo.island_nbr_set: + Island_Marking_SPF(topo,island_nbr) + + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + P.lfin_list = [] + for island_nbr in topo.island_nbr_set: + min_isl_nbr_to_pref_cost = 2147483647 + for (adv_node, prefix_cost) in P.node_prefix_cost_list: + (adv_node_cost, path_hits_island) = \ + island_nbr.isl_marking_spf_dict[adv_node.node_id] + isl_nbr_to_pref_cost = adv_node_cost + prefix_cost + if isl_nbr_to_pref_cost < min_isl_nbr_to_pref_cost: + min_isl_nbr_to_pref_cost = isl_nbr_to_pref_cost + min_path_hits_island = path_hits_island + elif isl_nbr_to_pref_cost == min_isl_nbr_to_pref_cost: + if min_path_hits_island or path_hits_island: + min_path_hits_island = True + if not min_path_hits_island: + P.lfin_list.append( (island_nbr, + min_isl_nbr_to_pref_cost) ) + + +def Compute_Island_Border_Router_LFIN_Pairs_For_Each_Prefix(topo): + for ibr in topo.island_border_set: + ibr.prefix_lfin_dict = {} + ibr.min_intf_metric_dict = {} + ibr.min_intf_list_dict = {} + ibr.min_intf_list_dict[None] = None + for intf in ibr.intf_list: + if not intf.remote_node in topo.island_nbr_set: + continue + if not intf.remote_node in ibr.min_intf_metric_dict: + + + +Enyedi, et al. Standards Track [Page 93] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + ibr.min_intf_metric_dict[intf.remote_node] = \ + intf.metric + ibr.min_intf_list_dict[intf.remote_node] = [intf] + else: + if (intf.metric + < ibr.min_intf_metric_dict[intf.remote_node]): + ibr.min_intf_metric_dict[intf.remote_node] = \ + intf.metric + ibr.min_intf_list_dict[intf.remote_node] = [intf] + elif (intf.metric + < ibr.min_intf_metric_dict[intf.remote_node]): + ibr.min_intf_list_dict[intf.remote_node].\ + append(intf) + + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + for ibr in topo.island_border_set: + min_ibr_lfin_pref_cost = 2147483647 + min_lfin = None + for (lfin, lfin_to_pref_cost) in P.lfin_list: + if not lfin in ibr.min_intf_metric_dict: + continue + ibr_lfin_pref_cost = \ + ibr.min_intf_metric_dict[lfin] + lfin_to_pref_cost + if ibr_lfin_pref_cost < min_ibr_lfin_pref_cost: + min_ibr_lfin_pref_cost = ibr_lfin_pref_cost + min_lfin = lfin + ibr.prefix_lfin_dict[prefix] = (min_lfin, + min_ibr_lfin_pref_cost, + ibr.min_intf_list_dict[min_lfin]) + +def Proxy_Node_Att_Router_Compare(pnar_a, pnar_b): + if pnar_a.named_proxy_cost < pnar_b.named_proxy_cost: + return -1 + if pnar_b.named_proxy_cost < pnar_a.named_proxy_cost: + return 1 + if pnar_a.node.node_id < pnar_b.node.node_id: + return -1 + if pnar_b.node.node_id < pnar_a.node.node_id: + return 1 + if pnar_a.min_lfin == None: + return -1 + if pnar_b.min_lfin == None: + return 1 + +def Choose_Proxy_Node_Attachment_Routers(topo): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + + + +Enyedi, et al. Standards Track [Page 94] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + pnar_candidate_list = [] + for (node, prefix_cost) in P.node_prefix_cost_list: + if not node.IN_MRT_ISLAND: + continue + pnar = Proxy_Node_Attachment_Router() + pnar.prefix = prefix + pnar.named_proxy_cost = prefix_cost + pnar.node = node + pnar_candidate_list.append(pnar) + for ibr in topo.island_border_set: + (min_lfin, prefix_cost, min_intf_list) = \ + ibr.prefix_lfin_dict[prefix] + if min_lfin == None: + continue + pnar = Proxy_Node_Attachment_Router() + pnar.named_proxy_cost = prefix_cost + pnar.node = ibr + pnar.min_lfin = min_lfin + pnar.nh_intf_list = min_intf_list + pnar_candidate_list.append(pnar) + pnar_candidate_list.sort(cmp=Proxy_Node_Att_Router_Compare) + #pop first element from list + first_pnar = pnar_candidate_list.pop(0) + second_pnar = None + for next_pnar in pnar_candidate_list: + if next_pnar.node is first_pnar.node: + continue + second_pnar = next_pnar + break + + P.pnar1 = first_pnar + P.pnar2 = second_pnar + +def Attach_Named_Proxy_Nodes(topo): + Compute_Loop_Free_Island_Neighbors_For_Each_Prefix(topo) + Compute_Island_Border_Router_LFIN_Pairs_For_Each_Prefix(topo) + Choose_Proxy_Node_Attachment_Routers(topo) + +def Select_Proxy_Node_NHs(P,S): + if P.pnar1.node.node_id < P.pnar2.node.node_id: + X = P.pnar1.node + Y = P.pnar2.node + else: + X = P.pnar2.node + Y = P.pnar1.node + P.pnar_X = X + P.pnar_Y = Y + A = X.order_proxy + + + +Enyedi, et al. Standards Track [Page 95] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + B = Y.order_proxy + if (A is S.localroot + and B is S.localroot): + #print("1.0") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if (A is S.localroot + and B is not S.localroot): + #print("2.0") + if B.LOWER: + #print("2.1") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if B.HIGHER: + #print("2.2") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + #print("2.3") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if (A is not S.localroot + and B is S.localroot): + #print("3.0") + if A.LOWER: + #print("3.1") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if A.HIGHER: + #print("3.2") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + #print("3.3") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if (A is not S.localroot + and B is not S.localroot): + #print("4.0") + if (S is A.localroot or S is B.localroot): + #print("4.05") + + + +Enyedi, et al. Standards Track [Page 96] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if A.topo_order < B.topo_order: + #print("4.05.1") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + #print("4.05.2") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if A.LOWER: + #print("4.1") + if B.HIGHER: + #print("4.1.1") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + if B.LOWER: + #print("4.1.2") + if A.topo_order < B.topo_order: + #print("4.1.2.1") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + #print("4.1.2.2") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + #print("4.1.3") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if A.HIGHER: + #print("4.2") + if B.HIGHER: + #print("4.2.1") + if A.topo_order < B.topo_order: + #print("4.2.1.1") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + #print("4.2.1.2") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + + + +Enyedi, et al. Standards Track [Page 97] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if B.LOWER: + #print("4.2.2") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + #print("4.2.3") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + #print("4.3") + if B.LOWER: + #print("4.3.1") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + if B.HIGHER: + #print("4.3.2") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + else: + #print("4.3.3") + if A.topo_order < B.topo_order: + #print("4.3.3.1") + Copy_List_Items(P.blue_next_hops, X.blue_next_hops) + Copy_List_Items(P.red_next_hops, Y.red_next_hops) + return + else: + #print("4.3.3.2") + Copy_List_Items(P.blue_next_hops, X.red_next_hops) + Copy_List_Items(P.red_next_hops, Y.blue_next_hops) + return + assert(False) + +def Compute_MRT_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,S): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + if P.pnar2 == None: + if S is P.pnar1.node: + # set the MRT next hops for the PNAR to + # reach the LFIN and change FEC to green + Copy_List_Items(P.blue_next_hops, + P.pnar1.nh_intf_list) + S.blue_to_green_nh_dict[P.node_id] = True + Copy_List_Items(P.red_next_hops, + P.pnar1.nh_intf_list) + + + +Enyedi, et al. Standards Track [Page 98] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + S.red_to_green_nh_dict[P.node_id] = True + else: + # inherit MRT NHs for P from pnar1 + Copy_List_Items(P.blue_next_hops, + P.pnar1.node.blue_next_hops) + Copy_List_Items(P.red_next_hops, + P.pnar1.node.red_next_hops) + else: + Select_Proxy_Node_NHs(P,S) + # set the MRT next hops for the PNAR to reach the LFIN + # and change FEC to green rely on the red or blue + # next hops being empty to figure out which one needs + # to point to the LFIN. + if S is P.pnar1.node: + this_pnar = P.pnar1 + elif S is P.pnar2.node: + this_pnar = P.pnar2 + else: + continue + if P.blue_next_hops == []: + Copy_List_Items(P.blue_next_hops, + this_pnar.nh_intf_list) + S.blue_to_green_nh_dict[P.node_id] = True + if P.red_next_hops == []: + Copy_List_Items(P.red_next_hops, + this_pnar.nh_intf_list) + S.red_to_green_nh_dict[P.node_id] = True + +def Select_Alternates_Proxy_Node(P,F,primary_intf): + S = primary_intf.local_node + X = P.pnar_X + Y = P.pnar_Y + A = X.order_proxy + B = Y.order_proxy + if F is A and F is B: + return 'PRIM_NH_IS_OP_FOR_BOTH_X_AND_Y' + if F is A: + return 'USE_RED' + if F is B: + return 'USE_BLUE' + + if not In_Common_Block(A, B): + if In_Common_Block(F, A): + return 'USE_RED' + elif In_Common_Block(F, B): + return 'USE_BLUE' + else: + return 'USE_RED_OR_BLUE' + + + +Enyedi, et al. Standards Track [Page 99] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if (not In_Common_Block(F, A) + and not In_Common_Block(F, A) ): + return 'USE_RED_OR_BLUE' + + alt_to_X = Select_Alternates(X, F, primary_intf) + alt_to_Y = Select_Alternates(Y, F, primary_intf) + + if (alt_to_X == 'USE_RED_OR_BLUE' + and alt_to_Y == 'USE_RED_OR_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED_OR_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED_OR_BLUE': + return 'USE_RED' + + if (A is S.localroot + and B is S.localroot): + #print("1.0") + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if (A is S.localroot + and B is not S.localroot): + #print("2.0") + if B.LOWER: + #print("2.1") + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if B.HIGHER: + #print("2.2") + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + else: + #print("2.3") + + + +Enyedi, et al. Standards Track [Page 100] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if (A is not S.localroot + and B is S.localroot): + #print("3.0") + if A.LOWER: + #print("3.1") + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if A.HIGHER: + #print("3.2") + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + #print("3.3") + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + if (A is not S.localroot + and B is not S.localroot): + #print("4.0") + if (S is A.localroot or S is B.localroot): + #print("4.05") + if A.topo_order < B.topo_order: + #print("4.05.1") + if (alt_to_X == 'USE_BLUE' and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + + + +Enyedi, et al. Standards Track [Page 101] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + #print("4.05.2") + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if A.LOWER: + #print("4.1") + if B.HIGHER: + #print("4.1.1") + if (alt_to_X == 'USE_RED' and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if B.LOWER: + #print("4.1.2") + if A.topo_order < B.topo_order: + #print("4.1.2.1") + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + #print("4.1.2.2") + if (alt_to_X == 'USE_RED' + and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + else: + #print("4.1.3") + if (F.LOWER and not F.HIGHER + + + +Enyedi, et al. Standards Track [Page 102] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + and F.topo_order > A.topo_order): + #print("4.1.3.1") + return 'USE_RED' + else: + #print("4.1.3.2") + return 'USE_BLUE' + if A.HIGHER: + #print("4.2") + if B.HIGHER: + #print("4.2.1") + if A.topo_order < B.topo_order: + #print("4.2.1.1") + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + #print("4.2.1.2") + if (alt_to_X == 'USE_RED' + and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + if B.LOWER: + #print("4.2.2") + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + #print("4.2.3") + if (F.HIGHER and not F.LOWER + and F.topo_order < A.topo_order): + return 'USE_RED' + else: + return 'USE_BLUE' + + + + +Enyedi, et al. Standards Track [Page 103] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + else: + #print("4.3") + if B.LOWER: + #print("4.3.1") + if (F.LOWER and not F.HIGHER + and F.topo_order > B.topo_order): + return 'USE_BLUE' + else: + return 'USE_RED' + if B.HIGHER: + #print("4.3.2") + if (F.HIGHER and not F.LOWER + and F.topo_order < B.topo_order): + return 'USE_BLUE' + else: + return 'USE_RED' + else: + #print("4.3.3") + if A.topo_order < B.topo_order: + #print("4.3.3.1") + if (alt_to_X == 'USE_BLUE' + and alt_to_Y == 'USE_RED'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_BLUE': + return 'USE_BLUE' + if alt_to_Y == 'USE_RED': + return 'USE_RED' + assert(False) + else: + #print("4.3.3.2") + if (alt_to_X == 'USE_RED' + and alt_to_Y == 'USE_BLUE'): + return 'USE_RED_OR_BLUE' + if alt_to_X == 'USE_RED': + return 'USE_BLUE' + if alt_to_Y == 'USE_BLUE': + return 'USE_RED' + assert(False) + assert(False) + +def Compute_Primary_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + min_total_pref_cost = 2147483647 + for (adv_node, prefix_cost) in P.node_prefix_cost_list: + total_pref_cost = (adv_node.primary_spf_metric + + prefix_cost) + if total_pref_cost < min_total_pref_cost: + + + +Enyedi, et al. Standards Track [Page 104] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + min_total_pref_cost = total_pref_cost + Copy_List_Items(P.primary_next_hops, + adv_node.primary_next_hops) + elif total_pref_cost == min_total_pref_cost: + for nh_intf in adv_node.primary_next_hops: + Add_Item_To_List_If_New(P.primary_next_hops, + nh_intf) + +def Select_Alts_For_One_Src_To_Named_Proxy_Nodes(topo,src): + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + P.alt_list = [] + for failed_intf in P.primary_next_hops: + alt = Alternate() + alt.failed_intf = failed_intf + if failed_intf not in src.island_intf_list: + alt.info = 'PRIM_NH_FOR_PROXY_NODE_NOT_IN_ISLAND' + elif P.pnar1 is None: + alt.info = 'NO_PNARs_EXIST_FOR_THIS_PREFIX' + elif src is P.pnar1.node: + alt.info = 'SRC_IS_PNAR' + elif P.pnar2 is not None and src is P.pnar2.node: + alt.info = 'SRC_IS_PNAR' + elif P.pnar2 is None: + #inherit alternates from the only pnar. + alt.info = Select_Alternates(P.pnar1.node, + failed_intf.remote_node, failed_intf) + elif failed_intf in src.island_intf_list: + alt.info = Select_Alternates_Proxy_Node(P, + failed_intf.remote_node, failed_intf) + + if alt.info == 'USE_RED_OR_BLUE': + alt.red_or_blue = \ + random.choice(['USE_RED','USE_BLUE']) + if (alt.info == 'USE_BLUE' + or alt.red_or_blue == 'USE_BLUE'): + Copy_List_Items(alt.nh_list, P.blue_next_hops) + alt.fec = 'BLUE' + alt.prot = 'NODE_PROTECTION' + elif (alt.info == 'USE_RED' + or alt.red_or_blue == 'USE_RED'): + Copy_List_Items(alt.nh_list, P.red_next_hops) + alt.fec = 'RED' + alt.prot = 'NODE_PROTECTION' + elif (alt.info == 'PRIM_NH_IS_D_OR_OP_FOR_D' + or alt.info == 'PRIM_NH_IS_OP_FOR_BOTH_X_AND_Y'): + if failed_intf.OUTGOING and failed_intf.INCOMING: + # cut-link: if there are parallel cut links, use + + + +Enyedi, et al. Standards Track [Page 105] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + # the link(s) with lowest metric that are not + # primary intf or None + cand_alt_list = [None] + min_metric = 2147483647 + for intf in src.island_intf_list: + if ( intf is not failed_intf and + (intf.remote_node is + failed_intf.remote_node)): + if intf.metric < min_metric: + cand_alt_list = [intf] + min_metric = intf.metric + elif intf.metric == min_metric: + cand_alt_list.append(intf) + if cand_alt_list != [None]: + alt.fec = 'GREEN' + alt.prot = 'PARALLEL_CUTLINK' + else: + alt.fec = 'NO_ALTERNATE' + alt.prot = 'NO_PROTECTION' + Copy_List_Items(alt.nh_list, cand_alt_list) + else: + # set Z as the node to inherit blue next hops from + if alt.info == 'PRIM_NH_IS_D_OR_OP_FOR_D': + Z = P.pnar1.node + else: + Z = P + if failed_intf in Z.red_next_hops: + Copy_List_Items(alt.nh_list, Z.blue_next_hops) + alt.fec = 'BLUE' + alt.prot = 'LINK_PROTECTION' + else: + assert(failed_intf in Z.blue_next_hops) + Copy_List_Items(alt.nh_list, Z.red_next_hops) + alt.fec = 'RED' + alt.prot = 'LINK_PROTECTION' + + elif alt.info == 'PRIM_NH_FOR_PROXY_NODE_NOT_IN_ISLAND': + if (P.pnar2 == None and src is P.pnar1.node): + #MRT Island is singly connected to non-island dest + alt.fec = 'NO_ALTERNATE' + alt.prot = 'NO_PROTECTION' + elif P.node_id in src.blue_to_green_nh_dict: + # blue to P goes to failed LFIN so use red to P + Copy_List_Items(alt.nh_list, P.red_next_hops) + alt.fec = 'RED' + alt.prot = 'LINK_PROTECTION' + elif P.node_id in src.red_to_green_nh_dict: + # red to P goes to failed LFIN so use blue to P + + + +Enyedi, et al. Standards Track [Page 106] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Copy_List_Items(alt.nh_list, P.blue_next_hops) + alt.fec = 'BLUE' + alt.prot = 'LINK_PROTECTION' + else: + Copy_List_Items(alt.nh_list, P.blue_next_hops) + alt.fec = 'BLUE' + alt.prot = 'LINK_PROTECTION' + elif alt.info == 'TEMP_NO_ALTERNATE': + alt.fec = 'NO_ALTERNATE' + alt.prot = 'NO_PROTECTION' + + P.alt_list.append(alt) + +def Run_Basic_MRT_for_One_Source(topo, src): + MRT_Island_Identification(topo, src, 0, 0) + Set_Island_Intf_and_Node_Lists(topo) + Set_GADAG_Root(topo,src) + Sort_Interfaces(topo) + Run_Lowpoint(topo) + Assign_Remaining_Lowpoint_Parents(topo) + Construct_GADAG_via_Lowpoint(topo) + Run_Assign_Block_ID(topo) + Add_Undirected_Links(topo) + Compute_MRT_NH_For_One_Src_To_Island_Dests(topo,src) + Store_MRT_Nexthops_For_One_Src_To_Island_Dests(topo,src) + Select_Alts_For_One_Src_To_Island_Dests(topo,src) + Store_Primary_and_Alts_For_One_Src_To_Island_Dests(topo,src) + +def Store_GADAG_and_Named_Proxies_Once(topo): + for node in topo.node_list: + for intf in node.intf_list: + if intf.OUTGOING: + intf.SIMULATION_OUTGOING = True + else: + intf.SIMULATION_OUTGOING = False + for prefix in topo.named_proxy_dict: + P = topo.named_proxy_dict[prefix] + topo.stored_named_proxy_dict[prefix] = P + +def Run_Basic_MRT_for_All_Sources(topo): + for src in topo.node_list: + Reset_Computed_Node_and_Intf_Values(topo) + Run_Basic_MRT_for_One_Source(topo,src) + if src is topo.gadag_root: + Store_GADAG_and_Named_Proxies_Once(topo) + + + + + + +Enyedi, et al. Standards Track [Page 107] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +def Run_MRT_for_One_Source(topo, src): + MRT_Island_Identification(topo, src, 0, 0) + Set_Island_Intf_and_Node_Lists(topo) + Set_GADAG_Root(topo,src) + Sort_Interfaces(topo) + Run_Lowpoint(topo) + Assign_Remaining_Lowpoint_Parents(topo) + Construct_GADAG_via_Lowpoint(topo) + Run_Assign_Block_ID(topo) + Add_Undirected_Links(topo) + Compute_MRT_NH_For_One_Src_To_Island_Dests(topo,src) + Store_MRT_Nexthops_For_One_Src_To_Island_Dests(topo,src) + Select_Alts_For_One_Src_To_Island_Dests(topo,src) + Store_Primary_and_Alts_For_One_Src_To_Island_Dests(topo,src) + Create_Basic_Named_Proxy_Nodes(topo) + Attach_Named_Proxy_Nodes(topo) + Compute_MRT_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src) + Store_MRT_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src) + Compute_Primary_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src) + Store_Primary_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src) + Select_Alts_For_One_Src_To_Named_Proxy_Nodes(topo,src) + Store_Alts_For_One_Src_To_Named_Proxy_Nodes(topo,src) + +def Run_Prim_SPF_for_One_Source(topo,src): + Normal_SPF(topo, src) + Store_Primary_NHs_For_One_Source_To_Nodes(topo,src) + Create_Basic_Named_Proxy_Nodes(topo) + Compute_Primary_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src) + Store_Primary_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,src) + +def Run_MRT_for_All_Sources(topo): + for src in topo.node_list: + Reset_Computed_Node_and_Intf_Values(topo) + if src in topo.island_node_list_for_test_gr: + # src runs MRT if it is in same MRT island as test_gr + Run_MRT_for_One_Source(topo,src) + if src is topo.gadag_root: + Store_GADAG_and_Named_Proxies_Once(topo) + else: + # src still runs SPF if not in MRT island + Run_Prim_SPF_for_One_Source(topo,src) + +def Write_Output_To_Files(topo,file_prefix): + Write_GADAG_To_File(topo,file_prefix) + Write_Both_MRTs_For_All_Dests_To_File(topo,file_prefix) + Write_Alternates_For_All_Dests_To_File(topo,file_prefix) + + + + + +Enyedi, et al. Standards Track [Page 108] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +def Create_Basic_Topology_Input_File(filename): + data = [[01,02,10],[02,03,10],[03,04,11],[04,05,10,20],[05,06,10], + [06,07,10],[06,07,10],[06,07,15],[07,01,10],[07,51,10], + [51,52,10],[52,53,10],[53,03,10],[01,55,10],[55,06,10], + [04,12,10],[12,13,10],[13,14,10],[14,15,10],[15,16,10], + [16,17,10],[17,04,10],[05,76,10],[76,77,10],[77,78,10], + [78,79,10],[79,77,10]] + with open(filename + '.csv', 'w') as topo_file: + for item in data: + if len(item) > 3: + line = (str(item[0])+','+str(item[1])+','+ + str(item[2])+','+str(item[3])+'\n') + else: + line = (str(item[0])+','+str(item[1])+','+ + str(item[2])+'\n') + topo_file.write(line) + +def Create_Complex_Topology_Input_File(filename): + data = [[01,02,10],[02,03,10],[03,04,11],[04,05,10,20],[05,06,10], + [06,07,10],[06,07,10],[06,07,15],[07,01,10],[07,51,10], + [51,52,10],[52,53,10],[53,03,10],[01,55,10],[55,06,10], + [04,12,10],[12,13,10],[13,14,10],[14,15,10],[15,16,10], + [16,17,10],[17,04,10],[05,76,10],[76,77,10],[77,78,10], + [78,79,10],[79,77,10]] + with open(filename + '.csv', 'w') as topo_file: + for item in data: + if len(item) > 3: + line = (str(item[0])+','+str(item[1])+','+ + str(item[2])+','+str(item[3])+'\n') + else: + line = (str(item[0])+','+str(item[1])+','+ + str(item[2])+'\n') + topo_file.write(line) + + data = [[01,0],[02,0],[03,0],[04,0],[05,0], + [06,0],[07,0], + [51,0],[55,0], + [12,0],[13,0],[14,0],[15,0], + [16,0],[17,0],[76,0],[77,0], + [78,0],[79,0]] + with open(filename + '.profile', 'w') as topo_file: + for item in data: + line = (str(item[0])+','+str(item[1])+'\n') + topo_file.write(line) + + data = [[2001,05,100],[2001,07,120],[2001,03,130], + [2002,13,100],[2002,15,110], + [2003,52,100],[2003,78,100]] + + + +Enyedi, et al. Standards Track [Page 109] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + with open(filename + '.prefix', 'w') as topo_file: + for item in data: + line = (str(item[0])+','+str(item[1])+','+ + str(item[2])+'\n') + topo_file.write(line) + +def Generate_Basic_Topology_and_Run_MRT(): + this_gadag_root = 3 + Create_Basic_Topology_Input_File('basic_topo_input') + topo = Create_Topology_From_File('basic_topo_input') + res_file_base = 'basic_topo' + Compute_Island_Node_List_For_Test_GR(topo, this_gadag_root) + Raise_GADAG_Root_Selection_Priority(topo,this_gadag_root) + Run_Basic_MRT_for_All_Sources(topo) + Write_Output_To_Files(topo, res_file_base) + +def Generate_Complex_Topology_and_Run_MRT(): + this_gadag_root = 3 + Create_Complex_Topology_Input_File('complex_topo_input') + topo = Create_Topology_From_File('complex_topo_input') + Add_Profile_IDs_from_File(topo,'complex_topo_input') + Add_Prefix_Advertisements_From_File(topo,'complex_topo_input') + Compute_Island_Node_List_For_Test_GR(topo, this_gadag_root) + Add_Prefixes_for_Non_Island_Nodes(topo) + res_file_base = 'complex_topo' + Raise_GADAG_Root_Selection_Priority(topo,this_gadag_root) + Run_MRT_for_All_Sources(topo) + Write_Output_To_Files(topo, res_file_base) + +Generate_Basic_Topology_and_Run_MRT() + +Generate_Complex_Topology_and_Run_MRT() + +<CODE ENDS> + +Appendix B. Constructing a GADAG Using SPFs + + The basic idea in this method for constructing a GADAG is to use + slightly modified SPF computations to find ears. In every block, an + SPF computation is first done to find a cycle from the local root and + then SPF computations in that block find ears until there are no more + interfaces to be explored. The used result from the SPF computation + is the path of interfaces indicated by following the previous hops + from the minimized IN_GADAG node back to the SPF root. + + To do this, first all cut-vertices must be identified and localroots + assigned as specified in Figure 12. + + + + +Enyedi, et al. Standards Track [Page 110] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + The slight modifications to the SPF are as follows. The root of the + block is referred to as the block-root; it is either the GADAG root + or a cut-vertex. + + a. The SPF is rooted at a neighbor x of an IN_GADAG node y. All + links between y and x are marked as TEMP_UNUSABLE. They should + not be used during the SPF computation. + + b. If y is not the block-root, then it is marked TEMP_UNUSABLE. It + should not be used during the SPF computation. This prevents + ears from starting and ending at the same node and avoids cycles; + the exception is because cycles to/from the block-root are + acceptable and expected. + + c. Do not explore links to nodes whose localroot is not the block- + root. This keeps the SPF confined to the particular block. + + d. Terminate when the first IN_GADAG node z is minimized. + + e. Respect the existing directions (e.g., INCOMING, OUTGOING, + UNDIRECTED) already specified for each interface. + + + Mod_SPF(spf_root, block_root) + Initialize spf_heap to empty + Initialize nodes' spf_metric to infinity + spf_root.spf_metric = 0 + insert(spf_heap, spf_root) + found_in_gadag = false + while (spf_heap is not empty) and (found_in_gadag is false) + min_node = remove_lowest(spf_heap) + if min_node.IN_GADAG + found_in_gadag = true + else + foreach interface intf of min_node + if ((intf.OUTGOING or intf.UNDIRECTED) and + ((intf.remote_node.localroot is block_root) or + (intf.remote_node is block_root)) and + (intf.remote_node is not TEMP_UNUSABLE) and + (intf is not TEMP_UNUSABLE)) + path_metric = min_node.spf_metric + intf.metric + if path_metric < intf.remote_node.spf_metric + intf.remote_node.spf_metric = path_metric + intf.remote_node.spf_prev_intf = intf + insert_or_update(spf_heap, intf.remote_node) + return min_node + + + + + +Enyedi, et al. Standards Track [Page 111] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + SPF_for_Ear(cand_intf.local_node,cand_intf.remote_node, block_root, + method) + Mark all interfaces between cand_intf.remote_node + and cand_intf.local_node as TEMP_UNUSABLE + if cand_intf.local_node is not block_root + Mark cand_intf.local_node as TEMP_UNUSABLE + Initialize ear_list to empty + end_ear = Mod_SPF(spf_root, block_root) + y = end_ear.spf_prev_hop + while y.local_node is not spf_root + add_to_list_start(ear_list, y) + y.local_node.IN_GADAG = true + y = y.local_node.spf_prev_intf + if(method is not hybrid) + Set_Ear_Direction(ear_list, cand_intf.local_node, + end_ear,block_root) + Clear TEMP_UNUSABLE from all interfaces between + cand_intf.remote_node and cand_intf.local_node + Clear TEMP_UNUSABLE from cand_intf.local_node + return end_ear + + + Figure 31: Modified SPF for GADAG Construction + + Assume that an ear is found by going from y to x and then running an + SPF that terminates by minimizing z (e.g., y<->x...q<->z). Now it is + necessary to determine the direction of the ear; if y<<z, then the + path should be y->x...q->z; but if y>>z, then the path should be + y<-x...q<-z. In Section 5.5, the same problem was handled by finding + all ears that started at a node before looking at ears starting at + nodes higher in the partial order. In this GADAG construction + method, using that approach could mean that new ears aren't added in + order of their total cost since all ears connected to a node would + need to be found before additional nodes could be found. + + The alternative is to track the order relationship of each node with + respect to every other node. This can be accomplished by maintaining + two sets of nodes at each node. The first set, Higher_Nodes, + contains all nodes that are known to be ordered above the node. The + second set, Lower_Nodes, contains all nodes that are known to be + ordered below the node. This is the approach used in this GADAG + construction method. + + + + + + + + + +Enyedi, et al. Standards Track [Page 112] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Set_Ear_Direction(ear_list, end_a, end_b, block_root) + // Default of A_TO_B for the following cases: + // (a) end_a and end_b are the same (root) + // or (b) end_a is in end_b's Lower Nodes + // or (c) end_a and end_b were unordered with respect to each + // other + direction = A_TO_B + if (end_b is block_root) and (end_a is not end_b) + direction = B_TO_A + else if end_a is in end_b.Higher_Nodes + direction = B_TO_A + if direction is B_TO_A + foreach interface i in ear_list + i.UNDIRECTED = false + i.INCOMING = true + i.remote_intf.UNDIRECTED = false + i.remote_intf.OUTGOING = true + else + foreach interface i in ear_list + i.UNDIRECTED = false + i.OUTGOING = true + i.remote_intf.UNDIRECTED = false + i.remote_intf.INCOMING = true + if end_a is end_b + return + // Next, update all nodes' Lower_Nodes and Higher_Nodes + if (end_a is in end_b.Higher_Nodes) + foreach node x where x.localroot is block_root + if end_a is in x.Lower_Nodes + foreach interface i in ear_list + add i.remote_node to x.Lower_Nodes + if end_b is in x.Higher_Nodes + foreach interface i in ear_list + add i.local_node to x.Higher_Nodes + else + foreach node x where x.localroot is block_root + if end_b is in x.Lower_Nodes + foreach interface i in ear_list + add i.local_node to x.Lower_Nodes + if end_a is in x.Higher_Nodes + foreach interface i in ear_list + add i.remote_node to x.Higher_Nodes + + Figure 32: Algorithm to Assign Links of an Ear Direction + + A goal of this GADAG construction method is to find the shortest + cycles and ears. An ear is started by going to a neighbor x of an + IN_GADAG node y. The path from x to an IN_GADAG node is minimal, + + + +Enyedi, et al. Standards Track [Page 113] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + since it is computed via SPF. Since a shortest path is made of + shortest paths, to find the shortest ears requires reaching from the + set of IN_GADAG nodes to the closest node that isn't IN_GADAG. + Therefore, an ordered tree is maintained of interfaces that could be + explored from the IN_GADAG nodes. The interfaces are ordered by + their characteristics of metric, local loopback address, remote + loopback address, and ifindex, based on the Interface_Compare + function defined in Figure 14. + + This GADAG construction method ignores interfaces picked from the + ordered list that belong to the block root if the block in which the + interface is present already has an ear that has been computed. This + is necessary since we allow at most one incoming interface to a block + root in each block. This requirement stems from the way next hops + are computed as was seen in Section 5.7. After any ear gets + computed, we traverse the newly added nodes to the GADAG and insert + interfaces whose far end is not yet on the GADAG to the ordered tree + for later processing. + + Finally, cut-links are a special case because there is no point in + doing an SPF on a block of two nodes. The algorithm identifies cut- + links simply as links where both ends of the link are cut-vertices. + Cut-links can simply be added to the GADAG with both OUTGOING and + INCOMING specified on their interfaces. + + add_eligible_interfaces_of_node(ordered_intfs_tree,node) + for each interface of node + if intf.remote_node.IN_GADAG is false + insert(intf,ordered_intfs_tree) + + check_if_block_has_ear(x,block_id) + block_has_ear = false + for all interfaces of x + if ( (intf.remote_node.block_id == block_id) && + intf.remote_node.IN_GADAG ) + block_has_ear = true + return block_has_ear + + Construct_GADAG_via_SPF(topology, root) + Compute_Localroot (root,root) + Assign_Block_ID(root,0) + root.IN_GADAG = true + add_eligible_interfaces_of_node(ordered_intfs_tree,root) + while ordered_intfs_tree is not empty + cand_intf = remove_lowest(ordered_intfs_tree) + if cand_intf.remote_node.IN_GADAG is false + if L(cand_intf.remote_node) == D(cand_intf.remote_node) + // Special case for cut-links + + + +Enyedi, et al. Standards Track [Page 114] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + cand_intf.UNDIRECTED = false + cand_intf.remote_intf.UNDIRECTED = false + cand_intf.OUTGOING = true + cand_intf.INCOMING = true + cand_intf.remote_intf.OUTGOING = true + cand_intf.remote_intf.INCOMING = true + cand_intf.remote_node.IN_GADAG = true + add_eligible_interfaces_of_node( + ordered_intfs_tree,cand_intf.remote_node) + else + if (cand_intf.remote_node.local_root == + cand_intf.local_node) && + check_if_block_has_ear(cand_intf.local_node, + cand_intf.remote_node.block_id)) + /* Skip the interface since the block root + already has an incoming interface in the + block */ + else + ear_end = SPF_for_Ear(cand_intf.local_node, + cand_intf.remote_node, + cand_intf.remote_node.localroot, + SPF method) + y = ear_end.spf_prev_hop + while y.local_node is not cand_intf.local_node + add_eligible_interfaces_of_node( + ordered_intfs_tree, y.local_node) + y = y.local_node.spf_prev_intf + + + Figure 33: SPF-Based Method for GADAG Construction + +Appendix C. Constructing a GADAG Using a Hybrid Method + + The idea of this method is to combine the salient features of the + lowpoint inheritance and SPF methods. To this end, we process nodes + as they get added to the GADAG just like in the lowpoint inheritance + by maintaining a stack of nodes. This ensures that we do not need to + maintain lower and higher sets at each node to ascertain ear + directions since the ears will always be directed from the node being + processed towards the end of the ear. To compute the ear however, we + resort to an SPF to have the possibility of better ears (path + lengths) thus giving more flexibility than the restricted use of + lowpoint/dfs parents. + + Regarding ears involving a block root, unlike the SPF method, which + ignored interfaces of the block root after the first ear, in the + hybrid method we would have to process all interfaces of the block + root before moving on to other nodes in the block since the direction + + + +Enyedi, et al. Standards Track [Page 115] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + of an ear is predetermined. Thus, whenever the block already has an + ear computed, and we are processing an interface of the block root, + we mark the block root as unusable before the SPF run that computes + the ear. This ensures that the SPF terminates at some node other + than the block-root. This in turn guarantees that the block-root has + only one incoming interface in each block, which is necessary for + correctly computing the next hops on the GADAG. + + As in the SPF GADAG, bridge ears are handled as a special case. + + The entire algorithm is shown below in Figure 34. + + find_spf_stack_ear(stack, x, y, xy_intf, block_root) + if L(y) == D(y) + // Special case for cut-links + xy_intf.UNDIRECTED = false + xy_intf.remote_intf.UNDIRECTED = false + xy_intf.OUTGOING = true + xy_intf.INCOMING = true + xy_intf.remote_intf.OUTGOING = true + xy_intf.remote_intf.INCOMING = true + xy_intf.remote_node.IN_GADAG = true + push y onto stack + return + else + if (y.local_root == x) && + check_if_block_has_ear(x,y.block_id) + //Avoid the block root during the SPF + Mark x as TEMP_UNUSABLE + end_ear = SPF_for_Ear(x,y,block_root,hybrid) + If x was set as TEMP_UNUSABLE, clear it + cur = end_ear + while (cur != y) + intf = cur.spf_prev_hop + prev = intf.local_node + intf.UNDIRECTED = false + intf.remote_intf.UNDIRECTED = false + intf.OUTGOING = true + intf.remote_intf.INCOMING = true + push prev onto stack + cur = prev + xy_intf.UNDIRECTED = false + xy_intf.remote_intf.UNDIRECTED = false + xy_intf.OUTGOING = true + xy_intf.remote_intf.INCOMING = true + return + + + + + +Enyedi, et al. Standards Track [Page 116] + +RFC 7811 MRT-FRR Algorithm June 2016 + + + Construct_GADAG_via_hybrid(topology,root) + Compute_Localroot (root,root) + Assign_Block_ID(root,0) + root.IN_GADAG = true + Initialize Stack to empty + push root onto Stack + while (Stack is not empty) + x = pop(Stack) + for each interface intf of x + y = intf.remote_node + if y.IN_GADAG is false + find_spf_stack_ear(stack, x, y, intf, y.block_root) + + Figure 34: Hybrid GADAG Construction Method + +Acknowledgements + + The authors would like to thank Shraddha Hegde, Eric Wu, Janos + Farkas, Stewart Bryant, Alvaro Retana, and Deccan (Shaofu Peng) for + their suggestions and review. We would also like to thank Anil Kumar + SN for his assistance in clarifying the algorithm description and + pseudocode. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Enyedi, et al. Standards Track [Page 117] + +RFC 7811 MRT-FRR Algorithm June 2016 + + +Authors' Addresses + + Gabor Sandor Enyedi + Ericsson + Konyves Kalman krt 11 + Budapest 1097 + Hungary + + Email: Gabor.Sandor.Enyedi@ericsson.com + + + Andras Csaszar + Ericsson + Konyves Kalman krt 11 + Budapest 1097 + Hungary + + Email: Andras.Csaszar@ericsson.com + + + Alia Atlas + Juniper Networks + 10 Technology Park Drive + Westford, MA 01886 + United States + + Email: akatlas@juniper.net + + + Chris Bowers + Juniper Networks + 1194 N. Mathilda Ave. + Sunnyvale, CA 94089 + United States + + Email: cbowers@juniper.net + + + Abishek Gopalan + University of Arizona + 1230 E Speedway Blvd. + Tucson, AZ 85721 + United States + + Email: abishek@ece.arizona.edu + + + + + + +Enyedi, et al. Standards Track [Page 118] + |