Skip to content

Commit

Permalink
Rewrite bgp.session plugin to use BGP neighbor generators
Browse files Browse the repository at this point in the history
  • Loading branch information
ipspace committed Oct 11, 2023
1 parent de31691 commit 36a272f
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 29 deletions.
39 changes: 12 additions & 27 deletions netsim/extra/bgp.session/plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from box import Box
from netsim.utils import log
from netsim.utils import log,bgp as _bgp
from netsim import api
from netsim.augment import devices

Expand Down Expand Up @@ -36,35 +36,27 @@ def check_device_attribute_support(attr: str, ndata: Box, neigh: Box, topology:
because they are neighbors' attributes, not ours
'''
def cleanup_neighbor_attributes(ndata: Box, topology: Box) -> None:
for attr in topology.defaults.bgp.attributes.ebgp_utils.local:
for neigh in ndata.get('bgp', {}).get('neighbors', []):
neigh.pop(attr,None)

for vdata in ndata.get('vrfs',{}):
if not vdata.get('bgp.neighbors',None):
continue
for neigh in vdata.bgp.neighbors:
neigh.pop(attr,None)
for ngb in _bgp.neighbors(ndata):
for attr in topology.defaults.bgp.attributes.ebgp_utils.local:
ngb.pop(attr,None)

'''
Copy local session attributes to BGP neighbors because we need
them there in the configuration templates
'''
def copy_local_attributes(ndata: Box, topology: Box) -> None:
config_name = api.get_config_name(globals()) # Get the plugin configuration name

# Iterate over all ebgp.utils link/interface attributes
for intf in ndata.interfaces:
for (intf,ngb) in _bgp.intf_neighbors(ndata):
for attr in topology.defaults.bgp.attributes.ebgp_utils.attr:
attr_value = intf.get('bgp',{}).get(attr,None) or ndata.bgp.get(attr,None)
if not attr_value: # Attribute not defined in node or interface, move on
continue

# Iterate over all BGP neighbors trying to find neighbors on this interface
for neigh in ndata.get('bgp', {}).get('neighbors', []):
if neigh.type == 'ebgp' and neigh.ifindex == intf.ifindex:
check_device_attribute_support(attr,ndata,neigh,topology)
neigh[attr] = attr_value # Found the neighbor, set neighbor attribute
api.node_config(ndata,config_name) # And remember that we have to do extra configuration
check_device_attribute_support(attr,ndata,ngb,topology)
ngb[attr] = attr_value # Set neighbor attribute from interface/node value
api.node_config(ndata,config_name) # And remember that we have to do extra configuration

if 'vrf' not in intf: # Not a VRF interface?
continue # ... great, move on
Expand Down Expand Up @@ -95,16 +87,9 @@ def process_tcpao_password(neigh: Box, ndata: Box) -> None:
ndata.bgp._ao_secrets.append(pwd)

def process_tcpao_secrets(ndata: Box,topology: Box) -> None:
for neigh in ndata.get('bgp', {}).get('neighbors', []):
if 'tcp_ao' in neigh:
process_tcpao_password(neigh,ndata)

for vdata in ndata.get('vrfs',{}):
if not vdata.get('bgp.neighbors',None):
continue
for neigh in vdata.bgp.neighbors:
if 'tcp_ao' in neigh:
process_tcpao_password(neigh,ndata)
for ngb in _bgp.neighbors(ndata):
if 'tcp_ao' in ngb:
process_tcpao_password(ngb,ndata)

'''
post_transform hook
Expand Down
34 changes: 34 additions & 0 deletions netsim/utils/bgp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# BGP neighbor traversal utilities
#

from box import Box
import typing

# Return all global and optionaly VRF neighbors
#
def neighbors(node: Box, vrf: bool = True) -> typing.Generator:
for ngb in node.get('bgp.neighbors',[]):
yield ngb

if not vrf:
return

for vdata in node.get('vrfs',{}).values():
for ngb in vdata.get('bgp.neighbors',[]):
yield ngb

# Return all BGP neighbors associated with interfaces (usually EBGP neighbors)
#
def intf_neighbors(node: Box, vrf: bool = True) -> typing.Generator:
for intf in node.interfaces:
if 'vrf' in intf:
if not vrf:
continue
for ngb in node.vrfs[intf.vrf].get('bgp.neighbors',[]):
if ngb.get('ifindex',None) == intf.ifindex:
yield (intf,ngb)
else:
for ngb in node.get('bgp.neighbors',[]):
if ngb.get('ifindex',None) == intf.ifindex:
yield (intf,ngb)
121 changes: 121 additions & 0 deletions tests/topology/expected/ebgp.utils.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,37 @@ links:
ipv4: 10.1.0.4/30
role: external
type: p2p
- bgp:
password: InVrf
interfaces:
- bgp:
default_originate: true
ifindex: 3
ifname: Ethernet3
ipv4: 10.1.0.9/30
node: r1
- bgp:
allowas_in: 1
ifindex: 2
ifname: Ethernet2
ipv4: 10.1.0.10/30
node: r2
linkindex: 3
node_count: 2
prefix:
ipv4: 10.1.0.8/30
role: external
type: p2p
vrf: red
module:
- bgp
- vrf
name: input
nodes:
r1:
af:
ipv4: true
vpnv4: true
bgp:
advertise_loopback: true
as: 65001
Expand Down Expand Up @@ -149,6 +173,25 @@ nodes:
node: r3
role: external
type: p2p
- bgp:
default_originate: true
password: InVrf
ifindex: 3
ifname: Ethernet3
ipv4: 10.1.0.9/30
linkindex: 3
name: r1 -> r2
neighbors:
- bgp:
allowas_in: 1
password: InVrf
ifname: Ethernet2
ipv4: 10.1.0.10/30
node: r2
vrf: red
role: external
type: p2p
vrf: red
loopback:
ipv4: 10.0.0.1/32
mgmt:
Expand All @@ -157,10 +200,34 @@ nodes:
mac: 08:4f:a9:00:00:01
module:
- bgp
- vrf
name: r1
vrf:
as: 65000
vrfs:
red:
af:
ipv4: true
bgp:
neighbors:
- as: 65002
default_originate: true
ifindex: 3
ipv4: 10.1.0.10
name: r2
password: InVrf
type: ebgp
export:
- '65000:1'
id: 1
import:
- '65000:1'
rd: '65000:1'
vrfidx: 100
r2:
af:
ipv4: true
vpnv4: true
bgp:
advertise_loopback: true
as: 65002
Expand Down Expand Up @@ -210,6 +277,25 @@ nodes:
node: r1
role: external
type: p2p
- bgp:
allowas_in: 1
password: InVrf
ifindex: 2
ifname: Ethernet2
ipv4: 10.1.0.10/30
linkindex: 3
name: r2 -> r1
neighbors:
- bgp:
default_originate: true
password: InVrf
ifname: Ethernet3
ipv4: 10.1.0.9/30
node: r1
vrf: red
role: external
type: p2p
vrf: red
loopback:
ipv4: 10.0.0.2/32
mgmt:
Expand All @@ -218,7 +304,30 @@ nodes:
mac: 08:4f:a9:00:00:02
module:
- bgp
- vrf
name: r2
vrf:
as: 65000
vrfs:
red:
af:
ipv4: true
bgp:
neighbors:
- allowas_in: 1
as: 65001
ifindex: 2
ipv4: 10.1.0.9
name: r1
password: InVrf
type: ebgp
export:
- '65000:1'
id: 1
import:
- '65000:1'
rd: '65000:1'
vrfidx: 100
r3:
af:
ipv4: true
Expand Down Expand Up @@ -286,7 +395,19 @@ nodes:
module:
- bgp
name: r3
vrf:
as: 65000
plugin:
- bgp.session
- ebgp.multihop
provider: libvirt
vrf:
as: 65000
vrfs:
red:
export:
- '65000:1'
id: 1
import:
- '65000:1'
rd: '65000:1'
13 changes: 11 additions & 2 deletions tests/topology/input/ebgp.utils.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
#
# Testing ebgp-utils plugin
#
plugin: [ ebgp.multihop,ebgp.utils ]
module: [ bgp ]
plugin: [ ebgp.multihop,bgp.session ]
module: [ bgp,vrf ]
defaults.device: eos
bgp.password: Secret

vrfs:
red:
links:
- r1:
bgp.default_originate: True
r2:
bgp.allowas_in: True
bgp.password: InVrf

bgp.multihop.sessions:
- r2:
r3:
Expand Down

0 comments on commit 36a272f

Please sign in to comment.