Skip to content

Commit

Permalink
VRF-aware RIPv2/RIPng (implemented on FRR)
Browse files Browse the repository at this point in the history
  • Loading branch information
ipspace committed Sep 12, 2024
1 parent 95b4f09 commit ac0e9bc
Show file tree
Hide file tree
Showing 15 changed files with 250 additions and 44 deletions.
15 changes: 11 additions & 4 deletions docs/module/ripv2.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ This configuration module configures the RIPv2 and RIPng. The module supports th

* IPv4 and IPv6
* Passive interfaces
* VRF RIPv2/RIPng instances

```eval_rst
.. contents:: Table of Contents
Expand All @@ -17,13 +18,13 @@ This configuration module configures the RIPv2 and RIPng. The module supports th

The following table describes per-platform support of individual RIPv2/RIPng features:

| Operating system | IPv4<br>(RIPv2) | IPv6<br>(RIPng) | Passive<br>interfaces | Route<br>import |
| ------------------ | :-: | :-: | :-: | :-: |
| Operating system | IPv4<br>(RIPv2) | IPv6<br>(RIPng) | Passive<br>interfaces | Route<br>import | VRF<br>instances |
| ------------------ | :-: | :-: | :-: | :-: | :-: |
| Arista EOS |||||
| Cisco IOSv/IOSvL2 |||[](caveats-iosv) |[](caveats-iosv) |
| Cisco IOS XE[^18v] |||[](caveats-iosv) |[](caveats-iosv) |
| Cumulus Linux |||||
| FRR |||||
| Cumulus Linux ||||||
| FRR ||||||
| VyOS |||||

```{tip}
Expand All @@ -38,6 +39,12 @@ RIPv2/RIPng module does not have global parameters. The only relevant node param

RIPv2 also supports [](routing_passive) and [](routing_external).

## VRF Parameters

* By default, _netlab_ redistributes BGP- and connected routes into VRF RIPv2/RIPng instances on all network devices. You can change that on devices supporting configurable route import with the **[ripv2.import](routing_import)** VRF parameter.
* Set **ripv2.active** to *True* to force a VRF to use RIPv2/RIPng even when no routers are attached to the VRF interfaces.
* To disable RIPv2/RIPng in a VRF set **ripv2** to *False* (see also [](routing_disable_vrf)).

## Example

We want to create a simple two-router RIPv2 network using Cumulus Linux:
Expand Down
8 changes: 4 additions & 4 deletions docs/module/vrf.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ VRFs are supported on these platforms:
(module-vrf-platform-routing-support)=
These platforms support routing protocols in VRFs:

| Operating system | VRF-aware<br />OSPF | VRF-aware<br />OSPFv3 | VRF-aware<br />EBGP |
| --------------------- | :-: | :-: | :-: |
| Operating system | OSPFv2 | OSPFv3 | EBGP | RIPv2 | RIPng
| --------------------- | :-: | :-: | :-: | :-: | :-: |
| Arista EOS ||||
| Aruba AOS-CX ||||
| Cisco IOS/IOSvL2 |[](caveats-iosv) |||
| Cisco IOS XE[^18v] |[](caveats-csr) |||
| Cisco Nexus OS ||||
| Cumulus Linux ||||
| Cumulus Linux ||||||
| Dell OS10 ||||
| FRR [](caveats-frr) ||||
| FRR [](caveats-frr) ||||||
| Junos[^Junos] ||||
| Mikrotik RouterOS 6 |[](caveats-routeros6) |||
| Mikrotik RouterOS 7 ||||
Expand Down
25 changes: 2 additions & 23 deletions netsim/ansible/templates/ripv2/frr.j2
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
{% import "templates/routing/_redistribute.frr.j2" as redistribute with context %}
{% import "frr.macro.j2" as rip with context %}
!
{% if ripv2.af.ipv4|default(False) %}
router rip
version 2
{{ redistribute.config(ripv2,af='ipv4') }}
{% for intf in netlab_interfaces if 'ripv2' in intf and 'ipv4' in intf %}
network {{ intf.ifname }}
{% if intf.ripv2.passive|default(False) %}
passive-interface {{ intf.ifname }}
{% endif %}
{% endfor %}
{% endif %}
!
{% if ripv2.af.ipv6|default(False) %}
router ripng
{{ redistribute.config(ripv2,af='ipv6') }}
{% for intf in netlab_interfaces if 'ripv2' in intf and 'ipv6' in intf %}
network {{ intf.ifname }}
{% if intf.ripv2.passive|default(False) %}
passive-interface {{ intf.ifname }}
{% endif %}
{% endfor %}
{% endif %}
{{ rip.config(ripv2) }}
!
do write
26 changes: 26 additions & 0 deletions netsim/ansible/templates/ripv2/frr.macro.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% import "templates/routing/_redistribute.frr.j2" as redistribute with context %}
!
{% macro config(ripv2,vrf='') -%}
{% if ripv2.af.ipv4|default(False) %}
router rip{% if vrf %} vrf {{ vrf }}{% endif +%}
version 2
{{ redistribute.config(ripv2,af='ipv4') }}
{% for intf in ripv2.interfaces|default(netlab_interfaces) if 'ripv2' in intf and 'ipv4' in intf %}
network {{ intf.ifname }}
{% if intf.ripv2.passive|default(False) %}
passive-interface {{ intf.ifname }}
{% endif %}
{% endfor %}
{% endif %}
!
{% if ripv2.af.ipv6|default(False) %}
router ripng{% if vrf %} vrf {{ vrf }}{% endif +%}
{{ redistribute.config(ripv2,af='ipv6') }}
{% for intf in ripv2.interfaces|default(netlab_interfaces) if 'ripv2' in intf and 'ipv6' in intf %}
network {{ intf.ifname }}
{% if intf.ripv2.passive|default(False) %}
passive-interface {{ intf.ifname }}
{% endif %}
{% endfor %}
{% endif %}
{%- endmacro %}
2 changes: 1 addition & 1 deletion netsim/ansible/templates/vrf/frr.bgp.j2
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ router bgp {{ vdata.as|default(bgp.as) }} vrf {{ vname }}
{% endfor %}
{% for af in ['ipv4','ipv6'] if vdata.af[af]|default(False) %}
address-family {{ af }} unicast
{{ redistribute.config(vdata.bgp,af=af) }}
{{ redistribute.config(vdata.bgp,af=af)|indent(1,first=True) }}
label vpn export auto
export vpn
import vpn
Expand Down
8 changes: 6 additions & 2 deletions netsim/ansible/templates/vrf/frr.frr-config.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% import "frr.ospfv2.j2" as ospfv2 %}
{% import "frr.ospfv3.j2" as ospfv3 %}
{% import "templates/ospf/frr.ospfv2.j2" as ospfv2 %}
{% import "templates/ospf/frr.ospfv3.j2" as ospfv3 %}
{% import "templates/ripv2/frr.macro.j2" as ripv2 %}
cat >/tmp/vrf_config <<CONFIG
{% for vname,vdata in vrfs.items() %}
vrf {{ vname }}
Expand All @@ -21,6 +22,9 @@ router bgp {{ bgp.as|default(vrf.as) }}
{% endif %}
!
{% endfor %}
{% for vname,vdata in vrfs.items() if vdata.ripv2 is defined %}
{{ ripv2.config(ripv2=vdata.ripv2,vrf=vname) }}
{% endfor %}
do write
!
CONFIG
Expand Down
1 change: 0 additions & 1 deletion netsim/ansible/templates/vrf/frr.ospfv2.j2

This file was deleted.

1 change: 0 additions & 1 deletion netsim/ansible/templates/vrf/frr.ospfv3.j2

This file was deleted.

2 changes: 1 addition & 1 deletion netsim/defaults/const.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
#
---
routing_protocols: [ bgp, connected, eigrp, isis, ospf, ripv2 ]
vrf_igp_protocols: [ connected, ospf ]
vrf_igp_protocols: [ connected, ospf, ripv2 ]
4 changes: 3 additions & 1 deletion netsim/devices/cumulus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ features:
ipv4: true
ipv6: true
passive: true
import: [ bgp, isis, ospf, connected ]
import: [ bgp, isis, ospf, connected, vrf ]
routing:
policy:
set:
Expand All @@ -81,6 +81,8 @@ features:
vrf:
ospfv2: True
bgp: True
ripv2: True
ripng: True
vxlan: True

clab:
Expand Down
6 changes: 3 additions & 3 deletions netsim/devices/frr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ features:
ipv4: true
ipv6: true
passive: true
import: [ bgp, isis, ospf, connected ]
import: [ bgp, isis, ospf, connected, vrf ]
routing:
policy:
set:
Expand Down Expand Up @@ -110,8 +110,8 @@ features:
keep_module: true
ospfv2: True
ospfv3: True
# ripv2: True
# ripng: True
ripv2: True
ripng: True
bgp: True
vxlan:
vtep6: true
Expand Down
4 changes: 2 additions & 2 deletions netsim/modules/ripv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def node_post_transform(self, node: Box, topology: Box) -> None:
_routing.passive(intf,'ripv2',topology,features,node) # Set passive flag on other RIPv2 interfaces

_routing.igp_post_transform(node,topology,proto='ripv2',vrf_aware=True)
_routing.check_vrf_protocol_support(node,'ripv2','ipv4','ripv2',topology)
_routing.check_vrf_protocol_support(node,'ripv2','ipv6','ripng',topology)
_routing.check_vrf_protocol_support(node,proto='ripv2',af='ipv4',feature='ripv2',topology=topology)
_routing.check_vrf_protocol_support(node,proto='ripv2',af='ipv6',feature='ripng',topology=topology)
if 'ripv2' in node and 'loopback' in node:
node.loopback.ripv2.passive = False
5 changes: 4 additions & 1 deletion netsim/modules/ripv2.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# RIPv2/RIPng default settings and attributes
#
---
version: 2 # A fake RIP attribute to create RIP data structure in RIP-enabled nodes
transform_after: [ vlan, vrf ]
config_after: [ vlan, dhcp ]
config_after: [ vlan, dhcp, routing ]
attributes:
global:
version: { type: int, min_value: 2, max_value: 2 }
af:
_list_to_dict: True
_alt_types: [ NoneType ]
Expand All @@ -16,6 +18,7 @@ attributes:
_alt_types: [ bool ]
node:
af:
version:
import: _r_import
vrf:
active: bool
Expand Down
91 changes: 91 additions & 0 deletions tests/integration/ripv2/31-vrf-ipv4.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
message: |
The device under test has two VRFs with two interfaces in each VRF.
Routers are attached to those interfaces and run RIP and BGP with
device under test.
This scenario tests RIPv2 in VRF, redistribution of connected subnets
into RIPv2 and two-way RIPv2-to-BGP redistribution.
* r1 and r2 should be able to ping each other
* r3 and r4 should be able to ping each other
* r1 should not be able to reach r3
groups:
ce_rip:
members: [ r1, r3 ]
module: [ ripv2 ]
device: frr
provider: clab
ce_bgp:
members: [ r2, r4 ]
module: [ bgp ]
device: frr
provider: clab
pe:
members: [ dut ]
module: [ vrf, ripv2, bgp ]

vrfs:
red:
links: [ dut-r1, dut-r2 ]
blue:
links: [ dut-r3, dut-r4 ]

nodes:
dut:
bgp.as: 65000
id: 1
r1:
r2:
bgp.as: 65100
r3:
r4:
bgp.as: 65101

validate:
ebgp:
description: Check EBGP adjacencies with DUT
wait_msg: Waiting for EBGP sessions to start
nodes: [ r2, r4 ]
plugin: bgp_neighbor(node.bgp.neighbors,'dut')
wait: 10
stop_on_error: true
red_c_rip:
description: Check connected subnet as RIPv2 prefix on R1
wait: 15
wait_msg: Waiting for RIPv2 convergence
fail: DUT is not redistributing connected subnets into RIPv2
nodes: [ r1 ]
plugin: rt_prefix(nodes.r2.interfaces[0].ipv4,af='ipv4',proto='rip')
red_bgp_rip:
description: Check for BGP prefix in RIPv2
wait_msg: Waiting for BGP and RIPv2 convergence
fail: BGP is not redistributed into RIPv2
wait: 10
nodes: [ r1 ]
plugin: rt_prefix(nodes.r2.loopback.ipv4,af='ipv4',proto='rip')
red_rip_bgp:
description: Check for RIPv2 prefix in BGP
wait_msg: Waiting for RIPv2 and BGP convergence
fail: RIPv2 is not redistributed into BGP
wait: 3
nodes: [ r2 ]
plugin: bgp_prefix(nodes.r1.loopback.ipv4)
red_lb_ping:
description: Loopback-to-loopback reachability test in VRF red
nodes: [ r1 ]
plugin: ping('r2',src=nodes.r1.loopback.ipv4)
red_p_rip:
description: Check for reachability of connected routes in RIPv2
nodes: [ r2 ]
plugin: ping('r1')
blue_lb_ping:
description: Loopback-to-loopback reachability test in VRF blue
wait: 10
nodes: [ r3 ]
plugin: ping('r4',src=nodes.r3.loopback.ipv4)
inter_vrf:
description: Ping-based isolation test between blue and red VRF
nodes: [ r1 ]
plugin: ping('r4',expect='fail')
Loading

0 comments on commit ac0e9bc

Please sign in to comment.