# An Algorithm for Computing IP/LDP Fast Reroute Using Maximally Redundant Trees (MRT-FRR)

Pages: 118
Proposed Standard

```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
```
```   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
```
```              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.
```
```   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.
```
```+------+------------+------+------------------------------+------------+
| 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|            |
```
```+------+------------+------+-----------------+------------+------------+
| 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|            |
```
```+------+------------+------+-----------------+------------+------------+
| 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. |      |                 |            |            |
```
```|      |            +------+-----------------+------------+------------+
|      |            | 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
```
```   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

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.
```
```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.
```
```    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
else
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
```
```   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().
```
``` 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
```
```         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
```
```             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
```
```                 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,
```
```   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.
```
```   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.
```
```  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
```
```          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)
```
```          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'
```
```                          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':
```
```                          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)
```
```                  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.
```
```   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
```
```   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.

```