Skip to content

Commit

Permalink
Static routing on Linux (ip route + netplan)
Browse files Browse the repository at this point in the history
  • Loading branch information
ipspace committed Dec 25, 2024
1 parent 7cf445a commit 87defc6
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 49 deletions.
34 changes: 15 additions & 19 deletions docs/module/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@ This configuration module implements generic routing features:
The following table describes high-level per-platform support of generic routing features:

| Operating system | Routing<br>policies | Prefix<br>filters| AS-path<br>filters | BGP<br>communities | Static<br>routes|
| ------------------ | :-: | :-: | :-: |:-: | :-: |
| Arista EOS |||| |
| Aruba AOS-CX |||| |
| Cisco IOSv/IOSvL2 | ||| |
| Cisco IOS-XE[^18v] | | || |
| Cumulus Linux || | | |
| FRR | ||| |
| Nokia SR Linux | |[](caveats-srlinux) |
| Nokia SR OS | |
| VyOS | | | ||
| ------------------ |:--:|:--:|:--:|:--:|:--:|
| Arista EOS ||||| |
| Aruba AOS-CX |||| |
| Cisco IOS/XE[^18v] | | ||| |
| Cumulus Linux | |||| |
| FRR | |||| |
| Linux | | ||| |
| Nokia SR Linux ||[](caveats-srlinux) |
| Nokia SR OS ||
| VyOS ||| ||

```{tip}
See [Routing Integration Tests Results](https://release.netlab.tools/_html/coverage.routing) for more details.
```

[^18v]: Includes Cisco CSR 1000v, Cisco Catalyst 8000v, Cisco IOS-on-Linux (IOL), and IOL Layer-2 image.
[^18v]: Includes Cisco IOSv, Cisco IOSvL2, Cisco CSR 1000v, Cisco Catalyst 8000v, Cisco IOS-on-Linux (IOL), and IOL Layer-2 image.

(generic-routing-policies)=
## Routing Policies
Expand Down Expand Up @@ -101,8 +101,7 @@ You can use these routing policy **match** parameters on devices supported by th
|---------------------|:--:|:--:|:--:|:--:|
| Arista EOS |||||
| Aruba AOS-CX |||||
| Cisco IOSv/IOSvL2 |||||
| Cisco IOS-XE[^18v] |||||
| Cisco IOS/XE[^18v] |||||
| Cumulus Linux |||||
| FRR |||||
| Nokia SR Linux ||
Expand All @@ -114,8 +113,7 @@ You can use these routing policy **set** parameters on devices supported by the
|---------------------|:--:|:--:|:--:|:--:| :--:|
| Arista EOS ||||||
| Aruba AOS-CX ||||||
| Cisco IOSv/IOSvL2 ||||||
| Cisco IOS-XE[^18v] ||||||
| Cisco IOS/XE[^18v] ||||||
| Cumulus Linux ||||||
| FRR ||||||
| Nokia SR Linux ||||||
Expand All @@ -128,8 +126,7 @@ The **set.community** attribute can be used to set these BGP communities on supp
|---------------------|:--:|:--:|:--:|:--:|:--:|
| Arista EOS ||||||
| Aruba AOS-CX ||||||
| Cisco IOSv/IOSvL2 ||||||
| Cisco IOS-XE[^18v] ||||||
| Cisco IOS/XE[^18v] ||||||
| Cumulus Linux ||||||
| FRR ||||||
| VyOS ||||||
Expand Down Expand Up @@ -497,8 +494,7 @@ _netlab_ supports static routes on these platforms:
| Cisco IOS/XE[^18v] ||||
| Cumulus Linux 4.x ||||
| FRR ||||

[^18v]: Includes Cisco IOSv, Cisco IOSvL2, Cisco CSR 1000v, Cisco Catalyst 8000v, Cisco IOS-on-Linux (IOL), and IOL Layer-2 image.
| Linux ||||

### Global Static Routes

Expand Down
20 changes: 11 additions & 9 deletions netsim/ansible/templates/initial/linux/ubuntu.j2
Original file line number Diff line number Diff line change
Expand Up @@ -140,23 +140,25 @@ network:
SCRIPT
{% endfor %}
# Add routes to IPv4 address pools pointing to the first neighbor on the first link
{% for ifdata in interfaces|default([]) if ifdata.gateway is defined %}
cat <<SCRIPT > /etc/netplan/04-routes-{{ ifdata.ifname }}.yaml
{% if routing.static|default([]) %}
# Add IPv4 static routes
cat <<SCRIPT > /etc/netplan/04-routes.yaml
network:
version: 2
renderer: networkd
ethernets:
{{ ifdata.ifname }}:
{% for intf in routing.static|map(attribute='nexthop.intf',default='')|unique if intf %}
{{ intf }}:
routes:
{% for name,pool in pools.items()|default({}) %}
{% for af,pfx in pool.items() if af == 'ipv4' and name != 'mgmt' and name != 'router_id' %}
- to: {{ pfx }}
via: {{ ifdata.gateway.ipv4|ipaddr('address') }}
{% for sr_entry in routing.static|default([])
if 'ipv4' in sr_entry and
sr_entry.nexthop.intf|default('') == intf %}
- to: {{ sr_entry.ipv4 }}
via: {{ sr_entry.nexthop.ipv4 }}
{% endfor %}
{% endfor %}
SCRIPT
{% endfor %}
{% endif %}
echo -n 'Starting netplan generate ' && date
netplan generate
Expand Down
20 changes: 7 additions & 13 deletions netsim/ansible/templates/initial/linux/vanilla.j2
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,18 @@ ip link set {{ l.ifname }} mtu {{ l.mtu }}
{% endif %}
{% endfor %}
#
# Add routes to IPv4 address pools pointing to the first neighbor on the first link
# Add routes to IPv4 address pools pointing to the first usable default gateway
#
# If you need anything better, use FRR instead of Linux and start routing (or use IPv6)
#
{% for ifdata in interfaces|default([]) if ifdata.gateway is defined %}
{% for name,pool in pools.items()|default({}) %}
{% for af,pfx in pool.items() if af == 'ipv4' %}
# {{ name }} prefix: {{ pfx }} local subnet: {{ ifdata.gateway.ipv4|ipaddr('subnet') }}
{% if name not in ['mgmt','router_id'] and pfx is string and
pfx != ifdata.gateway.ipv4|ipaddr('subnet') %}
{% for sr_entry in routing.static|default([]) if 'ipv4' in sr_entry %}
echo "sr_entry: {{ sr_entry }}"
set +e
ip route del {{ pfx }} 2>/dev/null
ip route del {{ sr_entry.ipv4 }} via {{ sr_entry.nexthop.ipv4 }} 2>/dev/null
set -e
ip route add {{ pfx }} via {{ ifdata.gateway.ipv4|ipaddr('address') }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
ip route add {{ sr_entry.ipv4 }} via {{ sr_entry.nexthop.ipv4 }}{{
' dev '+sr_entry.nexthop.intf if 'intf' in sr_entry.nexthop else '' }}
{% endfor %}
#
# Print the final routing table
ip route
8 changes: 8 additions & 0 deletions netsim/ansible/templates/routing/linux.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
{% if routing.static|default([]) %}
#
echo "Static routes are configured as part of the initial configuration template"
echo
#
ip route
{% endif %}
3 changes: 3 additions & 0 deletions netsim/devices/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ features:
ipv6: true
server: true
relay: true
routing:
static:
max_nexthop: 1
libvirt:
image: generic/ubuntu2004
group_vars:
Expand Down
15 changes: 7 additions & 8 deletions netsim/modules/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -777,12 +777,7 @@ def resolve_node_nexthop(sr_data: Box, node: Box, topology: Box) -> Box:
"""
Check whether a VRF static route is valid and supported by the device on which it's used
"""
def check_VRF_static_route(sr_data: Box, node: Box, topology: Box) -> bool:
d_features = devices.get_device_features(node,topology.defaults)
sr_features = d_features.get('routing.static')
if not isinstance(sr_features,dict):
sr_features = data.get_empty_box()

def check_VRF_static_route(sr_data: Box, node: Box, sr_features: Box) -> bool:
if 'vrf' in sr_data:
if sr_data.vrf not in node.get('vrfs',{}):
log.error(
Expand Down Expand Up @@ -819,6 +814,10 @@ def check_VRF_static_route(sr_data: Box, node: Box, topology: Box) -> bool:

def check_static_routes(idx: int,o_name: str,node: Box,topology: Box) -> None:
sr_data = node.routing[o_name][idx]
d_features = devices.get_device_features(node,topology.defaults)
sr_features = d_features.get('routing.static')
if not isinstance(sr_features,dict):
sr_features = data.get_empty_box()

if 'pool' in sr_data:
sr_data = sr_data + extract_af_info(topology.addressing[sr_data.pool])
Expand All @@ -845,7 +844,7 @@ def check_static_routes(idx: int,o_name: str,node: Box,topology: Box) -> None:
return

if 'vrf' in sr_data or 'vrf' in sr_data.nexthop:
if not check_VRF_static_route(sr_data,node,topology):
if not check_VRF_static_route(sr_data,node,sr_features):
return

if sr_data.nexthop.get('node',None):
Expand All @@ -868,7 +867,7 @@ def check_static_routes(idx: int,o_name: str,node: Box,topology: Box) -> None:
for af in log.AF_LIST:
if af not in sr_data:
continue
for nh_entry in sr_data.nexthop.nhlist:
for nh_entry in sr_data.nexthop.nhlist[:sr_features.get('max_nexthop',256)]:
sr_entry = { af: sr_data[af], 'nexthop': nh_entry }
if 'vrf' in sr_data:
sr_entry['vrf'] = sr_data.vrf
Expand Down

0 comments on commit 87defc6

Please sign in to comment.