Adding support for configuration of ECMP of next hops for a static LSP
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]
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?
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 compatibilitything. 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.
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.
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
deprecatedshould be used.
Sure thanks, will update that. Also regarding next-hops, I have tried to use here similar to Static routes
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
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
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).
For reference:
- Cisco XR -- allows multiple
pathstatements 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?
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. :-)
/gcbrun
No major YANG version changes in commit 75ac876efc7093905b706f7d98a119fbbc8d8ffa
@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
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)
/gcbrun
To be reviewed on July 30,2024 OC Operators meeting
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
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?
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
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.
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
/gcbrun
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
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.
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.
/gcbrun
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.
Last call for comment Aug 20th, 2024
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.
Updated the implementation references, including adding a reference to SRLinux.
Last call for comment Aug 20th, 2024
Gentle reminder!