Generic Routing Configuration Module

This configuration module implements generic routing features:

Platform Support

The following table describes high-level per-platform support of generic routing features:

Operating system

Routing
policies

Prefix
filters

AS-path
filters

BGP
communities

Static
routes

Arista EOS

Aruba AOS-CX

Cisco IOSv

Cisco IOS-XE[1]

Cumulus Linux

FRR

Nokia SR Linux

Nokia SR OS

VyOS

Tip

See Routing Integration Tests Results for more details.

Routing Policies

Routing policies are lists of instructions that can match route parameters and set route attributes. Each routing policy entry can have these attributes:

  • action: A routing policy entry can permit or deny matched routes (default: permit)

  • sequence: Statement sequence number. When not specified, netlab sets a routing policy entry’s sequence number to ten times its list position.

  • match: Conditions that must match for the routing policy entry to take effect. Entries without a match parameter match all routes

  • set: Parameters that are set on matched routes.

You can match these route parameters in a netlab routing policy:

You can set these route parameters in a netlab routing policy:

  • locpref: BGP local preference

  • med: Route metric (for example, BGP MED)

  • prepend: BGP AS-path prepending (more details)

  • weight: BGP weight

  • community: A dictionary that can be used to set, add, or remove standard, large, or extended communities.

The set.community dictionary has these parameters:

  • standard: Standard BGP communities to set

  • large: Large BGP communities to set

  • extended: Extended BGP communities to set. The value is passed to the network device as-is (the same value might not work on all devices).

  • append: Add communities to existing BGP communities

  • delete: Remove specified communities from the BGP route

Routing policies are specified in the global- or node-level routing.policy dictionary (see Using Global- and Node-Level Routing Objects and Merging Routing Objects for more details).

The dictionary keys in the routing.policy dictionary are policy names (route map names), and the dictionary values are routing policies (lists of routing policy entries).

The following example specifies three routing policies: two global routing policies setting BGP local preference to different values and a node routing policy setting MED.

module: [ routing ]

routing.policy:
  lp_17:
  - set.locpref: 17
  lp_42:
  - set.locpref: 42

nodes:
  r1:
    routing.policy:
      set_med:
      - set.med: 100

Platform Support

You can use these routing policy match parameters on devices supported by the routing module:

Operating system

IPv4/IPv6
prefix

IPv4/IPv6
next hop

BGP
AS-path

BGP
Community

Arista EOS

Aruba AOS-CX

Cisco IOSv

Cisco IOS-XE[1]

Cumulus Linux

FRR

VyOS

You can use these routing policy set parameters on devices supported by the routing module:

Operating system

AS-path
prepend

Local
preference

MED

Weight

Community

Arista EOS

Aruba AOS-CX

Cisco IOSv

Cisco IOS-XE[1]

Cumulus Linux

FRR

Nokia SR Linux

Nokia SR OS

VyOS

The set.community attribute can be used to set these BGP communities on supported devices:

Operating system

Standard
community

Large
community

Extended
community

Append

Delete

Arista EOS

Aruba AOS-CX

Cisco IOSv

Cisco IOS-XE[1]

Cumulus Linux

FRR

VyOS

Shortcut Routing Policy Definitions

Routing policies tend to be verbose. You have to define a list of dictionaries with set and match attributes. netlab tries to reduce the verbosity with two shortcuts:

  • A routing policy with a single entry does not have to be a one-element list but could be a dictionary. For example, the following two routing policies are equivalent:

routing.policy:
  p1:
  - set.locpref: 100
  p2:
    set.locpref: 100
  • Unambiguous keywords like med and locpref do not need to be within the set or match dictionary. netlab automatically moves them into the routing-policy-entry set dictionary. For example, the following two routing policies are equivalent:

routing.policy:
  p1:
  - set.locpref: 100
    match.prefix: pfx-list
  p2:
    locpref: 100
    prefix: pfx-list

Dual-Stack Routing Policies

Most network operating systems cannot use match ip and match ipv6 commands in the same route map entry and behave differently when testing an IPv6 route with a route map entry that contains only match ip.

To avoid inconsistencies, netlab usually generates a separate per-address-family route map for each routing policy configured on a network device. The address-family-specific route maps are then used in device configuration.

For example:

  • If you create a routing policy X, and a node runs IPv4 and IPv6, netlab configures two route maps: X-ipv4 and X-ipv6.

  • When the same routing policy is used on a node that runs only IPv4, netlab configures only X-ipv4.

  • When the routing policy X is used in bgp.policy attribute, netlab uses route map X-ipv4 for IPv4 EBGP sessions and X-ipv6 for IPv6 EBGP sessions.

Prefix Filters (prefix-lists)

Prefix filters are lists of conditions (usually known as lists) that permit or deny IPv4 or IPv6 prefixes. You can use prefix filters in the match.prefix and match.nexthop parameters of routing policies to match IPv4/IPv6 routes or next hops. Each prefix filter entry can have these attributes:

  • action: A prefix filter entry can permit or deny matched prefixes (default: permit)

  • sequence: Statement sequence number. When not specified, netlab sets a prefix filter entry’s sequence number to ten times its list position.

  • ipv4: IPv4 prefix to match

  • ipv6: IPv6 prefix to match

  • pool: Name of the addressing pool to match

  • prefix: A named prefix to match

  • min: Minimum prefix length. It could be specified as an integer or a dictionary with ipv4 and ipv6 keys.

  • max: Maximum prefix length in the same format as the min parameters.

Prefix filters are specified in the global- or node-level routing.prefix dictionary (see Using Global- and Node-Level Routing Objects and Merging Routing Objects for more details).

The keys of the routing.prefix dictionary are filter names (prefix-list names), and the values are prefix filters (lists of prefix filter entries).

The following example specifies a prefix filter that matches the loopback pool, a named prefix, and an IPv6 prefix:

module: [ routing ]

prefix:
  lb_c1: 192.168.42.0/24

routing.prefix:
  loopbacks:
  - pool: loopback
  - prefix: lb_c1
  - ipv6: 2001:db8:cafe:2::/64

Dual-Stack Prefix Lists

Address pools, named prefixes, and prefix filter entries can contain IPv4 and IPv6 prefixes. Meanwhile, most network operating systems use different configuration objects to match IPv4 and IPv6 prefixes.

netlab generates separate per-address-family prefix lists for every prefix filter configured on a network device. The address family is appended to the prefix list name to deal with devices that cannot use the same names for IPv4 and IPv6 prefix lists.

To avoid route map inconsistencies, a prefix list that contains no usable entries (for example, an IPv6 prefix list generated from a prefix filter that matches only IPv4 prefixes) has a single deny everything condition.

Let’s assume we’re using the following prefix filters:

routing.prefix:
  p1:
    - ipv4: 192.168.24.0/24
    - ipv6: 2001:db8:0:1::/64
  p2:
    - ipv4: 172.16.0.0/16

netlab generates these prefix lists on an IPv4-only device (IPv6 prefix list is not generated, and entry #20 is missing from P1):

ip prefix-list p1-ipv4 seq 10 permit 192.168.24.0/24
!
ip prefix-list p2-ipv4 seq 10 permit 172.16.0.0/16

Meanwhile, the following prefix lists are generated on a dual-stack device (including a meaningless IPv6 prefix list P2)

ip prefix-list p1-ipv4 seq 10 permit 192.168.24.0/24
!
ip prefix-list p2-ipv4 seq 10 permit 172.16.0.0/16
!
ipv6 prefix-list p1-ipv6 seq 20 permit 2001:db8:0:1::/64
!
ipv6 prefix-list p2-ipv6 seq 10 deny ::/0

BGP AS-Path Filters

AS-path filters are lists of conditions (usually known as as-path access lists) that permit or deny BGP AS paths (and consequently the routes carrying them). They match a list of AS numbers or a regular expression. You can use them in the match.aspath parameters of routing policies to match BGP routes. Each AS-path filter entry can have these attributes:

  • action: A prefix filter entry can permit or deny matched prefixes (default: permit)

  • sequence: Statement sequence number. When not specified, netlab sets a prefix filter entry’s sequence number to ten times its list position.

  • path: A list of autonomous systems to match or a regular expression to match

AS-path filters are specified in the global- or node-level routing.aspath dictionary (see Using Global- and Node-Level Routing Objects and Merging Routing Objects for more details).

The keys of the routing.aspath dictionary are filter names (prefix-list names), and the values are AS-path filters (lists of AS-path filter entries).

The following example specifies an AS-path access list that drops BGP prefixes originated in AS 65000 and permits everything else:

module: [ routing ]

routing.aspath:
  not_65000:
  - action: deny
    path: _65000$
  - action: permit

Shortcut BGP AS-Path Definitions

Filters encoded in YAML tend to be verbose, and we tried to do as much as we could to reduce BGP AS-path filter verbosity:

  • You can skip the action and sequence attributes.

  • Each entry in a BGP AS-path filter could be a simple string or a list of AS numbers. Such entries are converted into dictionaries with the path element set to the entry’s value.

  • A list of AS numbers in the path element is converted into a string of AS numbers separated by a blank

  • A BGP AS-path filter could be a single string. That string is first converted into a list and subsequently into a list containing a single dictionary.

The following example lists various shortened definitions of BGP AS-path filters:

routing:
  aspath:
    ap1: 65000                      # AS-path ACL as int => single-entry ACL
    ap2: [ 65000 ]                  # Single-entry AS-path ACL
    ap3:                            # AS-path ACL
    - action: deny
      path: [ 65000, 65001 ]        # The first entry is a list of ASNs
    - '6510.'                       # The second entry is a regexp

netlab normalizes these AS-path filters into the following data structure:

aspath:
  ap1:
  - action: permit
    path: 65000
    sequence: 10
  ap2:
  - action: permit
    path: 65000
    sequence: 10
  ap3:
  - action: deny
    path: 65000 65001
    sequence: 10
  - action: permit
    path: '6510.'
    sequence: 20

BGP Community Filters

BGP community filters are lists of conditions (usually known as community lists) that permit or deny BGP routes based on standard BGP communities attached to them. They can match a list of communities or a regular expression. You can use them in the match.community parameters of routing policies to match BGP routes. Each BGP community filter entry can have these attributes:

  • action: A prefix filter entry can permit or deny matched prefixes (default: permit)

  • sequence: Statement sequence number. When not specified, netlab sets a prefix filter entry’s sequence number to ten times its list position.

  • list: A list of communities to match

  • regexp: A regular expression to match

BGP community filters are specified in the global- or node-level routing.community dictionary. The dictionary keys are filter names (community-list names), and the dictionary values are BGP community filters (lists of BGP community filter entries).

The following example specifies a BGP community filter that drops BGP routes carrying communities defined by AS 65000 and permits everything else:

module: [ routing ]

routing.community:
  not_65000:
  - action: deny
    regexp: _65000:[0-9]+_
  - action: permit

Shortcut BGP Community Filter Definitions

Filters encoded in YAML tend to be verbose, and we tried to do as much as we could to reduce BGP community filter verbosity:

  • You can skip the action and sequence attributes.

  • Each entry in a BGP community filter could be a simple string or a list of BGP communities to match. Such entries are converted into dictionaries with the list or regexp element set to the entry’s value. netlab automatically figures out whether a value is a list of communities or a regular expression.

  • A list of BGP communities in the list element is converted into a string of BGP communities separated by a blank

  • A BGP community filter could be a single string. That string is first converted into a list and subsequently into a list containing a single dictionary.

  • netlab automatically generates an expanded community list if at least one entry contains a regular expression, and a standard community list if all entries contain community values or lists of them.

The following example lists various shortened definitions of BGP community filters:

routing.community:
  cl1: 65000:100                            # Single-entry ACL
  cl2: [ 65000:100, 65000:101 ]             # Single-entry multivalue ACL
  cl3: _65000:10[1-2]_                      # Regular expression
  cl4:                                      # More complex standard ACL
  - action: permit                          # Used to implement or-of-ands condition
    path: [ 65000:100, 65001:100 ]
  - action: permit
    path: [ 65000:103, 65001:103 ]
  cl5:                                      # A mix standard and extended conditions ==> extended
  - action: deny
    path: [ 65000:100, 65001:100 ]          # first entry is a list of communities
  - '_6510.:307_'                           # the second entry is a regexp
  cl6:                                      # Permit any at the end forces an extended clist
  - action: deny
    path: [ 65000:100, 65001:100 ]
  - action: permit

netlab normalizes these BGP community filters into the following data structure:

community:
  cl1:
    - list: 65000:100
      action: permit
      sequence: 10
  cl2:
    - list: 65000:100
      action: permit
      sequence: 10
    - list: 65000:101
      action: permit
      sequence: 20
  cl3:
    - action: permit
      regexp: _65000:10[1-2]_
      sequence: 10
  cl4:
    value:
    - list: 65000:100 65001:100
      action: permit
      sequence: 10
    - list: 65000:103 65001:103
      action: permit
      sequence: 20
  cl5:
    value:
    - list: 65000:100 65001:100
      action: deny
      sequence: 10
    - action: permit
      regexp: _6510.:307_
      sequence: 20
  cl6:
    value:
    - list: 65000:100 65001:100
      action: deny
      sequence: 10
    - action: permit
      regexp: .*
      sequence: 20

Advanced Topics

Using Global- and Node-Level Routing Objects

A routing object (routing policy, prefix filter, BGP AS-path filter, or BGP community filter) will not be configured on a network device if it’s not defined within the node routing.object dictionary.

That’s usually not a problem as the users of routing policies (for example, the bgp.policy plugin) copy global routing policies and all filters used by those routing policies into node data whenever the lab topology references a global routing policy, or when a local routing policy references a global filter. However, you might need a placeholder routing object that is later used in a custom template. To force a global routing object to be copied and configured on a node, mention its name in the corresponding node routing dictionary within giving it a value.

For example, if you want to have route map P1 defined on node R1 even though it’s not used by any netlab configuration construct, use the following code snippet:

routing.policy:
  p1:
  - set.locpref: 100
  
nodes:
  r1:
    routing.policy.p1:

The above lab topology will copy the contents of the P1 global routing policy into the R1 routing.policy dictionary, resulting in the corresponding route map configured on R1.

Merging Routing Objects

When a routing object (routing policy, prefix filter, BGP AS-path filter, or BGP community filter) is defined globally as well as within a node, netlab tries to merge the two definitions based on the sequence numbers attached to the routing object entries:

  • Global routing object entries with sequence numbers that do not exist in the node-level routing object are added to that object.

  • The resulting list is sorted based on the sequence numbers.

For example, consider the following routing policy definitions:

routing.prefix:
  loopbacks:
  - pool: loopback

routing.policy:
  p1:
  - match.prefix: loopbacks
    set.locpref: 100
  - set.med: 200
  
nodes:
  r1:
    routing.policy:
      p1:
      - match.prefix: loopbacks
        set.locpref: 200
      - sequence: 15
        set.prepend.path: 65000

The entries in routing policies without sequence numbers get their sequence numbers assigned based on their position in the routing policy list. The above example is thus equivalent to:

routing.policy:
  p1:
  - sequence: 10
    match.prefix: loopbacks
    set.locpref: 100
  - sequence: 20
    set.med: 200
  
nodes:
  r1:
    routing.policy:
      p1:
      - sequence: 10
        match.prefix: loopbacks
        set.locpref: 200
      - sequence: 15
        set.prepend.path: 65000

The results of the merging process should now be self-explanatory. The sequence number 20 is missing from the node-level routing policy. That entry is added from the global routing policy, and the results are sorted, giving us the following routing policy on R1:

p1:
- sequence: 10
  match.prefix: loopbacks
  set.locpref: 200
- sequence: 15
  set.prepend.path: 65000
- sequence: 20
  set.med: 200