public icon indicating copy to clipboard operation
public copied to clipboard

Adding support for configuration of ECMP of next hops for a static LSP

Open Shashank-arista opened this issue 1 year ago • 14 comments

Change Scope

  • (M) release/models/mpls/openconfig-mpls-static.yang
  • (M) release/models/mpls/openconfig-mpls.yang

Currently, model supports configuration of only a single next hop for a given LSP name. We are adding support to configure multiple next hops by adding a new container next-hops to support backward compatibility. The incoming-label and metric will be used from existing config itself as its common to all next-hops.

     +--rw network-instance* [name]
        +--rw mpls
           +--rw lsps
              +--rw static-lsps
                 +--rw static-lsp* [name]
                    +--rw name       -> ../config/name
                    +--rw config
                    |  +--rw name?   string
                    +--ro state
                    |  +--ro name?   string
                    +--rw ingress
                    |  +--rw config
                    |  |  +--rw incoming-label?   oc-mplst:mpls-label
                    |  |  x--rw next-hop?         inet:ip-address
                    |  |  x--rw push-label?       oc-mplst:mpls-label
                    |  |  +--rw interface?        -> /oc-if:interfaces/interface/name
                    |  |  +--rw subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |  |  +--rw metric?           uint8
                    |  +--ro state
                    |  |  +--ro incoming-label?   oc-mplst:mpls-label
                    |  |  x--ro next-hop?         inet:ip-address
                    |  |  x--ro push-label?       oc-mplst:mpls-label
                    |  |  +--ro interface?        -> /oc-if:interfaces/interface/name
                    |  |  +--ro subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |  |  +--ro metric?           uint8
                    |  +--rw next-hops                                                                                                                                   [36/9557]
                    |     +--rw next-hop* [index]
                    |        +--rw index     -> ../config/index
                    |        +--rw config
                    |        |  +--rw index?          uint32
                    |        |  +--rw ip-address?     inet:ip-address
                    |        |  +--rw push-label?     oc-mplst:mpls-label
                    |        |  +--rw interface?      -> /oc-if:interfaces/interface/name
                    |        |  +--rw subinterface?   -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |        +--ro state
                    |           +--ro index?          uint32
                    |           +--ro ip-address?     inet:ip-address
                    |           +--ro push-label?     oc-mplst:mpls-label
                    |           +--ro interface?      -> /oc-if:interfaces/interface/name
                    |           +--ro subinterface?   -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    +--rw transit
                    |  +--rw config
                    |  |  +--rw incoming-label?   oc-mplst:mpls-label
                    |  |  x--rw next-hop?         inet:ip-address
                    |  |  x--rw push-label?       oc-mplst:mpls-label
                    |  |  +--rw interface?        -> /oc-if:interfaces/interface/name
                    |  |  +--rw subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |  |  +--rw metric?           uint8
                    |  +--ro state
                    |  |  +--ro incoming-label?   oc-mplst:mpls-label
                    |  |  x--ro next-hop?         inet:ip-address
                    |  |  x--ro push-label?       oc-mplst:mpls-label
                    |  |  +--ro interface?        -> /oc-if:interfaces/interface/name
                    |  |  +--ro subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |  |  +--ro metric?           uint8
                    |  +--rw next-hops
                    |     +--rw next-hop* [index]
                    |        +--rw index     -> ../config/index
                    |        +--rw config
                    |        |  +--rw index?          uint32
                    |        |  +--rw ip-address?     inet:ip-address
                    |        |  +--rw push-label?     oc-mplst:mpls-label
                    |        |  +--rw interface?      -> /oc-if:interfaces/interface/name
                    |        |  +--rw subinterface?   -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |        +--ro state
                    |           +--ro index?          uint32
                    |           +--ro ip-address?     inet:ip-address
                    |           +--ro push-label?     oc-mplst:mpls-label
                    |           +--ro interface?      -> /oc-if:interfaces/interface/name
                    |           +--ro subinterface?   -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    +--rw egress
                       +--rw config
                       |  +--rw incoming-label?   oc-mplst:mpls-label
                       |  x--rw next-hop?         inet:ip-address
                       |  x--rw push-label?       oc-mplst:mpls-label
                       |  +--rw interface?        -> /oc-if:interfaces/interface/name
                       |  +--rw subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                       |  +--rw metric?           uint8
                       +--ro state
                       |  +--ro incoming-label?   oc-mplst:mpls-label
                       |  x--ro next-hop?         inet:ip-address
                       |  x--ro push-label?       oc-mplst:mpls-label
                       |  +--ro interface?        -> /oc-if:interfaces/interface/name
                       |  +--ro subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                       |  +--ro metric?           uint8
                       +--rw next-hops
                          +--rw next-hop* [index]
                             +--rw index     -> ../config/index
                             +--rw config
                             |  +--rw index?          uint32
                             |  +--rw ip-address?     inet:ip-address
                             |  +--rw push-label?     oc-mplst:mpls-label
                             |  +--rw interface?      -> /oc-if:interfaces/interface/name
                             |  +--rw subinterface?   -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                             +--ro state
                                +--ro index?          uint32
                                +--ro ip-address?     inet:ip-address
                                +--ro push-label?     oc-mplst:mpls-label
                                +--ro interface?      -> /oc-if:interfaces/interface/name
                                +--ro subinterface?   -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index

Platform Implementations

  • Arista: https://www.arista.com/en/um-eos/eos-mpls-commands#xx1141474 CLI configuration: mpls static top-label top_tag[ bgp peer [peer IP]] [DEST_INTF] NEXTHOP_ADDR ACTION [PRIORITY]

Shashank-arista avatar Jun 23 '24 13:06 Shashank-arista

I would propose to align this with the AFT model and introduce the concept of next-hop-groups.
cc @robshakir, any thoughts on this?

Also, I'm not entirely clear on the support backward compatibility thing. The tree in the description doesn't look like a backward-compatible change to me. Could you elaborate on that?

LimeHat avatar Jun 25 '24 04:06 LimeHat

I would propose to align this with the AFT model and introduce the concept of next-hop-groups. cc @robshakir, any thoughts on this?

Also, I'm not entirely clear on the support backward compatibility thing. The tree in the description doesn't look like a backward-compatible change to me. Could you elaborate on that?

By backward compatibility, I meant the leaves model under (egress | transit | ingress)/config to configure a single next-hop are not being removed to change into a list. Instead, we are introducing a new container for the list of next-hops.

Shashank-arista avatar Jun 25 '24 04:06 Shashank-arista

Ah, I see what you mean.

I don't think it makes too much sense to keep the two (redundant/conflicting) methods in the long term, and the usual procedure of marking the old leafs as deprecated should be used.

LimeHat avatar Jun 25 '24 04:06 LimeHat

Ah, I see what you mean.

I don't think it makes too much sense to keep the two (redundant/conflicting) methods in the long term, and the usual procedure of marking the old leafs as deprecated should be used.

Sure thanks, will update that. Also regarding next-hops, I have tried to use here similar to Static routes

Shashank-arista avatar Jun 25 '24 04:06 Shashank-arista

I'd be happy if we added the concept of NHGs to static-routes too! That makes a lot of sense.

I think you guys support it as well? https://www.arista.com/en/um-eos/eos-nexthop-groups

LimeHat avatar Jun 25 '24 05:06 LimeHat

I'd be happy if we added the concept of NHGs to static-routes too! That makes a lot of sense.

I think you guys support it as well? https://www.arista.com/en/um-eos/eos-nexthop-groups

Yes, next-hop-groups is like an addition/enhancement to next-hops, right? We can still configure a list of next-hops and use them directly without configuring next-hop groups right?

In EOS, we can create a new next-hop each time we run a command: mpls static top-label top_tag [ bgp peer [peer IP]] [DEST_INTF] NEXTHOP_ADDR ACTION [PRIORITY]

Here, we need not use next-hop group

Shashank-arista avatar Jun 25 '24 05:06 Shashank-arista

w.r.t next-hop-groups -- the general benefit of these is if we end up with lots of sharing. I don't see that we necessarily must have the same approach between AFT and the data model used for config (for example, we do not have this for static routes).

robshakir avatar Jun 25 '24 20:06 robshakir

For reference:

  • Cisco XR -- allows multiple path statements docs
  • JUNOS -- allows one next-hop, multiple LSPs possible to the same destination using different "name" docs - this is similar to the current model.
  • SROS -- allows only one next-hop (docs)[https://infocenter.nokia.com/public/7750SR217R1A/index.jsp?topic=%2Fcom.nokia.MPLS_Guide_21.7.R1%2Fconfiguring_a_s-ai9emdyo7e.html]

@LimeHat @earies @rgwilton -- do you have thoughts here?

robshakir avatar Jun 25 '24 20:06 robshakir

the general benefit of these is if we end up with lots of sharing.

yes, and I think we should allow that.

I don't see that we necessarily must have the same approach between AFT and the data model used for config

Not a must, but a uniform approach would be highly beneficial from an implementation point of view. Otherwise, we need to support different ways of "config" (e.g., for gRIBI vs. CLI), which has to be normalized behind the scenes multiple times/in different ways (e.g., for hw programming, for AFT outputs, etc.).

(for example, we do not have this for static routes).

I'd love to see it for static routes as well. :-)

LimeHat avatar Jun 25 '24 20:06 LimeHat

/gcbrun

wenovus avatar Jun 25 '24 21:06 wenovus

No major YANG version changes in commit 75ac876efc7093905b706f7d98a119fbbc8d8ffa

OpenConfigBot avatar Jun 25 '24 21:06 OpenConfigBot

@LimeHat @earies @rgwilton -- do you have thoughts here?

Will revert back shortly - quick passthrough appears to not align well to existing support within our implementation as proposed

earies avatar Jun 26 '24 01:06 earies

w.r.t next-hop-groups -- the general benefit of these is if we end up with lots of sharing. I don't see that we necessarily must have the same approach between AFT and the data model used for config (for example, we do not have this for static routes).

Also Arista implementation doesn't have option to use next-hop group to configure transit labels and its optional for egress labels (https://www.arista.com/en/um-eos/eos-mpls-commands#xx1141474)

Shashank-arista avatar Jun 26 '24 04:06 Shashank-arista

/gcbrun

wenovus avatar Jun 28 '24 19:06 wenovus

To be reviewed on July 30,2024 OC Operators meeting

dplore avatar Jul 24 '24 21:07 dplore

Should this also deprecate the following leafs? This way it's clear the preferred way to configure any/all LSP's is via the next-hops/next-hop subtree.

                    |  |  +--rw interface?        -> /oc-if:interfaces/interface/name
                    |  |  +--rw subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |  |  +--rw metric?           uint8

dplore avatar Jul 24 '24 21:07 dplore

ygot is failing here because after path compression we have duplicate names -- i.e., next-hops/next-hop and state/next-hop are duplicate names in this generated code. Can we select different naming?

robshakir avatar Jul 25 '24 00:07 robshakir

next-hops

To avoid a breaking change we can't rename the existing, to be deprecated leaf so we'll need the newly introduced container and list to use something like lsp-next-hops/lsp-next-hop

dplore avatar Jul 25 '24 00:07 dplore

Should this also deprecate the following leafs? This way it's clear the preferred way to configure any/all LSP's is via the next-hops/next-hop subtree.

                    |  |  +--rw interface?        -> /oc-if:interfaces/interface/name
                    |  |  +--rw subinterface?     -> /oc-if:interfaces/interface[oc-if:name=current()/../interface]/subinterfaces/subinterface/index
                    |  |  +--rw metric?           uint8

Actually, interface and subinterface are marked as deprecated in the changes but they are not getting displayed in pyang due to some issue which is discussed here: https://github.com/openconfig/public/issues/1113

Regarding metric deprecation, incoming-label and metric together is considered as a key for lsp and is same for a route. So we have kept both them under the config as above except others.

Shashank-arista avatar Jul 25 '24 05:07 Shashank-arista

Reviewed with OC Operators on July 30,2024. The following names were proposed. We'll leave this open a couple more days and then should choose one:

Ideas to resolve conflict due to ygot compression:

  • lsp-next-hops/lsp-next-hop # most explicit, uses canonical terms, stutters
  • lsp-nhs/lsp-nh # pretty cryptic still
  • nhs/nh # too cryptic
  • next-nodes/next-node # succinct, doesn’t stutter, node is not the canonical term

dplore avatar Jul 30 '24 16:07 dplore

/gcbrun

dplore avatar Aug 02 '24 23:08 dplore

Reviewed with OC Operators on July 30,2024. The following names were proposed. We'll leave this open a couple more days and then should choose one:

Ideas to resolve conflict due to ygot compression:

  • lsp-next-hops/lsp-next-hop # most explicit, uses canonical terms, stutters
  • lsp-nhs/lsp-nh # pretty cryptic still
  • nhs/nh # too cryptic
  • next-nodes/next-node # succinct, doesn’t stutter, node is not the canonical term

I would be updating the model using the first option: lsp-next-hops/lsp-next-hop

Shashank-arista avatar Aug 07 '24 05:08 Shashank-arista

Reviewed with OC Operators on July 30,2024. The following names were proposed. We'll leave this open a couple more days and then should choose one: Ideas to resolve conflict due to ygot compression:

  • lsp-next-hops/lsp-next-hop # most explicit, uses canonical terms, stutters
  • lsp-nhs/lsp-nh # pretty cryptic still
  • nhs/nh # too cryptic
  • next-nodes/next-node # succinct, doesn’t stutter, node is not the canonical term

I would be updating the model using the first option: lsp-next-hops/lsp-next-hop

I approve, please do submit the change.

dplore avatar Aug 08 '24 19:08 dplore

Reviewed with OC Operators on July 30,2024. The following names were proposed. We'll leave this open a couple more days and then should choose one: Ideas to resolve conflict due to ygot compression:

  • lsp-next-hops/lsp-next-hop # most explicit, uses canonical terms, stutters
  • lsp-nhs/lsp-nh # pretty cryptic still
  • nhs/nh # too cryptic
  • next-nodes/next-node # succinct, doesn’t stutter, node is not the canonical term

I would be updating the model using the first option: lsp-next-hops/lsp-next-hop

I approve, please do submit the change.

Thanks, I have updated the PR with the change.

Shashank-arista avatar Aug 12 '24 05:08 Shashank-arista

/gcbrun

dplore avatar Aug 12 '24 21:08 dplore

Regarding operational use case, Google and others on the Operator group voiced support that this is a real use case in use.

Regarding multiple vendor implementations:

  • Arista static MPLS LSP configuration Repeating this CLI configuration is the method to define multiple next hops in EOS. mpls static top-label top_tag[ bgp peer [peer IP]] [DEST_INTF] NEXTHOP_ADDR ACTION [PRIORITY]

  • Cisco IOS XR has a path command which can be repeated in this example for MPLS over GRE. This looks very similar to the proposed OC model.

Router(config)# mpls static
Router(config-mpls-static)# lsp v4-encap-payload-1
Router(config-mpls-static-lsp)# in-label 10001 allocate per-prefix 111.0.0.1/32
Router(config-mpls-static-lsp)# forward
Router(config-mpls-static-lsp-fwd))# path 1 nexthop tunnel-ip1 out-label 20001
Router(config-mpls-static-lsp-fwd))# path 2 nexthop tunnel-ip2 out-label 20001
Router(config-mpls-static-lsp-fwd))# path 3 nexthop tunnel-ip3 out-label 20001
Router(config-mpls-static-lsp-fwd))# path 4 nexthop tunnel-ip4 out-label 20001
Router(config-mpls-static-lsp-fwd)# commit
  • Juniper: As @robshakir pointed out, Juniper appears to support this in concept, but the implementation is via multiple LSPs to the same destination using different "name" docs

  • Nokia SRLinux appears to support multiple next hops for static lsp

@LimeHat I think adding next-hop-group is also an option. That could be via a separate PR. As Rob pointed out, the precedent with IP static routes uses only a nexthop. So I think this PR follows that precedent which is ok. Internally a NOS is free to construct an AFT using groups to deliver this configured functionality.

dplore avatar Aug 12 '24 22:08 dplore

Last call for comment Aug 20th, 2024

dplore avatar Aug 12 '24 22:08 dplore

Regarding operational use case, Google and others on the Operator group voiced support that this is a real use case in use.

Regarding multiple vendor implementations, it seems there are three, although they are achieved in different ways. Cisco and Arista seem to both support configuring multiple next-hops for a static LSP:

  • Cisco has a path command which can be repeated in this example for MPLS over GRE. This looks very similar to the proposed OC model.
Router(config)# mpls static
Router(config-mpls-static)# lsp v4-encap-payload-1
Router(config-mpls-static-lsp)# in-label 10001 allocate per-prefix 111.0.0.1/32
Router(config-mpls-static-lsp)# forward
Router(config-mpls-static-lsp-fwd))# path 1 nexthop tunnel-ip1 out-label 20001
Router(config-mpls-static-lsp-fwd))# path 2 nexthop tunnel-ip2 out-label 20001
Router(config-mpls-static-lsp-fwd))# path 3 nexthop tunnel-ip3 out-label 20001
Router(config-mpls-static-lsp-fwd))# path 4 nexthop tunnel-ip4 out-label 20001
Router(config-mpls-static-lsp-fwd)# commit
  • Arista static MPLS LSP configuration @Shashank-arista , is repeating this CLI configuration the method to define multiple next hops in EOS? It was not clear to me from the docs. mpls static top-label top_tag[ bgp peer [peer IP]] [DEST_INTF] NEXTHOP_ADDR ACTION [PRIORITY]
  • As @robshakir pointed out, Juniper appears to support this in concept, but the implementation is via multiple LSPs to the same destination using different "name" docs

@LimeHat I think adding next-hop-group is also an option. That could be via a separate PR. As Rob pointed out, the precedent with IP static routes uses only a nexthop. So I think this PR follows that precedent which is ok. Internally a NOS is free to construct an AFT using groups to deliver this configured functionality.

@dplore, yes, repeating the CLI configuration is the method to define multiple next hops in EOS.

Shashank-arista avatar Aug 13 '24 04:08 Shashank-arista

Updated the implementation references, including adding a reference to SRLinux.

dplore avatar Aug 15 '24 00:08 dplore

Last call for comment Aug 20th, 2024

Gentle reminder!

Shashank-arista avatar Aug 23 '24 06:08 Shashank-arista