diff --git a/netsim/extra/bgp.session/plugin.py b/netsim/extra/bgp.session/plugin.py index 7096aa0db5..5cc56bca73 100644 --- a/netsim/extra/bgp.session/plugin.py +++ b/netsim/extra/bgp.session/plugin.py @@ -3,7 +3,7 @@ from box import Box, BoxList from netsim import api, modules -from netsim.data import append_to_list +from netsim.data import append_to_list, get_box from netsim.utils import log from netsim.utils import routing as _bgp @@ -156,6 +156,52 @@ def process_bfd_requests(ndata: Box, topology: Box) -> None: log.IncorrectValue, _config_name) +''' +Check whether a node originating a default route needs static default route(s) +''' +BGP_DEFAULT = { + 'ipv4': { 'ipv4': '0.0.0.0/0', 'floating': True, 'nexthop.discard': True }, + 'ipv6': { 'ipv6': '::/0', 'floating': True, 'nexthop.discard': True }} + +def process_default_requests(ndata: Box, topology: Box) -> None: + if _bgp.get_device_bgp_feature('default_originate',ndata,topology) != 'static': + return # The node does not need static routes to originate default + + for ngb in _bgp.neighbors(ndata): + if not 'default_originate' in ngb: # Does the neighbor need a BGP default route? + continue # Nope? Cool + + route_list = [ # Find relevant static routes based on neighbor AFs + BGP_DEFAULT[af] for af in log.AF_LIST if af in ngb + ] + if not route_list: + continue + + append_to_list(ndata,'module','routing') # Activate the routing module in the node + append_to_list(topology,'module','routing') # ... assuming the developer setting BGP features was sane ;) + + # Get VRF (or global) data and its static routes + # + vrf_data = ndata.vrfs[ngb._src_vrf] if '_src_vrf' in ngb else ndata + vrf_routes = vrf_data.get('routing.static',[]) + + for sr_data in route_list: # Iterate over routes that have to be added + for af in log.AF_LIST: # We have to check all AFs + if af not in sr_data: # Is this AF relevant for the current entry? + continue + + # Get existing route(s) where the AF prefix matches what we need + have_routes = [ r for r in vrf_routes if af in r and r[af] == sr_data[af] ] + if have_routes: # Did the user specify their own default route(s)? + continue # Cool, nothing to do ;) + + # No per-AF default route in the target VRF yet, add it + # + sr_final = sr_data # Assume we can use the static route data as-is + if '_src_vrf' in ngb: # But if we have a VRF neighbor, we have to add VRF info + sr_final = get_box({'nexthop': {'vrf': ngb._src_vrf}}) + sr_data + append_to_list(ndata,'routing.static',sr_final) + ''' Zap a BGP neighbor: remove all usable IP addresses, local_if and ifindex ''' @@ -288,6 +334,7 @@ def post_transform(topology: Box) -> None: copy_local_attributes(ndata,topology) process_tcpao_secrets(ndata,topology) process_bfd_requests(ndata,topology) + process_default_requests(ndata,topology) have_rs = process_rs_requests(ndata,topology) or have_rs # We need to do the RS-related EBGP session cleanup in a second pass diff --git a/tests/coverage/expected/bgp-default.yml b/tests/coverage/expected/bgp-default.yml new file mode 100644 index 0000000000..1329322648 --- /dev/null +++ b/tests/coverage/expected/bgp-default.yml @@ -0,0 +1,554 @@ +bgp: + advertise_loopback: true + community: + ebgp: + - standard + ibgp: + - standard + - extended + next_hop_self: true +groups: + as65000: + members: + - dut + as65001: + members: + - x1 + as65002: + members: + - x2 + as65100: + members: + - v1 + as65101: + members: + - v2 +input: +- coverage/input/bgp-default.yml +- package:topology-defaults.yml +links: +- _linkname: links[1] + interfaces: + - bgp: + default_originate: true + ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.1/30 + node: dut + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.2/30 + node: x1 + linkindex: 1 + node_count: 2 + prefix: + ipv4: 10.1.0.0/30 + role: external + type: p2p +- _linkname: links[2] + interfaces: + - bgp: + default_originate: true + ifindex: 2 + ifname: eth2 + ipv4: 10.1.0.5/30 + node: dut + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.6/30 + node: x2 + linkindex: 2 + node_count: 2 + prefix: + ipv4: 10.1.0.4/30 + role: external + type: p2p +- _linkname: links[3] + interfaces: + - bgp: + default_originate: true + ifindex: 3 + ifname: eth3 + ipv4: 10.1.0.9/30 + node: dut + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.10/30 + node: v1 + linkindex: 3 + node_count: 2 + prefix: + ipv4: 10.1.0.8/30 + role: external + type: p2p + vrf: t1 +- _linkname: links[4] + interfaces: + - bgp: + default_originate: true + ifindex: 4 + ifname: eth4 + ipv4: 10.1.0.13/30 + node: dut + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.14/30 + node: v2 + linkindex: 4 + node_count: 2 + prefix: + ipv4: 10.1.0.12/30 + role: external + type: p2p + vrf: t1 +message: 'Checks the default static route origination needed to originate the + + BGP default route(s) + + ' +module: +- routing +- bgp +- vrf +name: input +nodes: + dut: + _features: + bgp: + default_originate: static + af: + ipv4: true + vpnv4: true + bgp: + _session_clear: + - 10.1.0.2 + - 10.1.0.6 + advertise: + - ipv4: 10.0.0.1/32 + advertise_loopback: true + as: 65000 + community: + ebgp: + - standard + ibgp: + - standard + - extended + localas_ibgp: + - standard + - extended + ipv4: true + neighbors: + - activate: + ipv4: true + as: 65001 + default_originate: true + ifindex: 1 + ipv4: 10.1.0.2 + name: x1 + type: ebgp + - activate: + ipv4: true + as: 65002 + default_originate: true + ifindex: 2 + ipv4: 10.1.0.6 + name: x2 + type: ebgp + next_hop_self: true + router_id: 10.0.0.1 + box: none + config: + - bgp.session + device: none + id: 1 + interfaces: + - bgp: + default_originate: true + ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.1/30 + linkindex: 1 + name: dut -> x1 + neighbors: + - ifname: eth1 + ipv4: 10.1.0.2/30 + node: x1 + role: external + type: p2p + - bgp: + default_originate: true + ifindex: 2 + ifname: eth2 + ipv4: 10.1.0.5/30 + linkindex: 2 + name: dut -> x2 + neighbors: + - ifname: eth1 + ipv4: 10.1.0.6/30 + node: x2 + role: external + type: p2p + - bgp: + default_originate: true + ifindex: 3 + ifname: eth3 + ipv4: 10.1.0.9/30 + linkindex: 3 + name: dut -> v1 + neighbors: + - ifname: eth1 + ipv4: 10.1.0.10/30 + node: v1 + role: external + type: p2p + vrf: t1 + - bgp: + default_originate: true + ifindex: 4 + ifname: eth4 + ipv4: 10.1.0.13/30 + linkindex: 4 + name: dut -> v2 + neighbors: + - ifname: eth1 + ipv4: 10.1.0.14/30 + node: v2 + role: external + type: p2p + vrf: t1 + loopback: + bgp: + advertise: true + ifindex: 0 + ifname: Loopback0 + ipv4: 10.0.0.1/32 + neighbors: [] + type: loopback + virtual_interface: true + mgmt: + ifname: eth0 + ipv4: 192.168.121.101 + mac: ca:fe:00:01:00:00 + module: + - routing + - bgp + - vrf + name: dut + routing: + static: + - floating: true + ipv4: 0.0.0.0/0 + nexthop: + discard: true + - floating: true + ipv4: 0.0.0.0/0 + nexthop: + discard: true + vrf: t1 + vrf: + as: 65000 + vrfs: + t1: + af: + ipv4: true + bgp: + _session_clear: + - 10.1.0.10 + - 10.1.0.14 + import: + connected: + auto: true + neighbors: + - _src_vrf: t1 + activate: + ipv4: true + as: 65100 + default_originate: true + ifindex: 3 + ipv4: 10.1.0.10 + name: v1 + type: ebgp + - _src_vrf: t1 + activate: + ipv4: true + as: 65101 + default_originate: true + ifindex: 4 + ipv4: 10.1.0.14 + name: v2 + type: ebgp + export: + - '65000:1' + id: 1 + import: + - '65000:1' + rd: '65000:1' + vrfidx: 100 + v1: + af: + ipv4: true + bgp: + advertise: + - ipv4: 10.0.0.4/32 + advertise_loopback: true + as: 65100 + community: + ebgp: + - standard + ibgp: + - standard + - extended + localas_ibgp: + - standard + - extended + ipv4: true + neighbors: + - _vrf: t1 + activate: + ipv4: true + as: 65000 + ifindex: 1 + ipv4: 10.1.0.9 + name: dut + type: ebgp + next_hop_self: true + router_id: 10.0.0.4 + box: none + device: none + id: 4 + interfaces: + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.10/30 + linkindex: 3 + name: v1 -> dut + neighbors: + - bgp: + default_originate: true + ifname: eth3 + ipv4: 10.1.0.9/30 + node: dut + vrf: t1 + role: external + type: p2p + loopback: + bgp: + advertise: true + ifindex: 0 + ifname: Loopback0 + ipv4: 10.0.0.4/32 + neighbors: [] + type: loopback + virtual_interface: true + mgmt: + ifname: eth0 + ipv4: 192.168.121.104 + mac: ca:fe:00:04:00:00 + module: + - bgp + name: v1 + v2: + af: + ipv4: true + bgp: + advertise: + - ipv4: 10.0.0.5/32 + advertise_loopback: true + as: 65101 + community: + ebgp: + - standard + ibgp: + - standard + - extended + localas_ibgp: + - standard + - extended + ipv4: true + neighbors: + - _vrf: t1 + activate: + ipv4: true + as: 65000 + ifindex: 1 + ipv4: 10.1.0.13 + name: dut + type: ebgp + next_hop_self: true + router_id: 10.0.0.5 + box: none + device: none + id: 5 + interfaces: + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.14/30 + linkindex: 4 + name: v2 -> dut + neighbors: + - bgp: + default_originate: true + ifname: eth4 + ipv4: 10.1.0.13/30 + node: dut + vrf: t1 + role: external + type: p2p + loopback: + bgp: + advertise: true + ifindex: 0 + ifname: Loopback0 + ipv4: 10.0.0.5/32 + neighbors: [] + type: loopback + virtual_interface: true + mgmt: + ifname: eth0 + ipv4: 192.168.121.105 + mac: ca:fe:00:05:00:00 + module: + - bgp + name: v2 + x1: + af: + ipv4: true + bgp: + advertise: + - ipv4: 10.0.0.2/32 + advertise_loopback: true + as: 65001 + community: + ebgp: + - standard + ibgp: + - standard + - extended + localas_ibgp: + - standard + - extended + ipv4: true + neighbors: + - activate: + ipv4: true + as: 65000 + ifindex: 1 + ipv4: 10.1.0.1 + name: dut + type: ebgp + next_hop_self: true + router_id: 10.0.0.2 + box: none + device: none + id: 2 + interfaces: + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.2/30 + linkindex: 1 + name: x1 -> dut + neighbors: + - bgp: + default_originate: true + ifname: eth1 + ipv4: 10.1.0.1/30 + node: dut + role: external + type: p2p + loopback: + bgp: + advertise: true + ifindex: 0 + ifname: Loopback0 + ipv4: 10.0.0.2/32 + neighbors: [] + type: loopback + virtual_interface: true + mgmt: + ifname: eth0 + ipv4: 192.168.121.102 + mac: ca:fe:00:02:00:00 + module: + - bgp + name: x1 + x2: + af: + ipv4: true + bgp: + advertise: + - ipv4: 10.0.0.3/32 + advertise_loopback: true + as: 65002 + community: + ebgp: + - standard + ibgp: + - standard + - extended + localas_ibgp: + - standard + - extended + ipv4: true + neighbors: + - activate: + ipv4: true + as: 65000 + ifindex: 1 + ipv4: 10.1.0.5 + name: dut + type: ebgp + next_hop_self: true + router_id: 10.0.0.3 + box: none + device: none + id: 3 + interfaces: + - ifindex: 1 + ifname: eth1 + ipv4: 10.1.0.6/30 + linkindex: 2 + name: x2 -> dut + neighbors: + - bgp: + default_originate: true + ifname: eth2 + ipv4: 10.1.0.5/30 + node: dut + role: external + type: p2p + loopback: + bgp: + advertise: true + ifindex: 0 + ifname: Loopback0 + ipv4: 10.0.0.3/32 + neighbors: [] + type: loopback + virtual_interface: true + mgmt: + ifname: eth0 + ipv4: 192.168.121.103 + mac: ca:fe:00:03:00:00 + module: + - bgp + name: x2 +plugin: +- bgp.session +provider: libvirt +vrf: + as: 65000 +vrfs: + t1: + export: + - '65000:1' + id: 1 + import: + - '65000:1' + rd: '65000:1' + t2: + export: + - '65000:2' + id: 2 + import: + - '65000:2' + rd: '65000:2' diff --git a/tests/coverage/input/bgp-default.yml b/tests/coverage/input/bgp-default.yml new file mode 100644 index 0000000000..e3f27b3f6e --- /dev/null +++ b/tests/coverage/input/bgp-default.yml @@ -0,0 +1,37 @@ +message: | + Checks the default static route origination needed to originate the + BGP default route(s) + +defaults.device: none +module: [ bgp ] +plugin: [ bgp.session ] + +vrfs: + t1: + t2: + +nodes: + dut: + module: [ bgp, vrf ] + bgp.as: 65000 + _features.bgp.default_originate: static + x1: + bgp.as: 65001 + x2: + bgp.as: 65002 + v1: + bgp.as: 65100 + v2: + bgp.as: 65101 + +links: +- dut.bgp.default_originate: True + x1: +- dut.bgp.default_originate: True + x2: +- dut.bgp.default_originate: True + v1: + vrf: t1 +- dut.bgp.default_originate: True + v2: + vrf: t1