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
        
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)

一种利用最大冗余树计算IP/LDP快速重路由的算法(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.

本文件支持“使用最大冗余树的IP/LDP快速重路由架构(MRT-FRR)”(RFC 7812)中提出的解决方案通过定义默认MRT配置文件中使用的相关MRT低点算法,计算必要的最大冗余树及其相关的下一跳,以及为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.

本文件是互联网工程任务组(IETF)的产品。它代表了IETF社区的共识。它已经接受了公众审查,并已被互联网工程指导小组(IESG)批准出版。有关互联网标准的更多信息,请参见RFC 7841第2节。

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.

有关本文件当前状态、任何勘误表以及如何提供反馈的信息,请访问http://www.rfc-editor.org/info/rfc7811.

Copyright Notice

版权公告

Copyright (c) 2016 IETF Trust and the persons identified as the document authors. All rights reserved.

版权所有(c)2016 IETF信托基金和确定为文件作者的人员。版权所有。

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.

本文件受BCP 78和IETF信托有关IETF文件的法律规定的约束(http://trustee.ietf.org/license-info)自本文件出版之日起生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文件中提取的代码组件必须包括信托法律条款第4.e节中所述的简化BSD许可证文本,并提供简化BSD许可证中所述的无担保。

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
        
   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
        
   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
        
   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
1. 介绍

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.

MRT快速重路由要求数据包不仅可以在最短路径树上转发,还可以在两个最大冗余树(MRT)上转发,即MRT蓝色和MRT红色。遇到本地故障的路由器还必须预先确定要使用的备用路由器。本文件定义了如何计算MRT-FRR中使用的这三件事,并描述了算法设计决策和基本原理。该算法基于[MRTLinear]中提出的算法,并在[EnyediThesis]中进行了扩展。当实施默认MRT配置文件时,实施MRT低点算法是必需的。

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.

本文件中定义的MRT低点算法,当用于[RFC7812]中所述的MRT快速重路由时,可保证在网络为2-connected时,单次故障的100%恢复。这种保证的覆盖率不取决于链路指标,运营商可能会使用链路指标来对IP网络进行流量工程。因此,链路度量和一般网络拓扑在很大程度上与保证覆盖解耦。

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.

正如逐跳路由的数据包要求每个路由器计算一致的最短路径树,每个路由器必须以一致的方式计算MRT蓝色下一跳和MRT红色下一跳。本文件定义了MRT低点算法,该算法将用作MRT-FRR默认MRT配置文件中的标准。

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.

路由器的转发信息库(FIB)将继续包含转发流量的当前最短路径树的主要下一跳。此外,路由器的FIB将包含MRT蓝色的主下一跳,用于在MRT蓝色上转发接收的流量,以及MRT红色的主下一跳,用于在MRT红色上转发接收的流量。

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.

本地修复点(PLR)选择的下一个备选跳数不需要一致,但必须防止循环。为了减少拥塞,可以选择多个备用下一跳;在地铁候补的情况下,每一个候补的下一跳都是相同的成本路径。

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.

本文件定义了一种算法,用于选择适当的MRT备选方案以供考虑。其他备选方案,例如作为下游路径的无回路备选方案(LFA),在可用时可能是首选方案。参见[RFC7812]的“操作注意事项”一节,了解关于将MRT替代品与其他FRR技术生产的MRT替代品相结合的更详细讨论。

   [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]<--|
        
   [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

(a) (b)(c)两连通图MRT蓝色朝向R红色朝向R

Figure 1

图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.

MRT Lowpoint算法可以处理整个网络图不是2-连通的任意网络拓扑,如图2所示,以及网络图是2-连通的更简单情况(图1)。每个MRT都是一个生成树。这对MRT提供从每个节点X到MRT根的两条路径。这些路径共享最小数量的节点和最小数量的链接。每个这样的共享节点都是一个切割顶点。任何共享链接都是剪切链接。

                        [E]---[D]---|     |---[J]
                         |     |    |     |    |
                         |     |    |     |    |
                        [R]   [F]  [C]---[G]   |
                         |     |    |     |    |
                         |     |    |     |    |
                        [A]---[B]---|     |---[H]
        
                        [E]---[D]---|     |---[J]
                         |     |    |     |    |
                         |     |    |     |    |
                        [R]   [F]  [C]---[G]   |
                         |     |    |     |    |
                         |     |    |     |    |
                        [A]---[B]---|     |---[H]
        

(a) a graph that is not 2-connected

(a) 非二连通图

         [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]
        
         [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

(b) 地铁蓝色向右转(c)地铁红色向右转

Figure 2: A Network That Is Not 2-Connected

图2:非双向连接的网络

2. Requirements Language
2. 需求语言

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].

本文件中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“应”、“不应”、“建议”、“可”和“可选”应按照[RFC2119]中所述进行解释。

3. Terminology and Definitions
3. 术语和定义

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.

有关本文件相关术语的完整列表,请参见[RFC7812]的术语部分。以下列表不重复该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.

后缘:在通过深度优先搜索计算的生成树上下文中,后缘是连接节点x的后代和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.

部分ADAG:几乎有向无环图(ADAG)的子集,尚未包含块中的所有节点。在MRT Lowpoint算法期间创建一个部分ADAG,然后进行扩展,直到包含块中的所有节点,并成为ADAG。

DFS: Depth-First Search

深度优先搜索

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祖先:如果n位于从DFS根到x的DFS树路径上,则节点n是x的DFS祖先。

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.

DFS子体:如果x位于从DFS根到n的DFS树路径上,则节点n是x的DFS子体。

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.

ear:沿着尚未包含在通用ADAG(GADAG)中的节点的路径,从已经包含在GADAG中的节点开始,到已经包含在GADAG中的节点结束。如果是切割顶点,则起始节点和结束节点可能是同一节点。

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.

十> >Y或Y<<X:表示X和Y之间的关系,如在GADAG中发现的部分顺序。十> >Y表示X在偏序中高于Y。Y<<X表示Y在偏序中低于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.

十> Y或Y<X:表示X和Y之间的关系,如通过拓扑排序。十> Y表示X在总阶数上高于Y。Y<X表示Y在总阶数上低于X。

X ?? Y: Indicates that X is unordered with respect to Y in the partial order.

X??Y:表示X相对于Y的偏序是无序的。

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.

无方向:在GADAG中,每个链接都标记为传出、传入或两者。在确定链接的方向性之前,链接将标记为无方向,以指示其方向尚未确定。

OUTGOING: A link marked as OUTGOING has direction in the GADAG from the interface's router to the remote end.

传出:标记为传出的链路在GADAG中具有从接口路由器到远程端的方向。

INCOMING: A link marked as INCOMING has direction in the GADAG from the remote end to the interface's router.

传入:标记为传入的链路在GADAG中具有从远程端到接口路由器的方向。

4. Algorithm Key Concepts
4. 算法关键概念

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

有五个关键概念对理解MRT低点算法至关重要。第一种是将网络图中的节点彼此和GADAG根部分排序的思想。第二个想法是找到一个节点的ear并按正确的方向添加它们。第三个是低点值的概念,以及如何使用它来识别切割顶点并找到通向根的第二条路径。第四个是非2连通图是由块组成的,其中块是

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.

2-连接群集、断开链接或隔离节点。第五个是每个节点都有一个localroot;这用于计算每个块中的ADAG。

4.1. Partial Ordering for Disjoint Paths
4.1. 不相交路径的偏序

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.

给定一个图中的任意两个节点X和Y,特定的总顺序意味着X<Y或X>Y在该总顺序中。例如,图中的节点根据其唯一的IP环回地址进行排序。在偏序中,可能有一些节点无法确定X<<Y或X>>Y。可以在有向图中捕获偏序,如图3所示。在图形表示中,从X指向Y的链接表示X是网络图中Y的邻居,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]
        
         [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

图3:显示偏序的有向图

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.

要计算MRT,MRT的根位于偏序的最底部和最顶部。这意味着可以从任何节点X中拾取顺序更高的节点,直到到达根节点。类似地,从任何节点X,可以拾取顺序较低的节点,直到到达根。例如,在图4中,从G中拾取的较高节点可以通过遵循有向链接进行跟踪,它们是H、D、E和R。类似地,从G中拾取的较低节点可以通过反转有向链接进行跟踪,它们是F、B、A和R。表示此修改的偏序的图不再是DAG;它被称为几乎DAG(ADAG),因为如果指向根的链接被删除,它将是DAG。

     [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]
        
     [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

图4:ADAG显示R最低和最高的偏序

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.

最重要的是,如果节点Y>>X,则Y只能出现在从X到根的递增路径上,而不能出现在递减路径上。类似地,如果节点Z<<X,则Z只能出现在从X到根的递减路径上,而不能出现在递增路径上。

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.

当遵循递增路径时,可以选择多个较高的节点,并且仍然可以确定这些路径将与递减路径不相交。例如,在前面的示例中,节点B具有沿递增路径转发数据包的多种可能性:它可以将数据包转发到C或F。

4.2. Finding an Ear and the Correct Direction
4.2. 找到耳朵和正确的方向

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.

为简单起见,假设网络图是一个单独的2连接集群,则描述了通过添加EAR来创建GADAG的基本思想,这样ADAG就足够了。通过考虑块根而不是GADAG根,可将其推广到多个块,实际算法见第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".

为了理解查找ADAG的基本思想,首先假设我们已经有了一个部分ADAG,它还没有包含块中的所有节点,我们希望将其扩展到覆盖所有节点。假设我们找到了一条从节点X到Y的路径,使得X和Y已经包含在部分ADAG中,但是沿着该路径的所有剩余节点尚未添加到ADAG中。我们将这种路径称为“耳朵”。

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.

回想一下,我们的ADAG与偏序密切相关。更准确地说,如果我们去掉根R,剩下的DAG描述了节点的偏序。如果我们假设X和Y都不是根,我们就可以比较它们。如果其中一个相对于我们的偏序(x<y)绝对较小,我们可以在从x到y的方向上添加到ADAG的新路径。作为例子,考虑图5。

           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---|
        
           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) (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

(a) 一个2-连通图(b)部分ADAG(C不包括)(C)在添加路径(或ear)b-C-D后得到的ADAG

Figure 5

图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.

在这部分ADAG中,节点C尚未包括在内。但是,我们可以找到路径B-C-D,其中两个端点都包含在这个部分ADAG中(我们在下面的文本中称这些节点“准备就绪”),而剩余的节点(节点C)尚未包含。如果我们去掉R,剩下的DAG定义了一个偏序,关于这个偏序,我们可以说B<D;因此,我们可以在从B到D的方向上向ADAG添加路径(添加圆弧B->C和C->D)。如果B>>D,我们将以相反方向添加相同的路径。

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.

如果按照耳朵两端为X和Y的偏序,X<<Y,则ADAG中必须已经存在从X到Y的定向路径。耳朵必须以不会产生循环的方向添加;因此,耳朵必须从X到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

如果X和Y没有相互排序,我们可以为ear选择任意一个方向。我们没有限制,因为这两个方向都不会导致循环。在角落的情况下,如果ear的一个端点(比如X)是根(回想一下,两个端点必须不同),我们可以再次对ear使用两个方向,因为根可以被认为比Y小,也可以被认为比Y大。但是,我们严格选择根低于Y的方向。第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.

部分ADAG是通过找到从根R回到自身的循环来启动的。这可以通过选择R的一个非就绪邻居N,然后找到一条从N到R的路径,该路径不使用R和N之间的任何链接来实现。由于循环开始排序,因此循环的方向可以任意分配。

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.

一旦部分ADAG已经存在,它将始终有一个不是根R的节点。下面是部分ADAG总是可以添加EAR的简要证明:只需选择就绪节点Q的非就绪邻居N,这样Q就不是根R,在移除Q的图中找到从N到根R的路径。此路径是一个ear,其中ear的第一个节点是Q,下一个节点是N,然后是路径到达的第一个就绪节点之前的路径(该就绪节点是路径的另一个端点)。因为图是2连通的,所以必须有一条从N到R的路径,没有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.

总是可以选择就绪节点Q的非就绪邻居N,以便Q不是根R。因为网络是2-连接的,N必须连接到两个不同的节点,并且只有一个可以是R。因为初始循环已经添加到ADAG,所以存在非R的就绪节点。因为图是2-连接的,虽然存在非就绪节点,但就绪节点的非就绪邻居N必须不是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

Generic_Find_Ears_ADAG(根)创建一个空ADAG。将root添加到ADAG。在_GADAG中标记根。选择包含根的任意循环。将任意循环添加到ADAG。将循环的节点标记为_GADAG中的节点。将周期的非根节点添加到进程列表。当图中存在不在_GADAG中的连接节点时,选择一个新的ear。设其端点为X和Y。如果Y为根或(Y<<X),则将ear朝向X添加到ADAG,否则/(a)X为根,或(b)X<<Y,或(c)X,Y未排序,则将ear朝向Y添加到ADAG

Figure 6: Generic Algorithm to Find Ears and Their Direction in 2-Connected Graph

图6:在2-连通图中查找耳朵及其方向的通用算法

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.

图6中的算法只要求选择一个循环或ear,而不指定如何选择。不管选择路径的方法是什么,我们都会得到一个ADAG。寻找和选择耳朵的方法很重要;较短的耳导致沿捷运的路径较短。MRT Lowpoint算法使用Lowpoint继承方法构建ADAG(最终是GADAG)。第5.5节对该方法进行了定义。附录B和C中描述了构建GADAG的其他方法。第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

作为例子,再次考虑图5。首先,我们选择包含R的最短周期,它可以是R-A-B-F-D-E(假设了统一的链路成本),因此我们得到了中描述的情况

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.

图5(b)。最后,我们在就绪节点旁边找到一个节点;那一定是节点C,假设我们从就绪节点B到达它。我们在原始图中搜索从C到R的路径,没有B。第一个准备就绪的节点是节点D,因此打开的ear是B-C-D。由于B<D,我们将弧B->C和C->D添加到ADAG中。因为所有节点都准备好了,所以我们在这里停止。

4.3. Lowpoint Values and Their Uses
4.3. 低点值及其用途

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.

在网络图上计算生成树的基本方法是运行DFS,如图7所示。此树具有一个重要属性,即如果存在链接(x,n),则n是x的DFS祖先或n是x的DFS后代。换句话说,n在从根到x的路径上,或者x在从根到n的路径上。

global_variable: dfs_number

全局变量:dfs\U编号

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)

DFS\u访问(节点x,节点父节点)D(x)=DFS\u编号DFS\u编号+=1 x。DFS\u父节点=每个链接(x,w)的父节点(如果D(w)未设置DFS\u访问(w,x)

Run_DFS(node gadag_root) dfs_number = 0 DFS_Visit(gadag_root, NONE)

运行DFS(节点gadag\U根)DFS\U编号=0 DFS\U访问(gadag\U根,无)

Figure 7: Basic DFS Algorithm

图7:基本DFS算法

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.

给定一个节点x,可以计算x的邻居的最小DFS数,即min(D(w)(如果(x,w)是链路)。这将给出与x相邻的最早附着点。有趣的是,x和x的后代最早的附着点。这是通过计算低点值确定的。

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.

为了计算低点值,使用DFS遍历网络,并根据DFS漫游对顶点进行编号。让此数字表示为DFS(x)。在DFS漫游期间,导致已访问节点的所有边都是后边。后缘很重要,因为它们提供了关于节点通过另一条路径的可达性的信息。

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) ).

Low(x)=最小值((DFS(x),最低DFS(n,x->n是后边缘),最低值(n,x->n是DFS漫游中的树边缘))。

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.

图8给出了计算低点值的详细算法。图9说明了低点算法如何应用于示例图。

global_variable: dfs_number

全局变量:dfs\U编号

            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
        
            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)

运行\u低点(节点gadag\u根)dfs\u编号=0低点\u访问(gadag\u根,无,无)

Figure 8: Computing Lowpoint Value

图8:计算低点值

            [E]---|    [J]-------[I]   [P]---[O]
             |    |     |         |     |     |
             |    |     |         |     |     |
            [R]  [D]---[C]--[F]  [H]---[K]   [N]
             |          |    |    |     |     |
             |          |    |    |     |     |
            [A]--------[B]  [G]---|    [L]---[M]
        
            [E]---|    [J]-------[I]   [P]---[O]
             |    |     |         |     |     |
             |    |     |         |     |     |
            [R]  [D]---[C]--[F]  [H]---[K]   [N]
             |          |    |    |     |     |
             |          |    |    |     |     |
            [A]--------[B]  [G]---|    [L]---[M]
        

(a) a non-2-connected graph

(a) 非2连通图

             [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,  )
        
             [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))

(b) 指定了DFS值(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)
        
             [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))

(c) 指定了低点值(D(x),L(x))

Figure 9: Example Lowpoint Value Computation

图9:低点值计算示例

From the lowpoint value and lowpoint parent, there are three very useful things that motivate our computation.

从lowpoint值和lowpoint父项来看,有三个非常有用的东西可以激发我们的计算。

   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
        
   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
        

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.

要达到R,比较节点所有DFS子节点的低点值与节点的DFS值非常有用,因为它允许识别切割顶点,从而识别块。

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.

其次,通过重复遵循lowpoint_parent给出的路径,从x返回到x的祖先的路径在两个方向上都不使用链接[x,x.dfs_parent]。不需要采用完整的路径,但这提供了一种找到初始循环的方法,然后使用EAR。

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.

第三,如图9所示,即使L(x)<D(x),也可能有一个块同时包含节点的根和DFS子节点,而其他DFS子节点可能位于不同的块中。在本例中,C的子D与R在同一块中,而F不是。必须认识到,一个块的根也可能是另一个块的根。

4.4. Blocks in a Graph
4.4. 图中的块

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.

MRT Lowpoint算法的一个关键思想是,任何非2-连通图都由块(例如,2-连通簇、切割链接和/或孤立节点)组成。为了计算GADAG和MRT,在每个块中进行计算以计算ADAG或冗余树,然后将这些ADAG或冗余树组合成GADAG或MRT。

                  [E]---|    [J]-------[I]   [P]---[O]
                   |    |     |         |     |     |
                   |    |     |         |     |     |
                  [R]  [D]---[C]--[F]  [H]---[K]   [N]
                   |          |    |    |     |     |
                   |          |    |    |     |     |
                  [A]--------[B]  [G]---|    [L]---[M]
        
                  [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

(a) 具有四个块的图:三个2连通簇和一个切割链接

                  [E]<--|    [J]<------[I]   [P]<--[O]
                   |    |     |         ^     |     ^
                   V    |     V         |     V     |
                  [R]  [D]<--[C]  [F]  [H]<---[K]  [N]
                              ^    |    ^           ^
                              |    V    |           |
                  [A]------->[B]  [G]---|     [L]-->[M]
        
                  [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

(b) 目的地R的捷运蓝色

                  [E]---|    [J]-------->[I]    [P]-->[O]
                        |                 |            |
                        V                 V            V
                  [R]  [D]-->[C]<---[F]  [H]<---[K]   [N]
                   ^          |      ^    |      ^     |
                   |          V      |    |      |     V
                  [A]<-------[B]    [G]<--|     [L]<--[M]
        
                  [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

(c) 目的地R的捷运红色

Figure 10

图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.

考虑图10(a)中所描述的示例。在此图中,显示了一个特殊的图,它向我们展示了2-连通簇的所有连接方式。它有四个区块:区块1包含R、A、B、C、D、E;区块2包含C、F、G、H、I、J;块3包含K,L,M,N,O,P;块4是包含H和K的切割链路。可以观察到,前两个块有一个公共节点(节点C),块2和块3没有任何公共节点,但它们通过块4的切割链路连接。任何两个块都不能有一个以上的公共节点,因为至少有两个公共节点的两个块将符合单个2连接集群的条件。

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).

此外,请注意,如果我们想从一个块到另一个块,我们必须使用切割顶点(此图中的切割顶点为C、H、K),而不管选择的路径是什么,因此我们可以说,沿着以R为根的MRT从块3开始的所有路径都将首先穿过K。这一观察结果意味着,如果我们想找到一对以R为根的MRT,那么我们需要在块3中建立一对以K为根的RTs。类似地,我们需要在块2中找到另一对以C为根的RTs,最后,我们需要块1中最后一对以R为根的RTs。当所有的树都被选中时,我们可以简单地将它们组合起来;当一个块是切割链接(如块4中所示)时,该切割链接将以相同的方向添加到两棵树。生成的树如图10(b)和(c)所示。

Similarly, to create a GADAG it is sufficient to compute ADAGs in each block and connect them.

类似地,要创建GADAG,计算每个块中的ADAG并连接它们就足够了。

It is necessary, therefore, to identify the cut-vertices, the blocks and identify the appropriate localroot to use for each block.

因此,有必要确定切割顶点、块,并确定每个块要使用的适当localroot。

4.5. Determining Localroot and Assigning Block-ID
4.5. 确定Localroot并分配块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.

网络图中的每个节点都有一个localroot,它是同一块中最靠近根的切割顶点(或根)。localroot用于确定两个节点是否共享一个公共块。

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(node x,node Localroot)x.Localroot=如果L(c)<D(x)//x不是切割顶点Compute_Localroot(c,x.Localroot),则将x标记为切割顶点Compute_Localroot(c,x)

Compute_Localroot(gadag_root, gadag_root)

计算本地根(gadag\u根,gadag\u根)

Figure 11: A Method for Computing Localroots

图11:计算localroot的方法

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.

有两种不同的方法计算每个节点的localroot。图11给出了独立方法,更好地说明了该概念;它由附录B和C中给出的GADAG构造方法使用。MRT Lowpoint算法计算块的localroot,作为使用Lowpoint继承计算GADAG的一部分;图12给出了这种计算的本质。计算localroot的两种方法产生相同的结果。

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

获取当前节点s。计算从s到就绪节点e的ear(通过低点继承或跟随dfs父节点)。(因此,如果存在这样的ear,则s不是e。)如果s是e,则ear中的每个节点x不是s。localroot=s,否则ear中的每个节点x不是s或e x。localroot=e.localroot

Figure 12: Ear-Based Method for Computing Localroots

图12:计算localroot的基于Ear的方法

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.

一旦知道localroot,当且仅当以下三个条件之一适用时,两个节点X和Y位于公共块中。

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的localroot是X的localroot:它们位于同一块中,并且离根最近的切割顶点也不是。

o Y's localroot is X: X is the cut-vertex closest to the root for Y's block

o Y的局部根是X:X是最接近Y块根的切割顶点

o Y is X's localroot: Y is the cut-vertex closest to the root for X's block

o Y是X的局部根:Y是距离X块的根最近的切割顶点

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.

一旦我们为网络图中的每个节点计算了localroot,我们就可以为每个节点分配一个块ID,它表示节点所在的块。该计算如图13所示。

global_var: max_block_id

全局变量:最大块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)

如果(c.local\u root是x)max\u Block\u ID+=1分配\u Block\u ID(c,max\u Block\u ID)否则分配\u Block\u ID(c,cur\u ID)

max_block_id = 0 Assign_Block_ID(gadag_root, max_block_id)

最大块id=0分配块id(gadag根,最大块id)

Figure 13: Assigning Block-ID to Identify Blocks

图13:分配块ID以标识块

5. MRT Lowpoint Algorithm Specification
5. MRT低点算法规范

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.

MRT Lowpoint算法计算一个GADAG,然后路由器使用该GADAG确定其到所有目的地的MRT蓝色和MRT红色下一跳。最后,基于该信息,为每个目的地的每个下一跳选择备选方案。该算法的不同部分如下所述。

o Order the interfaces in the network graph. See Section 5.1.

o 在网络图中对接口进行排序。见第5.1节。

o Compute the local MRT Island for the particular MRT Profile. See Section 5.2.

o 计算特定地铁线路的本地地铁岛。见第5.2节。

o Select the root to use for the GADAG. See Section 5.3.

o 选择要用于GADAG的根目录。见第5.3节。

o Initialize all interfaces to UNDIRECTED. See Section 5.4.

o 将所有接口初始化为无方向。见第5.4节。

o Compute the DFS value, e.g., D(x), and lowpoint value, L(x). See Figure 8.

o 计算DFS值,例如D(x)和低点值L(x)。参见图8。

o Construct the GADAG. See Section 5.5.

o 构建GADAG。见第5.5节。

o Assign directions to all interfaces that are still UNDIRECTED. See Section 5.6.

o 为仍然没有方向的所有接口指定方向。见第5.6节。

o From the computing router x, compute the next hops for the MRT-Blue and MRT-Red. See Section 5.7.

o 从计算路由器x,计算MRT蓝色和MRT红色的下一个跃点。见第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.

o 通过确定计算路由器x应选择的MRT蓝色和MRT红色中的哪一个,确定到每个目的地的每个下一跳的备选方案。见第5.8节。

A Python implementation of this algorithm is given in Appendix A.

附录A给出了该算法的Python实现。

5.1. Interface Ordering
5.1. 接口排序

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.

为了确保计算的一致性,所有路由器必须以相同的方式对接口进行排序,直至具有相同度量的链路集与相同的相邻节点。这对于第4.3节Lowpoint_访问中的DFS是必要的,在该节中,用于探索不同树中结果的接口的选择顺序。计算GADAG还需要一致的接口顺序,其中用于形成EAR的接口的选择顺序可能导致不同的GADAG。对于第5.8节中描述的拓扑排序也是必要的,其中不同的拓扑排序顺序可能导致在不同方向上向GADAG添加无向链接。

The required ordering between two interfaces from the same router x is given in Figure 14.

图14给出了来自同一路由器x的两个接口之间所需的顺序。

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

如果a.metric<b.metric返回a\u小于b\u如果b.metric<a.metric返回b\u小于a如果a.neighbor.mrt\u node\u id<b.neighbor.mrt\u node\u id返回a\u小于b如果b.neighbor.mrt\u node\u id<a.neighbor.mrt\u node\u id返回b\u小于a//相同的度量到同一节点,所以顺序对互操作性并不重要。返回A等于B的值

Figure 14: Rules for Ranking Multiple Interfaces (Order Is from Low to High)

图14:对多个接口进行排序的规则(顺序从低到高)

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.

在图14中,如果路由器上的两个接口以相同的度量连接到同一远程路由器,Interface_Compare函数将返回a_EQUAL_to_B。这是因为最初探索这些接口的顺序不会影响此处描述的算法生成的最终GADAG。虽然在初始穿越过程中,只有一条链路将添加到GADAG,但其他平行链路将添加到GADAG,其方向与第5.6节所述为无向链路分配方向的过程中指定的方向相同。在这种情况下,实现可以自由地应用一些额外的标准来打破接口顺序中的联系,但是这里没有指定这些标准,因为它们不会影响算法生成的最终GADAG。

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].

图14中的Interface_Compare函数依赖Interface.metric和Interface.neighbor.mrt_node_id值来订购接口。不同IGP和应用的这些值的确切来源如图15所示。此处提供的OSPFv2、OSPFv3和IS-IS的度量和mrt_节点_id值是规范性的。此表中IS-IS路径控制和保留(PCR)的度量值和mrt_节点_id值应视为信息。[IEEE8021Qca]中规定了标准值。

  +--------------+-----------------------+-----------------------------+
  | 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)       |                             |
  +--------------+-----------------------+-----------------------------+
        
  +--------------+-----------------------+-----------------------------+
  | 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

图15:interface.neighbor.mrt_node_id和interface.metric的值,用于不同泛洪协议和应用程序的接口排名

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.

度量是无符号整数,必须作为无符号整数进行比较。mrt_node_id比较的结果必须与使用网络字节顺序将mrt_node_id转换为无符号整数并作为无符号整数执行比较所获得的结果相同。在具有点到点链路的IP/LDP FRR的IS-IS情况下,伪节点号(第七个八位组)为零。广播接口将在第7节中讨论。

5.2. MRT Island Identification
5.2. 捷运岛识别

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.

通过从网络图中的计算路由器开始并进行广度优先搜索(BFS),可以确定特定MRT配置文件的本地MRT孤岛。BFS只探索同一区域/级别、不排除IGP以及不符合MRT要求的链接。BFS只探索支持特定MRT配置文件的节点。有关这些标准的更精确定义,请参见[RFC7812]第7节。

   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)
        
   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

图16:捷运岛标识

5.3. GADAG Root Selection
5.3. GADAG根选择

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

在[RFC7812]的第8.3节中,描述了默认MRT配置文件的GADAG根选择策略。此选择策略允许路由器根据公布的优先级值在本地MRT岛内一致地选择公共GADAG根。MRT低点算法只要求MRT岛中的所有路由器必须选择相同的GADAG根;根据MRT配置文件的描述,机制可能会有所不同。在开始计算之前,网络图

is reduced to contain only the set of routers that support the specific MRT profile whose MRTs are being computed.

减少为仅包含支持其MRT正在计算的特定MRT配置文件的路由器集。

As noted in Section 7, pseudonodes MUST NOT be considered for GADAG root selection.

如第7节所述,GADAG根选择不得考虑伪节点。

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.

预计运营商将通过将路由器组的GADAG根选择优先级设置为更低(更优选)的数值,将一组路由器指定为GADAG根选择的良好选择。有关设置GADAG根选择优先级值的指南,请参阅第9.1节。

5.4. Initialization
5.4. 初始化

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.

在运行算法之前,需要执行标准类型的初始化,例如清除任何计算的DFS值、低点值、DFS父级、低点父级、任何MRT计算的下一跳以及与算法关联的标志。

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.

假设已运行常规SPF计算,以便从计算路由器到每个目的地的主要下一跳是已知的。这是在最后一步确定备选方案所必需的。

Initially, all interfaces MUST be initialized to UNDIRECTED. Whether they are OUTGOING, INCOMING, or both is determined when the GADAG is constructed and augmented.

最初,所有接口都必须初始化为无向。它们是传出的还是传入的,或者两者都是在构建和扩充GADAG时确定的。

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.

可能会使用标准IGP机制对某些链路和节点进行标记,以阻止或阻止过境交通。[RFC7812]第7.3.1节描述了如何将这些链路和节点排除在MRT岛形成之外。

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.

如[RFC7812]第7.3.2节所述,MRT-FRR还可以公布MRT不合格的链接。这些连接线不包括在捷运岛和GADAG内。因此,计算捷运下一跳将不会使用任何捷运不合格链接。MRT LooPoT算法在计算FRR替换时仍然需要考虑MRT不合格链接,因为MRT不合格链路仍然可以是到达目的地的最短路径下一跳。

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.

当广播接口被宣布为MRT不合格时,代表整个广播网络的伪节点不得包含在MRT岛中。这相当于将该广播网络上的所有广播接口从MRT岛排除。

5.5. Constructing the GADAG Using Lowpoint Inheritance
5.5. 使用低点继承构造GADAG

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.

如第4.2节所述,有必要从已经在GADAG(称为in_GADAG)中的节点x中找到耳朵。该算法使用了两种不同的方法来寻找耳朵。第一种方法是转到不在_GADAG中的DFS子级,然后沿着低点父级链,直到找到IN_GADAG节点。第二种方法是转到不在\u GADAG中的邻居,然后跟随DFS父节点链,直到找到一个在\u GADAG中的节点。当发现ear时,将根据所采取的方向标记相关接口。耳中的节点标记为in_GADAG。在该算法中,首先通过DFS子节点找到耳朵,然后通过DFS邻居找到耳朵。

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.

通过在处理IN_GADAG节点时添加这两种类型的耳朵,可以找到连接到该节点的所有耳朵。当然,in_GADAG节点的处理顺序是算法的关键。顺序是一堆耳朵,因此最新的耳朵位于堆栈顶部。当然,堆栈存储的是节点,而不是ear,因此在探索ear时会创建一个有序的节点列表,从ear中的第一个节点到ear中的最后一个节点,然后将该列表推送到堆栈上。

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.

每个ear表示一个偏序(见图4),沿每个ear按顺序处理节点可确保在探索偏序较高的节点的ear之前找到连接到节点的所有ear。这意味着ear中链接的方向始终是从正在处理的节点x到ear的另一端。此外,通过使用EAR堆栈,这意味着前一个EAR中的任何未处理节点的顺序只能高于堆栈上它下面的EAR中的节点。

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.

在这个依赖于低点继承的算法中,每个节点都必须有一个不是自身的低点父节点。如果节点是切割顶点,则情况可能还不是这样。因此,任何没有低点父节点的节点都会将其低点父节点设置为其DFS父节点,并将其低点值设置为其父节点的DFS值。此指定还正确地允许在两个切割顶点之间使用ear。

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

最后,该算法同时计算每个节点的localroot,如图12所示。下文对此作了进一步阐述。localroot可以从ear末端的节点继承,除非ear末端是x本身,在这种情况下,ear中所有节点的localroot都是x。这是因为无论何时在块中找到第一个循环,或计算涉及桥的ear,最靠近根的切割顶点都是x本身。在所有其他场景中,lowpoint/dfs父级的属性可确保

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.

ear的末尾将位于同一块中,因此继承其localroot将是所有新添加节点的正确localroot。

The pseudocode for the GADAG algorithm (assuming that the adjustment of lowpoint for cut-vertices has been made) is shown in Figure 17.

GADAG算法的伪代码(假设已调整切割顶点的低点)如图17所示。

Construct_Ear(x, Stack, intf, ear_type) ear_list = empty cur_node = intf.remote_node cur_intf = intf not_done = true

构造Ear(x,堆栈,intf,Ear\u类型)Ear\u列表=空cur\u node=intf.remote\u node cur\u intf=intf not\u 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

未完成时cur\u intf.UNDIRECTED=false cur\u intf.outing=true cur\u intf.remote\u intf.UNDIRECTED=false cur\u intf.remote\u intf.inbound=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

如果cur_node.IN_GADAG为false cur_node.IN_GADAG=true添加_到_list_end(ear_list,cur_node)如果ear_type为CHILD cur_intf=cur_node.lowpoint_parent_intf cur_node=cur_node.lowpoint\u parent\u node=cur_node.lowpoint\u parent\u parent=cur_node=cur_node.lowpoint其他//ear_type必须为邻居cur_intf=cur_node.dfs

              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)
        
              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

通过\u Lowpoint(拓扑,GADAG\u root)GADAG\u root.IN\u GADAG=true GADAG\u root.localroot=None将堆栈初始化为空

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)

如果((intf.remote_node.IN_gadag==false)和(intf.remote_node.dfs_parent是x))构造x的每个有序_接口intf的Ear(x,Stack,intf,CHILD)如果((intf.remote_node.IN_gadag==false)和(intf.remote_node.dfs_parent是x))则构造Ear(x、堆栈、intf、邻居)

Construct_GADAG_via_Lowpoint(topology, gadag_root)

通过_低点构造_GADAG_(拓扑,GADAG_根)

Figure 17: Lowpoint Inheritance GADAG Algorithm

图17:低点继承GADAG算法

5.6. Augmenting the GADAG by Directing All Links
5.6. 通过引导所有链接来增强GADAG

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.

无论采用何种方法构建,GADAG此时都可以用于查找MRT,但拓扑结构并不包括网络图中的所有链接。这有两个影响。首先,可能存在较短的路径,这些路径遵循GADAG偏序,因此备用路径不会尽可能短。第二,路由器x和根之间可能存在GADAG中未包含的其他路径。与仅使用当前构建的GADAG相比,包括这些设备可能为备用设备上的流量提供更多带宽,并可能减少拥塞。

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.

因此,目标是为标记为无方向的每个剩余链接分配方向,以改进计算MRT时找到的路径和路径数。

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.

要做到这一点,我们需要建立一个总秩序,尊重GADAG描述的部分秩序。这可以使用Kahn的拓扑排序[Kahn_1962_topo_sort]来完成,该排序本质上是在节点x之前的所有节点(例如,连接到x的节点)都分配了编号之后,才将编号分配给节点x。拓扑排序的唯一问题是它适用于DAG,而不是ADAG或GADAG。

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

要将GADAG转换为DAG,必须从该块中删除指向块根的所有链接。这提供了对DAG的必要转换,然后可以进行拓扑排序。向GADAG添加无向链接时,将块根连接到该块中其他节点的链接需要特殊处理,因为拓扑顺序并不总是为这些链接提供正确答案。有三种情况需要考虑。如果所讨论的无向链接在

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.

与已定向的两个节点相同,则无定向链接的方向可以从先前定向的链接继承。对于平行切割链接,我们将所有平行链接设置为传入和传出。否则,所讨论的无向链接将设置为从块根节点传出。然后,可以通过在GADAG中同时引导输入和输出的事实来识别切断链路。整个过程的确切细节如图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

如果x.IS_CUT_顶点或x是gadag_根,则为拓扑中的每个节点x添加_无向_Block_Root_链接(topo,gadag_Root)(i.remote_node.localroot不是x或i.PROCESSED)如果i2.remote\u节点是i.remote\u节点,则继续将bundle\u列表初始化为空bundle.UNDIRECTED=true bundle.OUTGOING=false bundle.INCOMING=false foreach接口i2在x中(bundle\u列表,i2)如果不是i2.UNDIRECTED:bundle.UNDIRECTED=false如果i2.INCOMING:bundle.INCOMING=true如果i2.Outing:bundle.OUTGOING=true如果bundle.UNDIRECTED=false i3.remote\u intf.UNDIRECTED=false i3.PROCESSED=true i3.remote\u intf.PROCESSED=true i3.OUTGOING=true i3.remote\u intf.INCOMING=true如果(bundle.OUTGOING和bundle.INCOMING)bundle\u列表i3中的foreach接口i3.UNDIRECTED=false i3.remote\u intf.UNDIRECTED=false i3.PROCESSED=true i3.remote\u intf.PROCESSED=true i3.OUTGOING=true i3.remote\u intf.Ingoing=true i3.remote\u intf.OUTGOING=true

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

else if bundle.OUTGOING foreach interface i3 in bundle\u list i3.unddirected=false i3.remote\u intf.unddirected=false i3.PROCESSED=true i3.remote\u intf.PROCESSED=true i3.OUTGOING=true i3.remote\u intf.INCOMING=true else if bundle.INCOMING foreach interface i3 in in bundle\u list i3.unddirected=false i3.remote\u intf.unddirected=false i3.PROCESSED=false i3.PROCESSED=true i3.remote\u intf.PROCESSED=true i3.INCOMING=true i3.remote\u intf.Outing=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

如果x.IS_CUT_VERTEX或如果i.remote_node.localroot是x如果i.Incoming:i.Incoming=false i.Incoming\u STORED=true i.remote\u intf.outing=false i.remote\u intf.outing\u STORED=true,则修改topo中每个节点x的\u Block\u Root\u Incoming\u Links(topo,gadag\u Root)或如果i.remote\u node.localroot是x的每个接口i.remote\u根

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

如果x.IS_CUT_VERTEX或x是gadag_Root foreach接口i of x如果i.remote_node.localroot是x如果i.Incoming_storaged i.Incoming=true i.remote_intf.outing=true i.Incoming_storaged=false i.remote_intf.outing_storaged=false,则还原拓扑中每个节点x的\u Block\u Root\u传入链接(topo,gadag\u Root)

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

运行拓扑排序GADAG(拓扑,GADAG根)修改拓扑节点中每个节点x的块根传入链接(拓扑,GADAG根)。如果(i.传入)节点,未访问=0 foreach interface i of x。未访问+=1初始化工作列表为空初始化拓扑顺序列表为空

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)

在工作列表不为空的情况下,将项目添加到列表结束(工作列表,gadag根)y=从列表中删除项目开始(工作列表)将项目添加到列表结束(拓扑顺序列表,y)对于每个有序的i/y接口i,如果intf.OUTPING i.remote\U节点。未访问-=1如果i.remote\U节点。未访问为0,将项目添加到列表结束(工作列表,i.remote\U节点)下一个拓扑顺序=1,而拓扑顺序列表不为空y=从拓扑列表(拓扑顺序列表)中删除开始项y。拓扑顺序=下一个拓扑顺序下一个拓扑顺序+=1还原块根目录下传入链接(拓扑、gadag根目录)

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

def设置其他无向链接基于拓扑顺序(拓扑)如果i.UNDIRECTED:if x.topo_order<i.remote_node.topo_order i.outing=true i.UNDIRECTED=false i.remote_intf.INCOMING=true i.remote_intf.UNDIRECTED=false else i.INCOMING=true i.UNDIRECTED=false 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)

添加无向链接(拓扑,gadag根)添加无向块链接(拓扑,gadag根)运行拓扑排序gadag(拓扑,gadag根)设置其他无向链接基于拓扑顺序(拓扑)

Add_Undirected_Links(topo, gadag_root)

添加无向链接(拓扑、gadag根)

Figure 18: Assigning Direction to UNDIRECTED Links

图18:为无向链接指定方向

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.

代理节点不需要添加到网络图中。它们不能过渡,也不会影响计算的MRT。第5.9节详细介绍了如何计算代理节点的MRT蓝色和MRT红色下一跳,以及如何选择适当的备用下一跳。

5.7. Compute MRT Next Hops
5.7. 计算捷运下一跳

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.

如第4.1节所述,一旦找到ADAG,就可以直接找到从任何节点X到ADAG根的下一跳。然而,在该算法中,我们将重用公共GADAG,不仅用它找到根在GADAG根上的一对MRT,而且找到根在每个节点上的一对MRT。这很有用,因为它的计算速度要快得多。

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.

从普通GADAG计算不同根MRT的方法基于两个思想。首先,如果两个节点X和Y以偏序相互排序,则可以使用沿传出链路的SPF(递增SPF)和沿传入链路的SPF(递减SPF)来查找递增和递减路径。第二,如果两个节点X和Y没有按照偏序相互排序,则可以使用中间节点通过增加/减少到中间节点,然后减少/增加到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.

通常,假设网络是2连通的,将讨论这两个基本概念。第5.7.4节讨论了对多个块的概括。第5.7.5节给出了完整的算法。

5.7.1. MRT Next Hops to All Nodes Ordered with Respect to the Computing Node

5.7.1. MRT下一个跃点是相对于计算节点排序的所有节点

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.

查找从计算路由器X到任何节点Y的两条节点不相交路径取决于Y>>X还是Y<<X。如图19所示,如果Y>>X,则存在一条从X到Y的递增路径,而不穿过R;它包含间隔[X,Y]中的节点。还有一条递减路径,它向R递减,然后从R递减到Y;它包含间隔为[X,R-small]或[R-great,Y]的节点。这两条路径不能有X和Y以外的公共节点。

                     [Y]<---(Cloud 2)<--- [X]
                      |                    ^
                      |                    |
                      V                    |
                   (Cloud 3)--->[R]--->(Cloud 1)
        
                     [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
        
                  MRT-Blue path: X->Cloud 2->Y
                  MRT-Red path: X->Cloud 1->R->Cloud 3->Y
        
                              Figure 19: Y>>X
        
                              Figure 19: Y>>X
        

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].

如图20所示,如果Y<<X,则应用类似的逻辑。在这种情况下,从X增加到R,然后从R增加到Y,以使用间隔[X,R-great]和[R-small,Y]中的节点。从X开始的递减路径到达Y而不穿过R,并使用间隔[Y,X]中的节点。

                    [X]<---(Cloud 2)<--- [Y]
                     |                    ^
                     |                    |
                     V                    |
                  (Cloud 3)--->[R]--->(Cloud 1)
        
                    [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
        
                 MRT-Blue path: X->Cloud 3->R->Cloud 1->Y
                 MRT-Red path: X->Cloud 2->Y
        
                              Figure 20: Y<<X
        
                              Figure 20: Y<<X
        

5.7.2. MRT Next Hops to All Nodes Not Ordered with Respect to the Computing Node

5.7.2. MRT下一跳到所有未针对计算节点排序的节点

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.

当X和Y不排序时,第一条路径应该增加,直到到达节点G,其中G>>Y。在G处,我们需要减少到Y。另一条路径应该正好相反:我们必须减少,直到到达节点H,其中H<<Y,然后增加。因为R小于且大于Y,所以G和H必须存在。也很容易看出这两条路径必须是节点不相交的:第一条路径包含区间[X,G]和[Y,G]中的节点,而第二条路径包含区间[H,X]和[H,Y]中的节点。如图21所示。地铁蓝需要先减后增,地铁红需要先增后减;如果一个简单地为一个增加,为另一个减少,那么两条路径都将通过根R。

                 (Cloud 6)<---[Y]<---(Cloud 5)<------------|
                   |                                       |
                   |                                       |
                   V                                       |
                  [G]--->(Cloud 4)--->[R]--->(Cloud 1)--->[H]
                   ^                                       |
                   |                                       |
                   |                                       |
                  (Cloud 3)<---[X]<---(Cloud 2)<-----------|
        
                 (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
        
              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

图21:X和Y无序排列

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.

只要G和H不是同一个节点,这就给出了不相交的路径。由于G>>Y和H<<Y,如果G和H可以是同一个节点,则必须是根R。这是不可能的,因为只有一个到根R的传入接口是在找到初始循环时创建的。回想一下图6,每当发现一个ear的一端是根R时,该ear都是从R定向的,因此R上的关联接口是传出的,而不是传入的。因此,在R之前必须有一个最大的节点M,这样MRT红色路径将永远不会到达R;它将在M处转动并减小到Y。

5.7.3. Computing Redundant Tree Next Hops in a 2-Connected Graph
5.7.3. 2-连通图中冗余树下一跳的计算

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?

第5.7.1和5.7.2节给出了计算2连通图中RT下一跳的基本思想。有了这两个想法,我们怎么才能找到树呢?

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.

如果某个节点X只想找到下一个跃点(这通常是IP网络的情况),那么找到哪些节点大于或小于X,哪些节点没有排序就足够了;这可以通过运行以X为根的递增SPF和递减SPF,而不从ADAG根探索任何链接来实现。

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

原则上,在确定导致最大冗余树的蓝色和红色下一跳的过程中,可以使用SPF以外的遍历方法来遍历GADAG。只要一次遍历在GADAG指定的方向上使用链接,而另一次遍历在GADAG指定的相反方向上使用链接,情况就会如此。然而,不同的遍历算法通常会导致不同的蓝色和红色

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.

下一跳。因此,此处指定的算法需要使用SPF遍历GADAG以生成MRT蓝色和红色下一跳,如下所述。

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.

以X为根的SPF增加且不从根探索链接将发现增加的下一跳到所有Y>>X。增加的下一跳是X在MRT蓝色上到达Y的下一跳。以X为根的SPF减少且不从根探索链接将发现减少的下一跳到所有Z<<X。减少的下一跳是X的下一跳在MRT红色上到达Z。由于根R大于和小于X,在增加SPF和减少SPF后,X在MRT蓝色和MRT红色上到达R的下一跳是已知的。对于每个节点Y>>X,X在MRT红色上到达Y的下一跳被设置为在MRT红色上到达R的下一跳。对于每个节点Z<<X,X在MRT蓝色上到达Z的下一跳被设置为在MRT蓝色上到达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.

对于那些SPF增加或减少都无法到达的节点,我们还可以确定下一跳。对于没有按照X排序的节点,增加的MRT蓝色下一跳是沿着向R递减的MRT红色的下一跳,而递减的MRT红色下一跳是沿着向R递增的MRT蓝色的下一跳。当然,因为R是按照所有节点排序的,总有一条增加和减少的道路通向它。该算法不提供所采用的完整特定路径,只提供要使用的适当下一跳。G和H的恒等式不由计算节点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.

最后要考虑的是当GADAG ROOT R计算它自己的下一跳。由于GADAG根R<<所有其他节点,因此运行以R为根的递增SPF将到达所有其他节点;MRT蓝色下一个啤酒花是指SPF增加的啤酒花。类似地,由于GADAG根R是>>所有其他节点,因此在R处运行一个递减的SPF将到达所有其他节点;MRT红色下一个跃点是SPF降低时发现的。

                 E---D---|              E<--D<--|
                 |   |   |              |   ^   |
                 |   |   |              V   |   |
                 R   F   C              R   F   C
                 |   |   |              |   ^   ^
                 |   |   |              V   |   |
                 A---B---|              A-->B---|
        
                 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

(a) (b)一个2-连通图,它是根在R上的生成ADAG

Figure 22

图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.

作为一个例子,考虑图22中描述的情况。节点C在ADAG上运行递增SPF和递减SPF。增加的SPF达到D、E和R;下降的SPF到达B、A和R。E>>C。因此,朝向E的MRT蓝色下一跳是D,因为E是通过D在递增路径上到达的。朝向E的MRT红色下一跳是B,因为R是通过B在递减路径上到达的。因为E>>D,D将类似地计算其MRT蓝色下一跳是E,确保MRT Blue上的数据包将使用路径C-D-E。B、a和R将类似地计算向E的MRT Red下一跳(其顺序小于B、a和R),确保MRT Red上的数据包将使用路径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.

C也可以确定向F的下一跳。因为F不是相对于C排序的,所以MRT蓝色下一跳是朝向R(即B)的递减跳,而MRT红色下一跳是朝向R(即D)的递增跳。由于F>>B,对于其朝向F的MRT蓝色下一跳,B将使用朝向F的实际递增下一跳。因此,在MRT蓝色上转发给B的数据包将在路径C-B-F上到达F。类似地,D将使用朝向F的实际递减下一跳作为其MRT红色下一跳,在MRT红色上的数据包将使用路径C-D-F。

5.7.4. Generalizing for a Graph That Isn't 2-Connected
5.7.4. 非2-连通图的推广

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.

如果一个图不是2-连通的,那么第5.7.3节中给出的基本方法需要一些扩展来确定用于计算路由器X块之外的目的地的适当MRT下一跳。为了在该图中找到一对最大冗余树,我们需要在每个块中找到一对RTs(这些树的根将在后面讨论),并将它们组合起来。

When computing the MRT next hops from a router X, there are three basic differences:

从路由器X计算MRT下一跳时,有三个基本区别:

1. Only nodes in a common block with X should be explored in the increasing-SPF and decreasing-SPF.

1. 在递增SPF和递减SPF中,只应探索具有X的公共块中的节点。

2. Instead of using the GADAG root, X's localroot should be used. This has the following implications:

2. 应该使用X的localroot,而不是使用GADAG根。这有以下影响:

A. The links from X's localroot should not be explored.

A.不应探索来自X的localroot的链接。

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.

B.如果在传出SPF so Y>>X中探测节点,则X到达Y的MRT红色下一跳使用X的MRT红色下一跳到达X的本地根,如果Z<<X,则X到达Z的MRT蓝色下一跳使用X的MRT蓝色下一跳到达X的本地根。

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.

C.如果在递增SPF或递减SPF中未到达具有X的公共块中的节点W,则W相对于X是无序的。X的MRT蓝色下一跳到W是X的递减(又名MRT红色)下一跳到X的localroot。X的MRT红色下一跳到W是X的增加(又名MRT蓝色)下一跳到X的localroot。

3. For nodes in different blocks, the next hops must be inherited via the relevant cut-vertex.

3. 对于不同块中的节点,下一跳必须通过相关切割顶点继承。

These are all captured in the detailed algorithm given in Section 5.7.5.

这些都在第5.7.5节给出的详细算法中捕获。

5.7.5. Complete Algorithm to Compute MRT Next Hops
5.7.5. 计算MRT下一跳的完整算法

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.

图23给出了计算特定路由器X的MRT下一跳的完整算法。除了计算X用于到达每个节点Y的MRT蓝色下一跳和MRT红色下一跳外,该算法还存储了一个“order_proxy”,如果它位于块外,它是到达Y的合适切割顶点,这将在稍后决定MRT蓝色或MRT红色是否可以为特定的主下一跳提供可接受的备选方案时使用。

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

In_Common_Block(x,y)if((x.Block_id是y.Block_id)或(x是y.localroot)或(y是x.localroot))返回true返回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

如果方向为正向y,则存储结果(y,方向)。较高=真y。蓝色\下一个\跳数=y。如果方向为反向y,则存储下一个\跳数。较低=真y。红色\下一个\跳数=y。下一个\跳数

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)

SPF_No_Traverse_Block_Root(SPF_Root,Block_Root,direction)初始化SPF_堆以清空将节点的SPF_度量初始化为无穷大,然后跳到清空SPF_根。SPF_度量=0插入(SPF_堆,SPF_根),而(SPF_堆不为空)最小节点=移除最低(SPF_堆)如果((最小节点为SPF_根)或(min_节点不是block_root))如果(((方向向前)和intf.outing)或((方向反向)和intf.In传入))并且在公共_块(spf_root,intf.remote_node))中,则min_节点的每个接口intf如果路径度量<intf.remote\u node.spf\u metric=min\u node.spf\u metric=min\u node.spf\u metric=path\u metric如果min\u node是spf\u root intf.remote\u node.next\u hops=make\u list(intf)else intf.remote\u node.next\u hops=min\u node.next\u hops插入或更新(spf\u堆,intf.remote\u node)else如果path_metric==intf.remote_node.spf_metric如果min_node是spf_根添加_到_列表(intf.remote_node.next_hops,intf)否则添加_列表到_列表(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

SetEdge(y)如果y.blue\u next\u hops为空,y.red\u next\u hops为空SetEdge(y.localroot)y.blue\u next\u hops=y.localroot.blue\u next\u hops y.red\u next\u hops=y.localroot.red\u next\u hops y.order\u proxy=y.localroot.order\u proxy

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)

计算每个节点y的下一个hops(x,gadag_root)y.higher=y.lower=false clear y.red_next_hops和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.
        
      // 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

// 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_hopstranslate error, please retry

// 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)

//如果(x不是gadag\u root)和(x.localroot不是gadag\u root)gadag\u root.blue\u next\u hops=x.localroot.blue\u next\u hops gadag\u root.red\u next\u hops=x.localroot.red\u next\u hops gadag\u root.order\u proxy=x.localroot for每个节点y如果(y不是gadag\u root)和(y不是x)和y.IN\u MRT\u SetEdge(y)

max_block_id = 0 Assign_Block_ID(gadag_root, max_block_id) Compute_MRT_NextHops(x, gadag_root)

max\u block\u id=0分配\u block\u id(gadag\u root,max\u block\u id)计算\u MRT\u NextHops(x,gadag\u root)

Figure 23: Complete Algorithm to Compute MRT Next Hops

图23:计算MRT下一跳的完整算法

5.8. Identify MRT Alternates
5.8. 确定捷运候补列车

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

此时,计算路由器S知道MRT岛中每个目的地的MRT蓝色下一跳和MRT红色下一跳。沿SPT的主要下一跳也是已知的。对于到达目的地D的每个主下一跳,仍需确定哪个MRT避开主下一跳节点F。此计算取决于Compute_MRT_NextHops中的数据集,例如每个节点y

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.

y、 蓝色下一跳、红色下一跳、y顺序代理、y较高、y较低和拓扑顺序。回想一下,任何路由器都只知道哪些节点比自己大,哪些节点比自己小,但它无法轻松确定任意两个给定节点之间的关系;这就是为什么我们需要拓扑排序。

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.

对于每个目的地D的每个主下一跳节点F,S可以调用Select_Alternates(S、D、F、primary_intf),以确定是否使用MRT蓝色或MRT红色下一跳作为该主下一跳的备用下一跳。该算法如图24所示,随后将进行讨论。

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

选择内部(D、F、主输入、D、D、D、D、D、D、D、topo、顺序):如果D、U、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D、D

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

否则如果D_较高如果F.higher和F.LOWER return使用蓝色如果F.LOWER return使用蓝色如果F.higher if(F.topo_order>D_topo_order)返回使用蓝色如果(F.topo_order<D_topo_order)返回使用红色//对于无序的wrt返回使用红色或蓝色

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

否则,如果D_较低(如果F.HIGHER)和F.lower退货使用红色(如果F.HIGHER退货使用红色(如果F.lower)如果F.topo订单>D_topo订单退货使用蓝色

if F.topo_order < D_topo_order return USE_RED //F unordered wrt S return USE_RED_OR_BLUE

如果F.topo\u订单<D\u topo\u订单退货使用\u红色//如果未订单退货使用\u红色\u或\u蓝色

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

else//D是无序的,如果F为高,如果F为低,如果F为低,如果F为低,如果F为低,使用红色,如果F为高,使用蓝色,如果F为高,使用蓝色D\u拓扑顺序:返回使用\u蓝色其他:返回使用\u红色

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)

如果不在公共块(F,S)中,选择替换项(D,F,primary intf)如果(D是F)或(D.order\U proxy是F),则返回不同块中的原始项(D,F,primary)如果(D是F)或(D.order\U proxy是F)返回原始项(D,F,primary\U intf)如果(D是F)或(D.order\U proxy是F),则返回原始项(D,F,primary\U)或(D)OPU)order)返回内部替换项(D,F,主输入,D低,D高,D拓扑顺序)

      Figure 24: Select_Alternates() and Select_Alternates_Internal()
        
      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.

首先处理F也是D或者F是D的顺序代理的情况很有用。在这种情况下,只有链路保护是可能的。使用不使用失败的主下一跳的MRT。如果两个MRT都使用主下一跳,则主下一跳必须是剪切链路,因此可以使用任一MRT,但必须修剪MRT下一跳集,以避免主下一跳接口失败。为了指示这种情况,Select_Alternates返回PRIM_NH_IS_D_或_OP_FOR_D。不提供处理上述三个子情况的显式伪代码。

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.

Select_Alternates_Internal()背后的逻辑如图25所示。作为一个例子,考虑表中描述的第一种情况,其中d>>s和d<。如果这是真的,则S或D必须是块根,如果F>S和F<S,则S是块根。因此,从S到D的蓝色路径是到D的递增路径,红色路径S到D是到D的递减路径。如果F.topo_顺序>D.topo_顺序,则F的顺序高于D,或者F的顺序相对于D是无序的。因此,F要么在从S到D的递减路径上,或者它既不是从S到D的递增路径,也不是递减路径。在这两种情况下,从S到D的递增路径可以安全地避免F。我们知道,当S是R时,递增路径是蓝色路径,因此使用蓝色路径可以安全地避免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.

相反,如果F.topo_顺序<D.topo_顺序,则F的顺序低于D,或者F相对于D是无序的。因此,F要么在从S到D的递增路径上,要么在从S到D的递增路径上,要么在从S到D的递减路径上。在这两种情况下,从S到D的递减路径可以安全地避免F。我们知道,当S是R时,递减路径是红色路径,因此使用红色路径避免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.

如果F>>S或F<<S(但不是两者),则D是块根。然后我们知道从S到D的蓝色路径是到R的递增路径,红色路径是到R的递减路径。当F>>S时,我们推断F是从S到R的递增路径。因此为了避免F,我们使用从S到R的递减路径,即红色路径。相反,当F<<S时,我们推断F在从S到R的递减路径上。因此为了避免F,我们使用从S到R的递增路径,即蓝色路径。

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

根据源(S)、目的地(D)、主下一跳(F)和块根(R)之间的偏序和拓扑排序关系确定MRT下一跳和替换。topo(N)表示节点N的拓扑排序值。X??Y表示节点X相对于节点Y是无序的。假设已经处理了其中F是D或其中F是D的顺序代理的情况。

Figure 25: Determining MRT Next Hops and Alternates

图25:确定捷运下一跳和候补

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

图25中的最后一个案例需要额外的解释。在这种情况下,从S到D的红色路径避免了F,这一事实依赖于我们在该算法中构造的GADAG的一个特殊属性,这一属性通常不是所有GADAG都共享的。当D相对于S是无序的,F是S的localroot时,它可以

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.

仅当S和F之间的链接被标记为MRT_不合格时,才会出现该链接不在GADAG中的情况。对于任意GADAG,S没有足够的基于计算顺序关系的信息来确定红色路径或蓝色路径在到达K或L之前是否会到达F(也是本地根),并使其安全到达D。但是,我们使用本文中的算法构造的GADAG不是任意GADAG。它们还有一个附加属性,即到localroot的传入链接只来自同一块中的另一个节点。这是施工方法的结果。此附加属性保证从S到D的红色路径永远不会通过S的localroot(这将要求localroot扮演L的角色,即路径中排序高于D的第一个节点,这反过来又要求localroot在GADAG中有两个传入链接,这是不可能发生的),使用这些特殊构造的GADAG时,使用红色路径以避免F是安全的。

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.

作为SelpTyTalnEnthIsIn()操作的一个例子,考虑图26中描述的ADAG,首先假设G是源,D是目的地,H是失败的下一跳。由于D>>G,我们需要比较H.topo_顺序和D.topo_顺序。由于D.topo_顺序>H.topo_顺序,D必须高于H或相对于H无序,因此我们应该选择朝向根的递减路径。然而,如果目的地是J,我们必须找到H.topo_order>J.topo_order,因此我们必须选择J的下一跳递增的蓝色,即I。在这种情况下,当目的地是C时,我们发现需要先减小以避免使用H,因此选择蓝色,先减小后增大,路径。

                             [E]<-[D]<-[H]<-[J]
                              |    ^    ^    ^
                              V    |    |    |
                             [R]  [C]  [G]->[I]
                              |    ^    ^    ^
                              V    |    |    |
                             [A]->[B]->[F]---|
        
                             [E]<-[D]<-[H]<-[J]
                              |    ^    ^    ^
                              V    |    |    |
                             [R]  [C]  [G]->[I]
                              |    ^    ^    ^
                              V    |    |    |
                             [A]->[B]->[F]---|
        

Figure 26: ADAG Rooted at R for a 2-Connected Graph

图26:2-连通图的根在R的ADAG

5.9. Named Proxy-Nodes
5.9. 命名代理节点

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.

如[RFC7812]第11.2节所述,有必要为命名代理节点找到MRT蓝色和MRT红色下一跳和MRT-FRR替代。一个示例用例是当域中只有部分MRT支持时,不属于本地MRT岛的路由器。

5.9.1. Determining Proxy-Node Attachment Routers
5.9.1. 确定代理节点连接路由器

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.

[RFC7812]第11.2节讨论了确定给定代理节点的两个代理节点连接路由器(对应于前缀)的一般注意事项。MRT岛中播发前缀的路由器是代理节点附件路由器的候选路由器,其关联的命名代理成本等于前缀的播发成本。

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).

岛边界路由器(IBR)是MRT岛上连接到岛邻居(in)的路由器,该邻居不是MRT岛上的路由器,而是在同一区域/级别上的路由器。如果从IN到前缀的最短路径未进入MRT岛,则(IBR,IN)对是代理节点连接路由器的候选。下面给出了识别此类无环岛邻居(LFIN)的方法。分配给每对(IBR,IN)的命名代理成本是成本(IBR,IN)+D_opt(IN,前缀)。

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.

从前缀广告路由器集合和具有至少一个LFIN的ibr集合中,选择具有最低命名代理成本的两个路由器。根据最低的路由器ID断开连接。为便于讨论,所选的两个路由器将被称为代理节点连接路由器。

5.9.2. Computing If an Island Neighbor (IN) Is Loop-Free
5.9.2. 计算孤岛邻居(IN)是否无环路

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.

如上所述,对于目的地的整个捷运岛,IN需要无环路。这可以通过运行通常的SPF算法来实现,同时跟踪通过捷运岛的最短路径。这方面的伪代码如图27所示。孤岛_标记_SPF()将针对需要为无循环条件求值的每个IN运行,IN作为SPF_根。然后,可以通过评估每个感兴趣的目的地的node.PATH_HITS_island来确定与MRT岛相关的IN-loop是否空闲。

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

Island_Marking_SPF(SPF_root)初始化SPF_heap为空初始化节点的SPF_度量为无穷大,然后跳到空,路径_HITS_Island为false SPF_root.SPF_metric=0 insert(SPF_heap,SPF_root),而(SPF_heap不为空)min_node=remove_lower(SPF_heap)如果路径度量<intf.remote\u node.spf\u metric intf.spf\u metric intf.remote\u node.spf\u metric intf.remote\u node.spf\u metric=path\u metric如果min\u node是spf\u root intf.remote\u node.next\u hops=make\u list(intf)else intf.remote\u node.next\u hops=min\u node.next\u hops如果intf.remote\u node.IN\u MRT\u ISLAND intf.remote\u node.PATH\u HITS\u ISLAND=true else intf.remote\u node.PATH\u HITS\u ISLAND=min\u node.PATH\u HITS\u ISLAND插入或更新(spf\u堆、intf.remote\u节点)如果PATH\u metric==intf.remote\u node.spf\u metric如果min\u node是spf根节点,则添加\u到\u列表中(intf.remote_node.next_hops,intf)如果intf.remote_node.IN_MRT_ISLAND intf.remote_node.PATH_HITS_ISLAND=true else intf.remote_node.next_hops,则将_列表添加到_列表(intf.remote_node.next_hops,min_node.next_hops)中

Figure 27: Island_Marking_SPF() for Determining If an Island Neighbor Is Loop-Free

图27:孤岛_标记_SPF(),用于确定孤岛邻居是否无环路

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

给定前缀也可能是由非岛路由器和岛路由器的组合产生的。Island_Marking_SPF()计算的结果可用于确定从IN到该前缀的最短路径是否到达MRT Island。IN到达前缀P的最短路径由到达前缀P的总成本确定,该总成本是IN到达前缀广告节点的成本与该节点广告前缀的成本之和。选择前缀P的总成本最小的路径。如果该最小总成本路径的前缀广告节点将path_HITS_ISLAND设置为True,则对于到达前缀P的MRT ISLAND,IN不是无环的。如果

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.

有多个最小总成本路径可以到达前缀P,那么最小总成本路径中涉及的所有前缀广告路由器必须将路径_HITS_ISLAND设置为False,以使in被视为无环路才能到达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.

请注意,还有其他计算可用于确定来自给定IN_的路径是否可能通过给定前缀或目的地的MRT岛。例如,本文件之前的草案版本规定在修改后的拓扑上运行SPF算法,该算法将MRT岛视为单个节点(岛内链路设置为零成本),以便为计算提供输入,以确定从in到非岛目的地的路径是否在该修改后的拓扑中命中MRT岛。此计算足以保证路径不会撞到原始拓扑中的MRT岛。但是,在修改后的拓扑中不符合命中MRT岛条件的路径可能不会实际命中原始拓扑中的MRT岛。上面的Island_Marking_SPF()中描述的算法不会修改原始拓扑,只有在实际路径确实到达MRT岛时,才会取消路径的资格。

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.

由于所有路由器需要就哪些路由器符合LFIN得出相同的结论,本规范要求所有计算LFIN的路由器必须使用一种算法,其结果与图27中的孤岛标记SPF()的结果相同。

5.9.3. Computing MRT Next Hops for Proxy-Nodes
5.9.3. 计算代理节点的MRT下一跳

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.

在代理节点仅连接到GADAG中的一个节点的退化情况下,确定代理节点的MRT下一跳是微不足道的,因为所有需要的信息都可以从该代理节点连接路由器导出。如果有多个接口将代理节点连接到单个代理节点连接路由器,则可以将一些接口分配给MRT Red,将其他接口分配给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().

现在,考虑连接到两个代理节点附件路由器的代理节点P。图28中Select_Proxy_Node_NHs(P,S)的伪代码指定计算路由器S必须如何计算到达代理节点P的MRT红色和蓝色下一跳。MRT_Node_id值较低(如图15所定义)的代理节点连接路由器被分配给X,另一个代理节点连接路由器分配给Y。我们将使用GADAG定义的X、Y和S的相对顺序来确定到达P的MRT红色和蓝色下一跳,因此我们还将A和B分别定义为X和Y的顺序代理,关于S。所有节点关于S的订单代理已在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
        
 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
        
         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
        
             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)

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)返回断言(False)

Figure 28: Select_Proxy_Node_NHs()

图28:选择\u代理\u节点\u 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().

预先了解由Select_proxy_node_NHs()生成的到达代理节点P的蓝色下一个跃点将始终是到达代理节点附件路由器X的下一个跃点,这是非常有用的,而到达代理节点P的红色下一跳将始终是到达代理节点连接路由器Y的下一跳。这与Compute_MRT_NextHops()生成的红色和蓝色下一跳不同,例如,到目的地的蓝色下一跳(根据源排序)将始终对应于GADAG上增加的下一跳。由Select_Proxy_Node_NHs()选择的下一个跃点作为到达P的蓝色下一个跃点(在到达P的过程中必然经过X)的确切选择取决于GADAG,但这种关系比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.

A、B和S之间有21种不同的相对顺序关系,Select_Proxy_Node_NHs()用于确定P的红色和蓝色下一跳。本文档不试图提供Select_Proxy_Node_NHs()中考虑的每种情况的详尽描述。相反,我们提供了不同情况下的高级概述,并且我们详细地考虑了一些情况,给出了一个可以用来理解每种情况的推理的例子。

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.

在最高级别,选择_Proxy_Node_NHs()根据A或B是否是S的localroot来区分四种不同的情况。例如,对于案例4.0,A或B都不是S的localroot。案例4.05解决了S是A或B的localroot的情况,而案例4.1、4.2、,和4.3解决了在GADAG上,A的顺序低于S,A的顺序高于S,或A相对于S无序的情况。一般来说,这些情况中的每一种都会进一步细分为B的排序是否低于S,B的排序是否高于S,或者B相对于S的排序是否无序。在某些情况下,我们还需要进一步的区分,其中我们使用a相对于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,

作为一个详细的例子,让我们考虑案例4.1和它的所有子案例,并解释为什么选择红色和蓝色下一跳到达P,因为它们在StReTyPro XYOXNODENH()中。在案例4.1中,A和B都不是S的localroot,S不是A或B的localroot,

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.

在GADAG上,A的顺序低于S。在这种情况下,我们知道到达X的红色路径(如在Compute_MRT_NextHops()中计算的)将跟随向A的下一个跃点的减少,而到达X的蓝色路径将跟随向localroot的下一个跃点的增加,然后将下一个跃点增加到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.

现在考虑子情形4.1.1,其中B被排序为高于S。在这种情况下,我们知道到达Y的蓝色路径将跟随增加下跳到B,而红色下跳到达Y时将跟随下跳跳到局部根,然后将下跳变为B。因此,通过两个不相交的路径到达x和y;我们可以选择红色的下一跳到X,蓝色的下一跳到Y。我们选择了一个惯例,即蓝色的下一跳到P是通过X的,红色的下一跳到P是通过Y的,因此我们可以看到案例4.1.1产生了期望的结果。选择蓝色到X,红色到Y不会产生不相交的路径,因为路径至少在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.

现在考虑子情形4.1.2,其中B被排序为低于S。在这种情况下,我们知道到达Y的红色路径将跟随下跳向B减小,而到达下Y的蓝色下一跳将跟随增加下一跳到局部根,然后将下一个跃点增加到A。这里的选择比4.1.1中的选择更困难,因为A和B都在从S到localroot的递减路径上。我们希望使用直接递减(红色)路径,以接近GADAG上的S。我们通过比较A和B的拓扑排序顺序来获得额外的信息。如果A.topo_顺序<B.topo_顺序,那么我们使用红色到Y,蓝色到X,因为Y的红色路径将减少到B而不击中A,X的蓝色路径将增加到A而不击中B。相反,如果A.topo_顺序>B.topo_顺序,那么我们使用红色到X,蓝色到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.

请注意,当A相对于B无序时,比较A.topo_顺序与B.topo_顺序的结果可能大于或小于。在这种情况下,结果并不重要,因为任何选择(红色到Y,蓝色到X,或红色到X,蓝色到Y)都可以工作。需要的是,在比较A.topo_顺序和B.topo_顺序时,网络中的所有节点都给出相同的结果。通过让所有节点运行相同的算法(run_Topological_Sort_GADAG())来计算拓扑排序顺序,可以保证这一点。

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.

最后,我们考虑情况4.1.3,其中B相对于S.是无序的,在这种情况下,到达Y的蓝色路径将跟随下一跳到局部根,直到它到达小于B的某个节点(k),在此之后,需要增加下一个跃点到B。到达Y的红色路径将跟随增加的下一个跃点到localroot,直到到达排序大于B的某个节点(L),之后需要减少下一个跃点到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.

K和A都是从S开始递减的,但我们没有关于递减路径是否会先到达K或A的信息。相反,我们知道从S开始的递增路径在到达A之前会到达L。因此,我们使用红色路径到达Y,红色路径到达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.

类似的推理可用于理解Select_Proxy_Node_NHs()中使用的其他17种情况。然而,情况2.3和3.3值得特别注意,因为这两种情况下解决方案的正确性依赖于我们在该算法中构造的GADAG的一个特殊属性,一个不是所有GADAG都共享的属性。考虑到情况2.3,我们考虑A是S的局部根,而B不是,相对于B是无序的。x的红色路径从s减小到局部根a,而x的蓝色路径从s增加到局部根a。蓝色路径y y朝向局部根a减小,直到它到达某个节点(k)。它的顺序小于B,之后路径增加到B。到Y的红色路径向localroot A增加,直到到达排序大于B的某个节点(L),之后路径减少到B。可以看出,对于任意GADAG,到目前为止只计算了排序关系,我们没有足够的信息来选择一对保证不相交的路径来到达X和Y。在某些拓扑中,A将扮演K的角色,第一个节点在到Y的蓝色路径上的顺序小于B。在其他拓扑中,A将扮演L的角色,第一个节点在到Y的红色路径上的顺序大于B。基本问题是,我们无法根据顺序关系区分这两种情况。

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.8节所述,我们使用本文中的算法构造的GADAG不是任意的GADAG。它们还有一个附加属性,即到localroot的传入链接只来自同一块中的另一个节点。这是施工方法的结果。此附加属性保证localroot A永远不会在Y的红色路径中扮演L的角色,因为L必须在GADAG的同一块中至少有两个来自不同节点的传入链接。这反过来允许Select_Proxy_Node_NHs()选择到Y的红色路径和到X的红色路径作为到达P的不相交MRT路径。

5.9.4. Computing MRT Alternates for Proxy-Nodes
5.9.4. 计算代理节点的MRT替换

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.

在找到给定代理节点P的红色和蓝色下一跳之后,有必要知道在出现故障时使用其中哪一个。这可以通过选择_Alternates_Proxy_Node()完成,如图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'

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如果F是A,F是B:返回“PRIM_nhu是”如果F是A,则返回“使用红色”:返回“使用蓝色”

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'

如果不在公共块(A,B):如果在公共块(F,A):返回“使用红色”elif在公共块(F,B):返回“使用蓝色”否则:返回“使用红色或蓝色”如果(不在公共块(F,A)而不在公共块(F,A)):返回“使用红色或蓝色”

      alt_to_X = Select_Alternates(X, F, primary_intf)
      alt_to_Y = Select_Alternates(Y, F, primary_intf)
        
      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 (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 (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)
        
          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'
        
          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':
        
                          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)
        
                          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)
        
                  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()

图29:Select\u Alternates\u Proxy\u 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.

Select_Alternates_Proxy_Node(P,F,primary_intf)确定在节点F(可能还有节点F)的主_intf出现故障时,使用P的蓝色路径(穿过X)和P的红色路径(穿过Y)是否安全。基本方法是运行Select_Alternates(X,F,primary_intf)和Select_Alternates(Y,F,primary_intf),以确定到X的两条MRT路径中的哪一条以及到Y的两条MRT路径中的哪一条在F发生故障时可以安全使用。通常,我们会发现,如果在F发生故障时使用到X或Y的特定路径是安全的,并选择_Proxy_Node_NHs(),在构建到达P的红色或蓝色路径时使用该路径,那么在F失败时使用该路径到达P也是安全的。这条规则有一个例外,如下所述。首先,我们给出一个具体示例,说明在常见情况下,Select_Alternates_Proxy_Node()是如何工作的。

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.

Select_Proxy_Node_NHs()中使用的21种排序关系在Select_Alternates_Proxy_Node()中重复。我们将重点关注案例4.1.1,以给出Select_Alternates_Proxy_Node()中使用的详细推理示例。在Select_Proxy_Node_NHs()中,我们确定在案例4.1.1中,红色下一跳到X,蓝色下一跳到Y允许我们通过不相交的路径到达X和Y,因此是蓝色和红色下一跳到P。因此,如果Select_交替(X,F,primary_intf)运行,我们发现使用_red到达X是安全的,然后我们还得出结论,当F失效时,使用通过X的捷运路径到达P(到P的蓝色路径)是安全的。类似地,如果我们运行Select_Alternates(Y,F,primary_intf),并且我们发现使用_BLUE到达Y是安全的,那么我们还得出结论,当F失败时,使用MRT路径通过Y到达P(红色路径到P)是安全的。如果在Select_Proxy_Node_NHs()中用于构造P的蓝色和红色路径的两条路径都被发现可以安全地用于到达X和Y,t,那么我们得出结论,我们可以使用红色或蓝色路径到达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.

这种简单的推理在大多数情况下给出了正确的答案。但是,当A或B(但不是A和B)与S无序时,需要额外的逻辑。这适用于情况4.1.3、4.2.3、4.3.1和4.3.2。更详细地看案例4.1.3,A的顺序小于S,但B相对于S是无序的。在上面案例4.1.3的讨论中,我们看到Select_Proxy_Node_NHs()选择到达Y的红色路径和到达X的红色路径。我们还看到,到达Y的红色路径将沿着不断增加的下一个跃点到达localroot,直到到达排序大于B的某个节点(L),然后再减少下一个跃点到B。问题是,到达P的红色路径(通过Y的路径)不一定与到达Y的红色路径相同。这是因为节点L为其到达P的红色下一跃点计算的下一跃点可能不同于为其到达Y的红色下一跃点计算的下一跃点。这是因为B的顺序低于L,所以L适用于Select_Proxy_node_NHs()的情况4.1.2为了确定到达P的下一个跃点。如果A.topo_顺序<B.topo_顺序(案例4.1.2.1),则L将选择将下一个跃点直接减少到B,这与L在Compute_MRT_NextHops()中计算的结果相同,以达到Y。但是,如果A.topo_顺序>B.topo_顺序(案例4.1.2.2),则L将选择增加下一个跃点以达到B,这与L在Compute_MRT_NextHops()中计算的到达Y的路径不同。因此,在这种情况下,测试S在F失败时到达Y的路径的安全性作为使用红色路径到达P的安全性的替代是不可靠的。即使到Y的红色路径没有到达F,也可以在P的红色路径到达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.

幸运的是,我们已经计算出的订单关系中有足够的信息,仍然可以确定在这四种情况下选择哪种备选方案。基本思想是始终选择涉及有序节点的路径,除非该路径会击中F。回到案例4.1.3,我们看到,由于A的顺序低于S,S击中F的唯一方法是使用到A的简单递减路径,使F位于GADAG上的A和S之间。在案例4.1.3.1中,要求F低于S(但也不高于S)且F.topo_顺序>A.topo_顺序涵盖了该场景。

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

我们只需要确认在这个场景中使用涉及B的路径是安全的。在案例4.1.3.1中,F在GADAG上介于A和S之间,或者F相对于A无序,并且位于从S到localroot的递减路径上。当F在GADAG上的A和S之间时,选择B的路径以避免In SelpTyPro XYONDENH NHSH()将避免F。当F相对于A是无序的并且位于从S到Load Road的递减路径时,那么我们考虑两种情况。要么F.topo_顺序<B.topo_顺序,要么F.topo_顺序>B.topo_顺序。在第一种情况下,由于F.topo_顺序<B.topo_顺序和F.topo_顺序>A.topo_顺序,它必须是

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.

A.topo_顺序<B.topo_顺序的情况。因此,L将选择将下一跳数直接减少到B(情况4.1.2.1),因为F.topo_顺序<B.topo_顺序,所以不能达到F。在第二种情况下,当F.topo_顺序>B.topo_顺序时,涉及B的路径到达F的唯一方式是从L到B再到F,即,它必须是L>>F>>B。然而,由于S>>F,这意味着S>>B。然而,我们知道S相对于B是无序的,因此第二种情况不会发生。因此,我们已经证明,在4.1.3.1的条件下,P的红色路径(通过B和Y)是安全的。类似的推理也适用于其他三种特殊情况,其中A或B相对于S是无序的。

6. MRT Lowpoint Algorithm: Next-Hop Conformance
6. MRT低点算法:下一跳一致性

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.

本规范定义了MRT低点算法,该算法包括构建公共GADAG和计算图中每个节点的MRT Red和MRT Blue下一跳。一个实现可以为MRT Red和MRT Blue选择下一跳的任何子集,该子集与第5.7节中针对MRT Red和MRT Blue中的每个MRT Red和MRT Blue描述的可用节点有关,并且所选择的下一跳在朝向目的地的允许节点间隔内更进一步。

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].

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].translate error, please retry

Implementations SHOULD implement the Select_Alternates() function to pick an MRT-FRR alternate.

实现应该实现Select_Alternates()函数来选择MRT-FRR替代方案。

7. Broadcast Interfaces
7. 广播接口

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.

当广播接口用于连接节点时,广播网络必须表示为伪节点,其中每个真实节点连接到伪节点。从实节点到伪节点方向上的接口度量为非零接口度量,而从伪节点到实节点方向上的接口度量设置为零。这与is-is和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.

伪节点必须被视为与MRT低点算法中使用的网络图中的真实节点等效,以下将详细介绍一些例外情况。

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

伪节点必须包含在GADAG的计算中。伪节点的邻居需要知道虚拟节点的mrt_node_id

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.

伪节点,以便一致地对接口进行排序,这是计算GADAG所需的。IS-IS的mrt_node_id是TLV 22或TLV 222中的7-octet邻居系统id和伪节点号。OSPFv2的mrt_node_id是在路由器LSA中链路类型2(传输网络)的链路id字段中找到的指定路由器的4-octet接口地址。OSPFv3的mrt_node_id是在路由器LSA中链路类型2(传输网络)的邻居接口id字段中找到的指定路由器的4个八位字节接口地址。注意,这与图15中给出的OSPFv3路由器LSA中用于点到点链路的mrt_节点_ID的邻居路由器ID字段不同。

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.

伪节点不得被视为作为GADAG根选择的候选节点。此规则旨在通过消除广播网络上指定路由器或指定中间系统的更改可能导致GADAG根更改的可能性,从而实现更稳定的网络范围内GADAG根选择。

7.1. Computing MRT Next Hops on Broadcast Networks
7.1. 在广播网络上计算MRT下一跳

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.

有趣的是,这个问题并非MRT算法所独有,但在IGP的正常SPF计算中也会遇到。[RFC2328]第16.1.1节描述了如何为OSPF实现这一点。当OSPF运行其最短路径树计算时,它以以下方式处理伪节点。每当计算路由器发现到达真实目的地节点的较短路径且到目的地的较短路径是单个伪节点跳时,则该目的地的下一跳从路由器LSA中对应于到真实目的地节点的链路的接口IP地址中取得。

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.

对于IS-IS,在[ISO10589第二版]附录C中Dijkstra算法的伪代码实现示例中,每当算法遇到从实节点到伪节点的邻接时,它就会转换为从实节点到伪节点邻居的一组邻接。通过这种方式,计算出的下一跳将一直指向真实节点,而不是伪节点。

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.

通过将广播网络的伪节点表示转换为同一网络上真实节点之间链路的完整网格,我们可以避免确定MRT中伪节点的下一跳的问题。然而,如果我们在计算GADAG之前进行转换,我们将丢失有关哪些链路实际上对应于广播网络中的单个物理接口的信息。这可能导致计算使用相同广播接口的红色和蓝色下一跳,在这种情况下,红色和蓝色下一跳在广播接口故障时都不能用作备用。

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.

取而代之的是,我们采用以下方法,即如果拓扑允许,则保持红色和蓝色下一跳将避开广播网络的属性。我们运行MRT低点算法,将伪节点视为网络图中真实节点的等价物,但上述例外情况除外。除了从自身的角度运行MRT低点算法外,连接到伪节点的计算路由器还必须从其每个伪节点邻居的角度运行MRT低点算法。例如,如果计算路由器S确定其到达目的地D的MRT红色下一跳是伪节点P,则S从P的角度查看其MRT低点算法计算,以确定P到达目的地D的红色下一跳,假设节点X.S上的接口1现在知道它到达D的真正红色下一跳是广播网络上节点X上的接口1,它可以在其FIB中安装相应的条目。

7.2. Using MRT Next Hops as Alternates in the Event of Failures on Broadcast Networks

7.2. 在广播网络出现故障时,使用MRT下一跳作为备用

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.

在上一节中,我们指定了当涉及广播网络时如何计算MRT下一跳。在本节中,我们将讨论PLR如何在涉及广播网络的故障事件中使用这些MRT下一跳。

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

连接到仅运行OSPF或IS-IS且Hello间隔较大的广播网络的PLR在快速检测广播网络故障方面的能力有限。可以快速检测到的唯一故障模式是将PLR连接到广播网络的物理接口故障。对于将PLR连接到广播网络的接口故障,可通过在Select_Alternates()中将广播网络伪节点用作F(主下一跳节点)来计算避免广播网络的备用节点。这将选择避免广播网络的备用路径。然而,备用路径不一定会避开连接到广播网络的所有真实节点。这是因为我们使用了伪节点来表示广播网络。我们已经强制执行了节点保护

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.

伪节点上的MRT属性,用于针对广播网络而不是广播网络上的真实下一跳节点的故障提供保护。如果广播接口故障是PLR可以响应的唯一故障模式,则这是我们希望做到的最好的方法。

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.

如果PLR还能够快速检测到广播网络与给定IP层节点之间缺乏连接,则我们可以对此进行改进。这可以通过在广播网络上的所有IGP邻居对之间运行BFD来实现。注意,在OSPF的情况下,这需要在双向状态下的所有相邻对之间建立BFD会话。当PLR能够快速检测到广播网络中特定下一跳的故障时,PLR可以在其备选方案的选择中更具选择性。例如,当PLR观察到与广播网络上的IP层节点的连接已经失败时,PLR可以选择仍然使用广播网络来到达仍然可以到达的其他IP层节点。或者,如果PLR观察到与同一广播网络上的多个IP层节点的连接失败,则它可以选择将整个广播网络视为失败。对于一组特定的故障条件,由PLR交替选择MRT是一个局部决策,因为它不需要与其他节点协调。

8. Evaluation of Alternative Methods for Constructing GADAGs
8. 评估构建GADAG的替代方法

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.

本文件规定了MRT低点算法。该算法的一个组成部分涉及基于网络拓扑构造公共GADAG。MRT低点算法使用第5.5节中描述的方法计算GADAG。该方法旨在最小化计算GADAG所需的计算量。在开发MRT低点算法的过程中,还考虑了构建GADAG的两种备选方法。附录B和附录C中描述了这些替代方法。通常,这两种方法需要更多的计算来计算GADAG。进行以下分析,以确定替代GADAG施工方法是否会在实际网络拓扑中产生较短的MRT替代路径,如果是,程度如何。

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.

图30比较了使用三种不同方法在五种不同的服务提供商网络拓扑上构建GADAG的结果。MRT_LOWPOINT表示第5.5节中规定的方法,而MRT_SPF和MRT_HYBRID分别表示附录B和附录C中规定的方法。右侧的列显示了每种GADAG施工方法的备用路径长度分布。每个MRT计算均使用基于中心性选择的相同GADAG根进行。

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.

对于所分析的三种拓扑(T201、T206和T211),与MRT_低点法相比,使用MRT_SPF或MRT_混合方法似乎不会提供明显更短的备用路径长度。然而,对于其中两种拓扑(T216和T219),使用MRT_SPF方法比使用MRT_LOWPOINT或MRT_HYBRID方法产生的备用路径长度明显更短。

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.

决定使用MRT_LOWPOINT方法在本文件规定的算法中构造GADAG,以便最初提供计算要求较低的算法。这些结果表明,在未来,评估并潜在地指定使用不同GADAG构造方法的其他MRT低点算法变体可能是有用的。

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

图30:各种GADAG施工方法的备用路径长度

9. Operational Considerations
9. 业务考虑

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].

本节讨论与MRT低点算法和其他潜在MRT算法变体相关的操作注意事项。有关与MRT-FRR相关的一般操作注意事项的讨论,请参阅[RFC7812]的“操作注意事项”一节。

9.1. GADAG Root Selection
9.1. GADAG根选择

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.

默认MRT配置文件使用路由器公布的GADAG根选择优先级作为选择GADAG根的主要标准。建议运营商通过将路由器组的GADAG根选择优先级设置为更低(更优选)的数值,将一组路由器指定为选择GADAG根的良好选择。下文讨论了进行该指定的标准。

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.

分析表明,路由器的中心性对计算的备用路径的长度有重大影响。因此,建议使用考虑路由器中心性的离线分析来帮助确定特定路由器对于GADAG根角色的选择。

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.

如果当前选择为GADAG根的路由器在IGP拓扑中变得不可访问,则将选择新的GADAG根。改变GADAG根可以改变GADAG的整体结构以及使用GADAG构建的红色和MRT蓝色树的路径。为了最大限度地减少因更改GADAG根而导致的相关红色和MRT蓝色转发条目的更改,建议运营商优先选择预期始终属于IGP拓扑的路由器作为GADAG根。

9.2. Destination-Rooted GADAGs
9.2. 目的地扎根加达格

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.

MRT Lowpoint算法在选定为GADAG根的单个节点上构造一个根为GADAG的单个GADAG。也可以为每个目的地构建不同的GADAG,GADAG根在目的地。路由器可以根据根在该目的地的GADAG计算该目的地的MRT Red和MRT Blue下一跳。为每个目的地构建不同的GADAG在计算上比较昂贵,但它可能会提供更短的备用路径。使用基于目的地的GADAG需要使用新的MRT算法规范创建新的MRT配置文件,因为MRT岛上的所有路由器都需要使用基于目的地的GADAG。

10. Security Considerations
10. 安全考虑

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].

除了描述MRT FRR体系结构的文件[RFC7812]中已经讨论的安全问题外,本文件中描述的算法没有引入新的安全问题。

11. References
11. 工具书类
11.1. Normative References
11.1. 规范性引用文件

[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>.

[RFC2119]Bradner,S.,“RFC中用于表示需求水平的关键词”,BCP 14,RFC 2119,DOI 10.17487/RFC2119,1997年3月<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>.

[RFC7812]Atlas,A.,Bowers,C.,和G.Enyedi,“使用最大冗余树的IP/LDP快速重路由架构(MRT-FRR)”,RFC 7812,DOI 10.17487/RFC7812,2016年6月<http://www.rfc-editor.org/info/rfc7812>.

11.2. Informative References
11.2. 资料性引用

[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>.

Enyedi,G,“IP快速重路由新算法”,布达佩斯技术与经济大学电信与媒体信息学系,博士。论文,2011年2月<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>.

[IEEE8021Qca]IEEE,“局域网和城域网IEEE标准-网桥和桥接网络-修改件24:路径控制和保留”,IEEE 802.1Qca-2015,DOI 10.1109/IEEESTD.2016.74345442016<https://standards.ieee.org/findstds/ 标准/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.

[ISO10589第二版]国际标准化组织,“与提供无连接模式网络服务的协议一起使用的中间系统到中间系统域内路由信息交换协议(ISO 8473)”,ISO/IEC 10589:2002,第二版,2002年11月。

[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>.

[Kahn_1962_topo_sort]Kahn,A.“大型网络的拓扑排序”,《ACM通讯》,第5卷,第11期DOI 10.1145/368996.3690251962年11月<http://dl.acm.org/citation.cfm?doid=368996.369025>.

[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>.

[MRTLinear]Enyedi,G.,Retvari,G.,和A.Csaszar,“关于在严格线性时间内寻找最大冗余树”,IEEE计算机与通信研讨会(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>.

[RFC2328]Moy,J.,“OSPF版本2”,STD 54,RFC 2328,DOI 10.17487/RFC2328,1998年4月<http://www.rfc-editor.org/info/rfc2328>.

Appendix A. Python Implementation of MRT Lowpoint Algorithm
附录A.MRT低点算法的Python实现

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

下面是实现本文档中指定的MRT低点算法的Python代码。代码也发布在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.

虽然此Python代码被认为正确实现了算法的伪代码描述,但在出现差异的情况下,伪代码描述应被视为规范。

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

<CODE BEGINS>#该程序已经过测试,可以在Python2.6和2.7上运行(特别是Python2.6.6和2.7.8已经过测试)该程序已知与Python3.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.

#执行时,该程序将生成一个文本文件,描述一个示例拓扑。然后将该文本文件读回作为输入,以创建示例拓扑,并运行MRT低点算法这样做是为了简化将程序作为一个可从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.

#该程序的输出是四个文本文件,其中包含GADAG的描述、所有目的地的蓝色和MRT红色以及所有故障的MRT交替。

import random import os.path import heapq

导入随机导入os.path导入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 = {}
        
# 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 = {}
        
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 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
        
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
        

self.PROCESSED = False

自我处理=错误

class Bundle:
    def __init__(self):
        self.UNDIRECTED = True
        self.OUTGOING = False
        self.INCOMING = 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 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 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 = {}
        
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:

def Interface_Compare(intf_a,intf_b):如果intf_a.metric<intf_b.metric:返回-1如果intf_b.metric<intf_a.metric:如果intf_a.remote\u node.node\u id<intf_b.remote\u node.node\u id:

return -1 if intf_b.remote_node.node_id < intf_a.remote_node.node_id: return 1 return 0

如果intf_b.remote_node.node_id<intf_a.remote_node.node_id,则返回-1:返回0

def Sort_Interfaces(topo): for node in topo.island_node_list: node.island_intf_list.sort(Interface_Compare)

def Sort_Interfaces(topo):对于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()

def Reset_Computed_Node_和_Intf_值(topo):topo.Node_列表中节点的topo.init_new_computing_路由器():Node.Intf_列表中Intf的Node.init_new_computing_路由器())

# 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.

#此函数获取一个文件,其中的链接由两位数字表示,格式为:#01,05,10#05,02,30#02,01,15#,表示节点为01,05和02#的三角形拓扑,对称度量为10,30和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()
        
# 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()
        
        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
        
        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):
        
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):
        

intf.remote_INTF.IN_MRT_ISLAND = True explore_list.append(intf.remote_node)

intf.remote\u intf.IN\u MRT\u ISLAND=True explore\u list.append(intf.remote\u节点)

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 Computed_Island_Node_List_For_Test_GR(拓扑,Test_GR):重置计算的节点和输入值(topo)topo.Test_GR=topo.Node_dict[Test_GR]MRT_岛标识(topo,topo.Test_GR,0,0),用于topo.Node_列表中的节点:if Node.in_MRT_岛:topo.Island_Node_List_用于测试_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)

def Set_Island_Intf_和_Node_列表(topo):对于topo.Node_列表中的节点:if Node.in_MRT_Island:topo.Island_Node_列表中的Intf追加(Node)。Intf_列表:if Intf.in_MRT_Island:Node.Island_Intf列表追加(Intf)

global_dfs_number = None
        
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
        
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
        

def Run_Lowpoint(topo): global global_dfs_number global_dfs_number = 0 Lowpoint_Visit(topo.gadag_root, None, None)

def Run_Lowpoint(地形):全局全局_dfs_编号全局_dfs_编号=0低点_访问(topo.gadag_根,无,无)

max_block_id = 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 Assign_Block_ID(x,cur_Block_ID):全局max_Block_ID x.Block_ID=x.dfs_child_列表中c的cur_Block_ID:if(c.localroot为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 Run_Assign_Block_ID(topo):全局最大块ID最大块ID=0 Assign_Block_ID(topo.gadag_根,最大块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
        
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:

如果ear#U type==“CHILD”且cur_intf.remote_节点为x:#x为剖切顶点,且计算ear的块的局部根为x。is_cut_vertex=True localroot=x,否则:

# inherit local root from the end of the ear localroot = cur_intf.remote_node.localroot

#从ear的末尾继承本地根localroot=cur\u intf.remote\u node.localroot

    while ear_list != []:
        y = ear_list.pop()
        y.localroot = localroot
        stack.append(y)
        
    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 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 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:
        
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:
        

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

bundle.INCOMING=True if intf2.outing:bundle.outing=True if bundle.UNDIRECTED:for bundle\u列表中的intf3:intf3.UNDIRECTED=False intf3.remote\u intf.UNDIRECTED=False intf3.PROCESSED=True intf3.remote\u intf.PROCESSED=True intf3.outing=True intf3.remote\u intf.infounding=True其他:if(bundle.outing和bundle.inbound):对于bundle\u列表中的intf3:intf3.unddirected=False intf3.remote\u intf.unddirected=False intf3.PROCESSED=True intf3.remote\u intf.PROCESSED=True intf3.outing=True intf3.remote\u intf.inbounding=True intf3.remote\u intf.outing=True elif bundle.outing:对于bundle\u列表中的intf3:intf3.unddirected=Falseintf3.remote\u intf.unddirected=False intf3.PROCESSED=True intf3.remote\u intf.PROCESSED=True intf3.outing=True intf3.remote\u intf.inbound=True elif bundle.inbound:for intf3 in bundle\u列表:intf3.unddirected=False intf3.remote\u intf.unddirected=False intf3.PROCESSED=True intf3.remote\u intf.PROCESSED=True intf.PROCESSED=True intf3.remote\u intf.PROCESSED=True intfintf3.remote\u 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
        
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
        

intf.remote_intf.OUTGOING_STORED = True

intf.remote\u intf.OUTGOING\u storage=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 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 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:

def Set_Other_Undirected_Links_Based_On_Topo_Order(Topo):对于Topo.island_node_列表中的节点:对于node.island_intf列表中的intf:if intf.Undirected:if node.Topo_Order<intf.remote_node.Topo_Order:intf.outing=True intf.Undirected=False intf.remote_intf.intf=True intf.Undirected=False其他:

intf.INCOMING = True intf.UNDIRECTED = False intf.remote_intf.OUTGOING = True intf.remote_intf.UNDIRECTED = False

intf.INCOMING=True intf.UNDIRECTED=False intf.remote\u intf.outing=True intf.remote\u 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 Initialize_Temporary_Interface_Flags(topo):对于topo.island_node_列表中的节点:对于node.island_intf_列表中的intf:intf.PROCESSED=False intf.INCOMING_STORED=False intf.outing_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 Add_Undirected_Links(topo):初始化_临时_Interface_Flags(topo)Add_Undirected_Block_Root_Links(topo)Run_拓扑_Sort_GADAG(topo)设置_其他_Undirected_Links_基于_topo_顺序(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

_Common_块(x,y)中的def:if((x.Block_id==y.Block_id)或(x是y.localroot)或(y是x.localroot)):返回True返回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 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添加项目到项目列表(如果新)(目标项目列表,项目):如果项目不在目标项目列表中:目标项目列表。追加(项目)

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)
        
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)
        
# 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)
        
# 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:
        
def Normal_SPF(topo, spf_root):
    spf_heap = []
    for y in topo.node_list:
        
        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)
        
        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 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

def Compute_MRT_NH_For_One_Src_To_Island_Dests(地形,x):对于地形中的y.Island_节点_列表:y.HIGHER=False y.LOWER=False

        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)
        
        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

#继承x的MRT next hops到达GADAG根#从x的MRT next hops到达其局部根#,但首先检查x是否为GADAG根(在这种情况下#x没有局部根),或者x的局部根#是否为GADAG根(在这种情况下,我们已经有了#x的MRT next hops到达GADAG根)如果x不是topo.gadag_根,x.localroot不是topo.gadag_根:复制列表项(topo.gadag_根.blue_下一跳,x.localroot.blue_下一跳)复制列表项(topo.gadag_根.red_下一跳,x.localroot.red_下一跳)topo.gadag_根.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)

#在topo.island\u node\u列表中为y继承下一个跃点并将_代理排序到其他块:如果(y不是topo.gadag\u根,y不是x):设置_边(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)
        
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)
        

Copy_List_Items(x.red_next_hops_dict[y.node_id], y.red_next_hops)

复制列表项(x.red\U next\U hops\U dict[y.node\U id],y.red\U next\U 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_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_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_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_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 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:

def Select_alternative_Internal(D,F,primary_intf,D_lower,D_higher,D_topo_order):如果D_较高和D_较低:如果F.higher和F.lower:如果F.topo_order>D_topo_order:返回“使用蓝色”否则:如果F.higher返回“使用红色”:

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.

如果F.LOWER返回“USE_RED”如果F.LOWER返回“USE_BLUE”断言(primary_intf.MRT_不合格或primary_intf.remote_intf.MRT_不合格)如果D_较高:如果F.higher和F.LOWER返回“USE_BLUE”如果F.LOWER返回“USE_BLUE”如果F.higher:如果(F.topo_order>D_topo_order)返回“USE_BLUE”如果F.topo:return“USE\u RED”assert(False)assert(primary\u intf.MRT\u不合格或primary\u intf.remote\u intf.MRT\u不合格)return“USE\u RED”if D\u lower:if F.HIGHER和F.lower:return“USE\u RED”if F.lower:if F.topo>D\u topo\u order:return“USE\u BLUE”if F.topo<D\u topo\u order:return“USE\u RED”assert(False)断言(primary_intf.MRT_不合格或primary_intf.remote_intf.MRT_不合格)return'USE_RED_或_BLUE'else:#如果F.较高和F.较低,则D是无序的wrt S:如果primary_intf.传出和primary intf.传入:#当F和D位于不同的块中时可能会发生这种情况如果primary_intf返回'USE_RED_或_BLUE'。传出:如果primary_intf.传入:返回'USE_BLUE'传入:返回'USE_RED'#当primary#捷运大学不合格#在这种情况下,GADAG的特殊结构允许我们选择红色,而对于任意的GADAG,红色和蓝色都不能保证工作。

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'

assert(primary_intf.MRT_不合格或primary_intf.remote_intf.MRT_不合格)如果F.LOWER:return“USE_RED”如果F.HIGHER:return“USE_RED”如果F.topo订单>D_订单:return“USE_BLUE”:return“USE_BLUE”assert(primary_intf.MRT_不合格或primary_intf.remote_intf.MRT_不合格)如果F订单>D_订单: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 Select_Alternates(D,F,primary_intf):S=primary_intf.local_node如果不在公共块(F,S):如果(D是F)或(D.order_proxy是F)返回“PRIM_nhu In_In_DIFFERENT_Block”如果(D是F)或(D.order_proxy是F):返回“PRIM_nhu is_D_D_is_D_”或“D”OP_lower=D.order\u proxy.lowere D\u higher=D.order=D.order\u proxy.higher=D\u委托代理选择内部委托”(D,F,主输入,D低,D高,D拓扑顺序)

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是intf列表中的远程节点(节点,intf列表):对于intf列表中的intf:如果节点是intf。远程节点:返回True返回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:
        
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:
        

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'

alt.info=Select_Alternates(D、F、failed_intf)else:#主下一跳不在MRT岛中#红色或蓝色都会避开主下一跳,因为主下一跳甚至不在#GADAG中。alt.info='使用红色或蓝色'

            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)
        
            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,

#使用Is_Remote_Node_In_nhu_List(),而不是只检查failed_intf是否为D.red_next_hops,

                # 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'
        
                # 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)

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_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)
        
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)
        
                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);
        
                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将所有目的地的所有目的地写入文件(拓扑,文件前缀):将所有目的地的所有目的地写入文件(拓扑,“蓝色”,文件前缀)将所有目的地的所有目的地写入文件(拓扑,“红色”,文件前缀)

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()
        
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()
        

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);

filename=file_prefix+“_alts_to_all.csv”,打开(filename,'w')作为alt_文件:alt_file.write('gadag_root,dest,'\'prim_nh.local_节点,prim_nh.remote_节点,'\'prim_nh.link_数据,alt_nh.local节点,'\'alt_nh_远程_节点,alt_.nh_链接数据,'\'alt_nh_nh.fec\n'),用于边缘列表中的边缘字符串:alt_file.write(边缘字符串);

def Raise_GADAG_Root_Selection_Priority(topo,node_id): node = topo.node_dict[node_id] node.GR_sel_priority = 255

def Raise_GADAG_Root_Selection_Priority(拓扑,节点id):节点=拓扑。节点dict[节点id]节点。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 Lower_GADAG_Root_Selection_Priority(拓扑,节点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 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 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:
        
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:
        

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

打印(“跳过前缀文件的下一行”)打印(“前缀id应介于2000和2999之间”)打印(行)继续前缀节点id=int(cols[1])前缀成本=int(cols[2])广告节点=topo.node\u dict[prefix\u node\u id]广告节点前缀成本dict[prefix\u id]=前缀成本

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为非岛节点(topo)添加前缀:为topo.node列表中的节点添加前缀:如果node.in岛节点:continue prefix\u id=node.node\u id+1000 node。prefix\u cost\u dict[prefix\u 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 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
        
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
        
        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
        
        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()
        
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()
        
                topo.named_proxy_dict[prefix] = P
                P.node_id = prefix
                P.node_prefix_cost_list = [(node,prefix_cost)]
        
                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)
        
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)

对于地形图中的岛屿编号。岛屿编号集:岛屿编号SPF(地形图,岛屿编号)

    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) )
        
    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:
        
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:
        
                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)
        
                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])
        
    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 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]

def选择_Proxy_Node_Attachment_Routers(topo):作为topo中的前缀。命名_Proxy_dict:P=topo。命名_Proxy_dict[前缀]

        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
        
        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

P.pnar1=第一个pnar P.pnar2=第二个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 Attach_Named_Proxy_Nodes(topo):计算_Loop_Free_Island_neights_For_Each_Prefix(topo)计算_Island_Border_Router_LFIN_Pairs_For_Each_Prefix(topo)选择_Proxy_Node_Attachment_Router(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
        
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): #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")

B=Y.order_proxy if(A是S.localroot,B是S.localroot):#打印(“1.0”)复制_列表_项(P.blue_next_hops,X.blue_next_hops)复制_列表_项(P.red_next_hops,Y.red_next_hops)如果(A是S.localroot,B不是S.localroot)返回:#打印(“2.0”)如果B.LOWER:#打印(“2.1”)复制_列表_项(P.blue hopu next,X.hopu)复制_项(P.red_next_hops,Y.red_next_hops)返回如果B.HIGHER:#打印(“2.2”)复制列表项目(P.blue_next_hops,X.red_next_hops)复制列表项目(P.red_next_hops,Y.blue_next_hops)返回其他:#打印(“2.3”)复制列表项目(P.blue_next hops,X.red_next_hops)复制列表项目(P.blue_next_hops,X.red_next_hops)返回(A不是S.Loca根,B是S.Loca根。A不是S.Loca根,B是S.Loca根。A是S.Loca根。A不是S.Loca根,B是S.Loca根。A是S.Loca根。A是S.Loca根,B是S.Loca根,B是S.Loca根。A是:若A.LOWER:(3.1)打印(3.1)复制(3.1)拷贝(3.1)复制(3.1)列表)清单(列表)项目(P.B)项目(P.blue(P.blue(P.BlueU下一个下一个下一个下一个下一跳跳,P.B是S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S 3.3“)复制列表项(P.blue\u next\u hops,X.red\u next\u hops)复制列表项(P.red\u next\u hops,Y.red\u next\u hops)如果(A不是S.localroot,B不是S.localroot)返回:#如果(S是A.localroot或S是B.localroot)打印(“4.0”):#打印(“4.05”)

            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
        
            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
        
            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)
        
            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)

def Compute_MRT_NHs_For_One_Src_To_Named_Proxy_Nodes(topo,S):topo.Named_Proxy_dict:P=topo.Named_Proxy_dict[prefix]if P.pnar2==None:if S是P.pnar1.node:#将PNAR的MRT下一跳设置为#到达LFIN并将FEC更改为绿色复制_列表项(P.blue_next hops,P.pnarf.intu)设置为绿色节点id[P]=真实复制列表项(P.red\u next\u hops,P.pnar1.nh\u intf\u List)

                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
        
                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'

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如果F是A,F是B:返回“PRIM_nhu是”如果F是A,则返回“使用红色”:返回“使用蓝色”

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'

如果不在公共块(A,B):如果在公共块(F,A):返回“使用红色”elif在公共块(F,B):返回“使用蓝色”否则:返回“使用红色”或“蓝色”

if (not In_Common_Block(F, A) and not In_Common_Block(F, A) ): return 'USE_RED_OR_BLUE'

如果(不在公共块(F,A)和公共块(F,A)中):返回“使用红色或蓝色”

    alt_to_X = Select_Alternates(X, F, primary_intf)
    alt_to_Y = Select_Alternates(Y, F, primary_intf)
        
    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 (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")
        
    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")
        
            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'
        
            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'
        
                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
        
                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
        
                    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'
        
                    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'
        
        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)
        
        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:
        
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:
        

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)

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:对于adv_node中的nh_intf。primary_next_hops:如果新(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)
        
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
        
            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
        
                    # 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'
        
                    # 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
        
            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
        
                    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'
        
                    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)

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)

定义一个源(topo,src)的运行基本MRT:MRT岛标识(topo,src,0,0)集合岛和节点列表(topo)集合GADAG根(topo,src)排序接口(topo)运行低点(topo)分配剩余低点父母(topo)通过低点(topo)运行分配块ID(topo)添加无定向链接(topo)计算一个Src到岛目的地(拓扑,Src)存储区的MRT到岛目的地(拓扑,Src)存储区的MRT到岛目的地(拓扑,Src)的下一个路径(拓扑,Src)选择一个Src到岛目的地(拓扑,Src)存储区的Alts到岛目的地(拓扑,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 Store_GADAG_和_Named_proxy_Once(topo):用于topo.node_列表中的节点:用于node.intf_列表中的intf:if intf.outing:intf.SIMULATION_outing=True其他:intf.SIMULATION_outing=False用于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)

def Run_Basic_MRT_for_All_Sources(topo):对于topo.node_列表中的src:Reset_Computed_node_和Intf_Values(topo)Run_Basic_MRT_for_One_Source(topo,src),如果src是topo.gadag_root:Store_gadag_和_Named_Proxies_一次(topo)

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)

定义一个源(拓扑,src)的运行(MRT):MRT岛标识(拓扑,src,0,0)集岛和节点列表(拓扑)集根(拓扑,src)排序接口(拓扑)运行低点(拓扑)分配剩余低点(拓扑)通过低点(拓扑)运行分配块ID(拓扑)添加无方向链接(拓扑)(topo,Src)商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店商店主要和备用商店商店商店商店商店商店商店商店商店商店商店商店主要主要主要和价格价格价格。把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把把从从从从从从从从从从从从从从从从从从从从从从从从从从从从Src到命名的代理节点(拓扑,Src)存储一个Src到命名的代理节点(拓扑,Src)计算一个Src到命名的代理节点(拓扑,Src)的主要NHs到命名的代理节点(拓扑,Src)存储一个Src到命名的代理节点(拓扑,Src)的主要NHs到命名的代理节点(拓扑,Src)选择一个Src到命名的代理节点(拓扑,Src)的主要NHs到命名的代理节点(拓扑,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_Prim_SPF_for_One_Source(拓扑,src):Normal_SPF(拓扑,src)Store_Primary_NHs_for_One_Source_To_Nodes(拓扑,src)创建_Basic_Named_Proxy_Nodes(拓扑)计算_One_src_To_Named_Proxy_Nodes(拓扑,src)Store_Primary_NHs_for_To_Named_Proxy_(拓扑,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)

定义所有源(topo)的运行时间:对于topo.node列表中的src:如果topo.island节点列表中的src用于测试gr,则重置计算的节点值和输入值(topo):#如果src位于测试gr的同一MRT岛中,则src运行MRT;如果src位于topo.gadag根目录中,则为测试gr运行MRT(topo,src);如果src位于topo.gadag根目录中,则存储一次命名的代理(topo)否则:#src仍然运行SPF,如果不在MRT岛运行#Prim#SPF#U一个#U源(地形、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)

def Write_Output_To_Files(topo,file_prefix):Write_GADAG_To_file(topo,file_prefix)Write_两个mrt_For_All Dests_To_file(topo,file_prefix)Write_Alternates_For_All Dests_To_file(topo,file_prefix)

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_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)
        
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 = [[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]]
        
    data = [[2001,05,100],[2001,07,120],[2001,03,130],
            [2002,13,100],[2002,15,110],
            [2003,52,100],[2003,78,100]]
        
    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)
        
    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_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)
        
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()

生成\u基本\u拓扑\u和\u运行\u MRT()

Generate_Complex_Topology_and_Run_MRT()

生成复杂拓扑和运行MRT()

<CODE ENDS>

<代码结束>

Appendix B. Constructing a GADAG Using SPFs
附录B.使用SPF构建GADAG

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.

这种构造GADAG的方法的基本思想是使用稍加修改的SPF计算来找到耳朵。在每个块中,首先进行SPF计算,从局部根中找到一个循环,然后在该块中进行SPF计算,直到没有更多的接口可供探索。SPF计算的使用结果是接口的路径,该路径通过遵循从minimized IN_GADAG节点返回到SPF根的前一跳指示。

To do this, first all cut-vertices must be identified and localroots assigned as specified in Figure 12.

要做到这一点,首先必须确定所有切割顶点,并按照图12中的规定指定localroots。

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.

SPF的轻微修改如下所示。块的根称为块根;它是GADAG根或切割顶点。

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.

a. SPF以IN_GADAG节点y的邻居x为根。y和x之间的所有链接都标记为临时不可用。在SPF计算期间不应使用它们。

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.

b. 如果y不是块根,则它被标记为TEMP_unsable。在SPF计算期间不应使用它。这可以防止耳朵在同一节点开始和结束,并避免循环;例外情况是,从块根到块根的循环是可接受和预期的。

c. Do not explore links to nodes whose localroot is not the block-root. This keeps the SPF confined to the particular block.

c. 不要浏览指向localroot不是块根的节点的链接。这使SPF仅限于特定块。

d. Terminate when the first IN_GADAG node z is minimized.

d. 当第一个IN_GADAG节点z最小化时终止。

e. Respect the existing directions (e.g., INCOMING, OUTGOING, UNDIRECTED) already specified for each interface.

e. 尊重已为每个接口指定的现有方向(例如,输入、输出、无方向)。

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

Mod_SPF(SPF_root,block_root)初始化SPF_heap为空初始化节点的SPF_度量为无穷SPF_root.SPF_度量=0 insert(SPF_heap,SPF_root)在_gadag中找到_=false,而(SPF_heap不为空)和(在_gadag中找到_为false)min_node=remove_最低(SPF_heap)if min_node.IN_GADAG find_IN_GADAG=true,则min_节点的每个接口intf if((intf.outing或intf.UNDIRECTED)和((intf.remote_node.localroot为block_root)或(intf.remote_node为block_root))和(intf.remote_node不是TEMP_不可用)和(intf.remote_不是TEMP_不可用))如果路径度量<intf.remote\u node.spf\u metric intf.remote\u node.spf\u metric=path\u metric intf.remote\u node.spf\u prev\u intf=intf insert\u或更新(spf\u堆,intf.remote\u节点)返回最小节点

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

SPF_for_Ear(cand_intf.local_节点,cand_intf.remote_节点,block_root,method)将cand_intf.remote_节点和cand_intf.local_节点之间的所有接口标记为TEMP_不可用,如果cand_intf.local_节点不是block_root,则将cand_intf.local_节点标记为TEMP_不可用初始化Ear_列表以清空end_Ear=Mod_SPF(SPF_root,block_root)y=end\u ear.spf\u prev\u hop而y.local\u节点不是spf\u根添加到\u列表\u开始(ear\u列表,y)y.local\u节点。IN\u GADAG=true y=y.local\u node.spf\u prev\u intf if(方法不是混合)设置\u ear\u方向(ear\u列表,cand\u intf.local\u节点,end\u ear,block\u根)从cand_intf.remote_节点和cand_intf.local_节点之间的所有接口清除TEMP_不可用从cand_intf.local_节点清除TEMP_不可用返回结束

Figure 31: Modified SPF for GADAG Construction

图31:GADAG结构的修改SPF

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.

假设一个ear是通过从y到x,然后运行一个SPF来找到的,该SPF通过最小化z来终止(例如,y<->x…q<->z)。现在有必要确定耳朵的方向;如果y<<z,则路径应为y->x…q->z;但是如果y>>z,那么路径应该是y<-x…q<-z。在第5.5节中,同样的问题是通过查找从一个节点开始的所有耳朵,然后再查看从偏序中较高的节点开始的耳朵来处理的。在这种GADAG构造方法中,使用这种方法可能意味着不按照总成本的顺序添加新的耳朵,因为在找到其他节点之前,需要找到连接到节点的所有耳朵。

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.

另一种方法是跟踪每个节点相对于每个其他节点的顺序关系。这可以通过在每个节点上维护两组节点来实现。第一个集合,更高的_节点,包含已知在节点上方排序的所有节点。第二组,Lower_Nodes,包含所有已知在节点下方排序的节点。这是GADAG施工方法中使用的方法。

      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
        
      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

图32:分配Ear方向链接的算法

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,

这种GADAG构造方法的目标是找到最短的周期和耳朵。ear通过进入IN_GADAG节点y的邻居x启动。从x到IN_GADAG节点的路径最小,

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.

因为它是通过SPF计算的。由于最短路径由最短路径组成,要找到最短的耳朵,需要从IN_GADAG节点集到达不在IN_GADAG的最近节点。因此,维护了一个有序的接口树,可以从IN_GADAG节点探索这些接口。根据图14中定义的Interface_Compare函数,接口按其度量、本地环回地址、远程环回地址和ifindex的特征排序。

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.

如果接口所在的块已经有一个已计算的ear,则此GADAG构造方法将忽略从属于块根的有序列表中拾取的接口。这是必要的,因为我们最多允许一个传入接口到每个块中的块根。该要求源于第5.7节中所述的计算下一跳的方法。在计算任何ear之后,我们将新添加的节点遍历到GADAG,并将远端尚未在GADAG上的接口插入到有序树中,以供以后处理。

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.

最后,剪切链接是一种特殊情况,因为在两个节点块上执行SPF没有意义。该算法将剪切链接简单地识别为链接的两端都是剪切顶点的链接。剪切链接可以简单地添加到GADAG,并在其接口上指定传出和传入。

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)

如果intf.remote\u node.IN\u GADAG为假插入(intf,ordered\u intfs\u tree),则为节点的每个接口添加\u node的\u合格\u接口(有序的\u intfs\u tree,node)

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

如果((intf.remote\u node.block\u id==block\u id)&&intf.remote\u node.IN\u GADAG)block\u ear=true返回block\u ear,则检查x的所有接口的\u block\u是否有\u ear(x,block\u id)block\u有\u ear=false

     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
        
     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
        
                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
        
                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

图33:GADAG构造的基于SPF的方法

Appendix C. Constructing a GADAG Using a Hybrid Method
附录C.使用混合方法构建GADAG

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.

该方法的思想是结合低点继承和SPF方法的显著特征。为此,我们在将节点添加到GADAG时处理它们,就像在低点继承中一样,通过维护一组节点。这确保了我们不需要在每个节点上保持较低和较高的集合来确定耳朵方向,因为耳朵总是从正在处理的节点指向耳朵的末端。然而,为了计算ear,我们求助于SPF,以获得更好的ear(路径长度)的可能性,从而比限制使用lowpoint/dfs双亲提供更大的灵活性。

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

关于涉及块根的ear,与SPF方法不同,SPF方法在第一个ear之后忽略块根的接口,在混合方法中,我们必须在移动到块中的其他节点之前处理块根的所有接口,因为

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.

耳朵的形状是预先确定的。因此,无论何时块已经计算了ear,并且我们正在处理块根的接口,我们都会在SPF运行计算ear之前将块根标记为不可用。这可确保SPF终止于块根以外的某个节点。这反过来又保证了块根在每个块中只有一个传入接口,这对于正确计算GADAG上的下一个跃点是必要的。

As in the SPF GADAG, bridge ears are handled as a special case.

在SPF GADAG中,桥耳作为特例处理。

The entire algorithm is shown below in Figure 34.

整个算法如下图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

如果L(y)=D(y),则查找_spf_stack_ear(stack,x,y,xy_intf,block_root)//切割链接的特殊情况xy\u intf.UNDIRECTED=false xy\u intf.remote\u intf.UNDIRECTED=false xy\u intf.outing=true xy\u intf.remote\u intf.outing=true xy\u intf.remote\u intf.input=true xy\u intf.remote\u节点。IN\u GADAG=true将y推送到堆栈上返回,如果(y.local\u root==x)&检查块是否有ear(x,y.block\u id)//在SPF标记x为TEMP_UNUSABLE end_ear=SPF_for_ear(x,y,block_root,hybrid)期间避免块根如果x设置为TEMP_UNUSABLE,则清除它cur=end_ear,同时(cur!=y)intf=cur.spf\u prev\u hop prev=intf.local\u node intf.UNDIRECTED=false intf.remote\u intf.UNDIRECTED=false intf.outing=true intf.remote\u intf.INCOMING=true push prev to stack cur=prev xy\u intf.UNDIRECTED=false xy\u intf.remote\u intf.UNDIRECTED=false xy\u intf.outcoming=true xy\u intf.outcoming=true xy\u intf.remote\u intf.INCOMING=true返回

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)

通过混合(拓扑,根)构造\u GADAG\u计算\u Localroot(根,根)分配\u Block\u ID(根,0)root.IN\u GADAG=true初始化堆栈以清空将根推到堆栈上,而(堆栈不为空)x=pop(堆栈)用于x y的每个接口intf=intf.remote\u节点,如果y.IN\u GADAG为false查找\u spf\u堆栈(堆栈,x,y,intf,y.Block\u root)

Figure 34: Hybrid GADAG Construction Method

图34:混合GADAG施工方法

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.

作者要感谢Shraddha Hegde、Eric Wu、Janos Farkas、Stewart Bryant、Alvaro Retana和Deccan(彭少夫)的建议和评论。我们还要感谢Anil Kumar SN在澄清算法描述和伪代码方面提供的帮助。

Authors' Addresses

作者地址

Gabor Sandor Enyedi Ericsson Konyves Kalman krt 11 Budapest 1097 Hungary

加博·桑多尔·恩耶迪·爱立信·科尼维斯·卡尔曼krt 11布达佩斯1097匈牙利

   Email: Gabor.Sandor.Enyedi@ericsson.com
        
   Email: Gabor.Sandor.Enyedi@ericsson.com
        

Andras Csaszar Ericsson Konyves Kalman krt 11 Budapest 1097 Hungary

安德拉斯·卡斯扎尔·爱立信·科尼维斯·卡尔曼krt 11布达佩斯1097匈牙利

   Email: Andras.Csaszar@ericsson.com
        
   Email: Andras.Csaszar@ericsson.com
        

Alia Atlas Juniper Networks 10 Technology Park Drive Westford, MA 01886 United States

美国马萨诸塞州韦斯特福德科技园大道10号Alia Atlas Juniper Networks 01886

   Email: akatlas@juniper.net
        
   Email: akatlas@juniper.net
        

Chris Bowers Juniper Networks 1194 N. Mathilda Ave. Sunnyvale, CA 94089 United States

Chris Bowers Juniper Networks 1194 N.Mathilda Ave.Sunnyvale,加利福尼亚州94089

   Email: cbowers@juniper.net
        
   Email: cbowers@juniper.net
        

Abishek Gopalan University of Arizona 1230 E Speedway Blvd. Tucson, AZ 85721 United States

阿比舍克Gopala亚利桑那大学1230 E高速公路BLVD。美国亚利桑那州图森85721

   Email: abishek@ece.arizona.edu
        
   Email: abishek@ece.arizona.edu