Skip to content

Commit

Permalink
Unify loopback and virtual interface processing
Browse files Browse the repository at this point in the history
* Change 'create_loopback_interface' into a framework that supports
  multiple virtual interface types
* Assign virtual interface ifindex based on existing interfaces of the
  same virtual interface type
* Create interface name from device template or use 'ifname' if there
  is no device interface-specific name template
* Adjust ifindex based on virtual interface type to prevent clashes
  with physical or other virtual interfaces
* Use common framework when creating VRF loopbacks
  • Loading branch information
ipspace committed Apr 16, 2023
1 parent 60ebd84 commit 0b20f69
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 96 deletions.
48 changes: 32 additions & 16 deletions netsim/augment/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from .. import addressing
from . import devices

VIRTUAL_INTERFACE_TYPES: typing.Final[typing.List[str]] = [ 'loopback', 'tunnel' ]

def adjust_interface_list(iflist: list, link: Box, nodes: Box) -> list:
link_intf = []
intf_cnt = 0
Expand Down Expand Up @@ -202,7 +204,10 @@ def create_regular_interface(node: Box, ifdata: Box, defaults: Box) -> None:

# When computing default ifindex, consider only non-loopback interfaces
if not ifindex:
ifindex = len([intf for intf in node.interfaces if intf.get('type',None) != 'loopback']) + ifindex_offset
ifindex = len([
intf for intf in node.interfaces
if not intf.get('type',None) in VIRTUAL_INTERFACE_TYPES
]) + ifindex_offset

ifname_format = devices.get_device_attribute(node,'interface_name',defaults)

Expand All @@ -219,31 +224,42 @@ def create_regular_interface(node: Box, ifdata: Box, defaults: Box) -> None:
provider = devices.get_provider(node,defaults)
ifdata[provider] = pdata

def create_loopback_interface(node: Box, ifdata: Box, defaults: Box) -> None:
ifindex_offset = devices.get_device_attribute(node,'loopback_offset',defaults) or 0
ifdata.ifindex = ifindex_offset + ifdata.linkindex
def create_virtual_interface(node: Box, ifdata: Box, defaults: Box) -> None:
devtype = ifdata.get('type','loopback') # Get virtual interface type, default to loopback interface
ifindex_offset = (
devices.get_device_attribute(node,f'{devtype}_offset',defaults) or
1 if devtype == 'loopback' else 0) # Loopback interfaces have to start with 1 to prevent overlap with built-in loopback

ifdata.virtual_interface = True
ifname_format = devices.get_device_attribute(node,'loopback_interface_name',defaults)
if not 'ifindex' in ifdata:
ifdata.ifindex = len([intf for intf in node.interfaces if intf.get('type',None) == devtype]) + ifindex_offset
ifname_format = devices.get_device_attribute(node,f'{devtype}_interface_name',defaults)

if not ifname_format:
common.error(
f'Device {node.device}/node {node.name} does not support loopback links',
common.IncorrectValue,
'links')
return
if devtype == 'loopback':
common.error(
f'Device {node.device}/node {node.name} does not support loopback links',
common.IncorrectValue,
'links')
return
else:
common.error(
f'Need explicit interface name (ifname) for {devtype} interface on node {node.name} ({node.device})',
common.IncorrectValue,
'links')
return

if not 'ifname' in ifdata:
ifdata.ifname = utils.strings.eval_format(ifname_format,ifdata)

# If the device uses 'loopback_offset' then we're assuming it's large enough to prevent overlap with physical interfaces
# Otherwise, create fake ifindex for loopback interfaces to prevent that overlap
# Adjust ifindex to prevent overlap between device types
#
if not ifindex_offset:
ifdata.ifindex = 10000 + ifdata.ifindex
ifindex_offset = (VIRTUAL_INTERFACE_TYPES.index(devtype)+1) * 10000
ifdata.ifindex += ifindex_offset

def add_node_interface(node: Box, ifdata: Box, defaults: Box) -> Box:
if ifdata.get('type') == 'loopback':
create_loopback_interface(node,ifdata,defaults)
if ifdata.get('type',None) in VIRTUAL_INTERFACE_TYPES:
create_virtual_interface(node,ifdata,defaults)
else:
create_regular_interface(node,ifdata,defaults)

Expand Down
16 changes: 8 additions & 8 deletions netsim/modules/vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,7 @@ def validate_vrf_route_leaking(node : Box) -> None:
'vrf')

def vrf_loopbacks(node : Box, topology: Box) -> None:
loopback_name = devices.get_device_attribute(node,'loopback_interface_name',topology.defaults) or \
devices.get_device_attribute(node,'features.vrf.loopback_interface_name',topology.defaults)
loopback_name = devices.get_device_attribute(node,'loopback_interface_name',topology.defaults)

if not loopback_name: # pragma: no cover -- hope we got device settings right ;)
common.print_verbose(f'Device {node.device} used by {node.name} does not support VRF loopback interfaces - skipping assignment.')
Expand All @@ -265,19 +264,20 @@ def vrf_loopbacks(node : Box, topology: Box) -> None:
node = node,
topology = topology)
for vrfname,v in node.vrfs.items():
vrf_loopback = v.get('loopback',None) or node_vrf_loopback # Do we have VRF loopbacks enabled in the node or in the VRF?
if not vrf_loopback: # ... nope, move on
vrf_loopback = v.get('loopback',None) or node_vrf_loopback # Do we have VRF loopbacks enabled in the node or in the VRF?
if not vrf_loopback: # ... nope, move on
continue

ifdata = data.get_box({
'virtual_interface': True,
# Note: set interface ifindex to v.vrfidx if you want to have VRF-numbered loopbacks
#
ifdata = data.get_box({ # Create interface data structure
'type': "loopback",
'name': f'VRF Loopback {vrfname}',
'ifindex': node.interfaces[-1].ifindex + 1,
'ifname': loopback_name.format(vrfidx=v.vrfidx,ifindex=v.vrfidx), # Use VRF-specific and generic loopback index
'neighbors': [],
'vrf': vrfname,})

links.create_virtual_interface(node,ifdata,topology.defaults) # Use common function to create loopback interface

if isinstance(vrf_loopback,bool):
vrfaddr = addressing.get(topology.pools, ['vrf_loopback'])
else:
Expand Down
8 changes: 4 additions & 4 deletions tests/topology/expected/bgp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ links:
ipv4: 172.16.1.0/24
type: stub
- interfaces:
- ifindex: 10009
ifname: Loopback9
- ifindex: 10001
ifname: Loopback1
ipv4: 172.16.2.6/24
node: e2
linkindex: 9
Expand Down Expand Up @@ -302,8 +302,8 @@ nodes:
type: stub
- bgp:
advertise: true
ifindex: 10009
ifname: Loopback9
ifindex: 10001
ifname: Loopback1
ipv4: 172.16.2.6/24
linkindex: 9
name: e2 -> stub
Expand Down
24 changes: 12 additions & 12 deletions tests/topology/expected/group-data-vrf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ nodes:
vrf: red
type: p2p
vrf: red
- ifindex: 2
ifname: Loopback101
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.1/32
name: VRF Loopback red
neighbors: []
type: loopback
virtual_interface: true
vrf: red
- ifindex: 3
ifname: Loopback100
- ifindex: 10002
ifname: Loopback2
ipv4: 10.2.0.2/32
name: VRF Loopback blue
neighbors: []
Expand Down Expand Up @@ -134,8 +134,8 @@ nodes:
passive: false
type: p2p
vrf: red
- ifindex: 2
ifname: Loopback101
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.1/32
name: VRF Loopback red
neighbors: []
Expand Down Expand Up @@ -168,16 +168,16 @@ nodes:
vrf: red
type: p2p
vrf: red
- ifindex: 2
ifname: Loopback101
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.3/32
name: VRF Loopback red
neighbors: []
type: loopback
virtual_interface: true
vrf: red
- ifindex: 3
ifname: Loopback100
- ifindex: 10002
ifname: Loopback2
ipv4: 10.2.0.4/32
name: VRF Loopback blue
neighbors: []
Expand Down Expand Up @@ -244,8 +244,8 @@ nodes:
passive: false
type: p2p
vrf: red
- ifindex: 2
ifname: Loopback101
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.3/32
name: VRF Loopback red
neighbors: []
Expand Down
8 changes: 4 additions & 4 deletions tests/topology/expected/igp-af.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ links:
role: stub
type: stub
- interfaces:
- ifindex: 10006
ifname: Loopback6
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.1/32
ipv6: 2001:db8:cafe::5/64
node: r5
Expand Down Expand Up @@ -394,8 +394,8 @@ nodes:
passive: true
role: stub
type: stub
- ifindex: 10006
ifname: Loopback6
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.1/32
ipv6: 2001:db8:cafe::5/64
isis:
Expand Down
32 changes: 16 additions & 16 deletions tests/topology/expected/link-loopback.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ links:
ipv4: 172.16.0.0/24
type: lan
- interfaces:
- ifindex: 10002
ifname: Loopback2
- ifindex: 10001
ifname: Loopback1
ipv4: 172.16.1.1/24
node: r1
linkindex: 2
Expand All @@ -35,8 +35,8 @@ links:
ipv4: 172.16.2.0/24
type: stub
- interfaces:
- ifindex: 10004
ifname: Loopback4
- ifindex: 10001
ifname: Loopback1
ipv4: 10.1.0.1/32
node: r2
linkindex: 4
Expand All @@ -45,8 +45,8 @@ links:
ipv4: 172.16.3.0/24
type: loopback
- interfaces:
- ifindex: 10005
ifname: Loopback5
- ifindex: 10002
ifname: Loopback2
ipv4: 10.1.0.2/32
node: r1
linkindex: 5
Expand All @@ -55,8 +55,8 @@ links:
ipv4: 10.1.0.2/32
type: loopback
- interfaces:
- ifindex: 10006
ifname: Loopback6
- ifindex: 10003
ifname: Loopback3
ipv4: 10.2.0.1/32
node: r1
linkindex: 6
Expand Down Expand Up @@ -96,24 +96,24 @@ nodes:
device: eos
id: 1
interfaces:
- ifindex: 10002
ifname: Loopback2
- ifindex: 10001
ifname: Loopback1
ipv4: 172.16.1.1/24
linkindex: 2
name: r1 -> stub
neighbors: []
type: loopback
virtual_interface: true
- ifindex: 10005
ifname: Loopback5
- ifindex: 10002
ifname: Loopback2
ipv4: 10.1.0.2/32
linkindex: 5
name: r1 -> stub
neighbors: []
type: loopback
virtual_interface: true
- ifindex: 10006
ifname: Loopback6
- ifindex: 10003
ifname: Loopback3
ipv4: 10.2.0.1/32
linkindex: 6
name: r1 -> stub
Expand Down Expand Up @@ -144,8 +144,8 @@ nodes:
name: r2 -> stub
neighbors: []
type: stub
- ifindex: 10004
ifname: Loopback4
- ifindex: 10001
ifname: Loopback1
ipv4: 10.1.0.1/32
linkindex: 4
name: r2 -> stub
Expand Down
16 changes: 8 additions & 8 deletions tests/topology/expected/vrf-igp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ nodes:
vrf: blue
type: p2p
vrf: blue
- ifindex: 4
ifname: Loopback101
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.1/32
name: VRF Loopback blue
neighbors: []
Expand Down Expand Up @@ -255,8 +255,8 @@ nodes:
passive: false
type: p2p
vrf: blue
- ifindex: 4
ifname: Loopback101
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.1/32
name: VRF Loopback blue
neighbors: []
Expand Down Expand Up @@ -360,8 +360,8 @@ nodes:
node: r3
type: p2p
vrf: blue
- ifindex: 4
ifname: Loopback100
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.2/32
name: VRF Loopback blue
neighbors: []
Expand Down Expand Up @@ -441,8 +441,8 @@ nodes:
passive: false
type: p2p
vrf: blue
- ifindex: 4
ifname: Loopback100
- ifindex: 10001
ifname: Loopback1
ipv4: 10.2.0.2/32
name: VRF Loopback blue
neighbors: []
Expand Down
Loading

0 comments on commit 0b20f69

Please sign in to comment.