Skip to content

Commit 3ee233a

Browse files
authored
Add module data to VLAN neighbors (ipspace#2696)
* Copy node VLAN data to interface data during link_pre_transform to have them available when the neighbor list is built during link transformation * Copy most of the SVI interface data to the neighbor data structure when recreating the VLAN-wide neighbor list Also: * Fix the DHCP attributes in the neighbor data to reflect the final state of the device interfaces. This allows the 'get gw of last resort' function to return the actual default gateway * Add an optional 'limit merge to these attributes' parameter to the 'data.merge_with_removed_attributes' utility function * An IRB VLAN was added to the 'bgp-ibgp-localas' integration test as a regression test for ipspace#2615 Fixes ipspace#2615
1 parent 90efe4a commit 3ee233a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2639
-457
lines changed

netsim/data/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,12 @@ def removed_attributes(data: Box, path: str) -> bool:
7070
"""
7171
Merge two dictionaries considering removed attributes
7272
"""
73-
def merge_with_removed_attributes(d_to: Box, d_with: Box) -> Box:
73+
def merge_with_removed_attributes(d_to: Box, d_with: Box, m_scope: typing.Optional[list] = None) -> Box:
7474
for k in d_with.keys():
7575
if k in d_to.get('_removed_attr',[]):
7676
continue
77+
if m_scope is not None and k not in m_scope:
78+
continue
7779
if not k in d_to:
7880
d_to[k] = d_with[k]
7981
elif isinstance(d_to[k],Box) and isinstance(d_with[k],Box):

netsim/modules/dhcp.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,19 @@ def check_protocol_support(node: Box, topology: Box) -> bool:
122122
call the routing module "get me default gateway of last resort" function
123123
'''
124124
def get_gateway_data(link: Box, topology: Box) -> Box:
125-
if isinstance(link.get('gateway',None),Box):
126-
return link.gateway
125+
if isinstance(link.get('gateway',None),Box): # Do we have on-link gateway data
126+
return link.gateway # Cool, return that
127127

128-
ifdata = data.get_box({'neighbors': link.get('neighbors',[] )})
129-
(gw_data,u_flag) = routing.create_gateway_last_resort(ifdata,data.get_box({'ipv4': True}),topology)
128+
link_ngb = link.get('neighbors',[]) # Get link neighbors
129+
for ngb in link_ngb: # Fix DHCP relays that also have DHCP client information
130+
if ngb.get('dhcp.server'): # ... because that attribute will get removed from the
131+
ngb.dhcp.pop('client',None) # ... interface data anyway and just throws off the next function
132+
133+
ifdata = data.get_box({'neighbors': link_ngb }) # Now create a fake interface data structure
134+
135+
# Try to get the gateway-of-last-resort from the fake "interface" neighbors
136+
#
137+
(gw_data,_) = routing.create_gateway_last_resort(ifdata,data.get_box({'ipv4': True}),topology)
130138
return gw_data
131139

132140
'''
@@ -169,7 +177,7 @@ def build_topology_dhcp_pools(topology: Box) -> None:
169177

170178
# Phase 2: Iterate over node interfaces, find SVIs, and build excluded IP list
171179
#
172-
for node,ndata in topology.get('nodes',{}).items():
180+
for _,ndata in topology.get('nodes',{}).items():
173181
for intf in ndata.get('interfaces',[]):
174182
vname = intf.get('vlan.name')
175183
if not vname:

netsim/modules/vlan.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -759,21 +759,19 @@ def update_vlan_neighbor_list(vlan: str, phy_if: Box, svi_if: Box, node: Box,top
759759
phy_n_list = phy_if.get('neighbors',[]) # ... add interface neighbors not yet in the list
760760
vlan_data.neighbors.extend([n_data for n_data in phy_n_list if n_data.node not in n_map])
761761

762-
if node.name in n_map: # Is the current node in the list?
763-
n_map[node.name].ifname = svi_if.ifname # ... it is, fix the interface name
764-
for af in ('ipv4','ipv6'):
765-
if af in svi_if:
766-
n_map[node.name][af] = svi_if[af]
767-
else:
768-
n_map[node.name].pop(af,None)
762+
svi_info = node.get('module',[]) + list(log.AF_LIST) # Include SVI module and address information
763+
svi_ifdata = get_box({ 'ifname': svi_if.ifname, 'node': node.name }) # Prepare SVI interface data for neighbor list
764+
svi_ifdata += { k:v for k,v in svi_if.items() if k in svi_info } # Copy relevant SVI info into neighbor entry
765+
766+
if node.name in n_map:
767+
# The current node data must be based on physical interfaces
768+
# Remove the current node from the neighbor list and add the SVI information
769+
#
770+
vlan_data.neighbors = [ n for n in vlan_data.neighbors if n.node != node.name ] + [ svi_ifdata ]
769771
else:
770-
n_data = data.get_box({
771-
'ifname': svi_if.ifname,
772-
'node': node.name }) # ... not yet, create neighbor data
773-
for af in ('ipv4','ipv6'):
774-
if af in svi_if: # ... copy SVI interface addresses to neighbor data
775-
n_data[af] = svi_if[af]
776-
vlan_data.neighbors.append(n_data) # Add current node as a neighbor to VLAN neighbor list
772+
# The current node is not yet in the VLAN neighbor list, add the SVI information
773+
#
774+
vlan_data.neighbors.append(svi_ifdata)
777775

778776
"""
779777
create_node_vlan: Create a local (node) copy of a VLAN used on an interface
@@ -1389,6 +1387,12 @@ def link_pre_link_transform(self, link: Box, topology: Box) -> None:
13891387
for attr in topology.defaults.vlan.attributes.copy_vlan_to_intf:
13901388
if attr in vdata:
13911389
intf[attr] = vdata[attr]
1390+
1391+
# Finally, copy module attributes from node VLAN data to access interface data
1392+
# These attributes will be used to populate neighbor's "neighbor" list in VLANs
1393+
# with mode = route. We have to fix the IRB neighbors when rebuilding neighbor list.
1394+
#
1395+
data.merge_with_removed_attributes(intf,vdata,topology.nodes[intf.node].get('module',[]))
13921396

13931397
"""
13941398
We're almost done, but there's still some hard work to do:

tests/topology/expected/addressing-prefix.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ vlans:
241241
- ifname: Vlan1000
242242
ipv6: 2001:db8:cafe:1::2a/64
243243
node: r1
244+
vlan:
245+
mode: irb
246+
name: v1
244247
prefix:
245248
_name: s2
246249
allocation: id_based

tests/topology/expected/anycast-gateway.yml

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,39 @@ nodes:
507507
linkindex: 2
508508
name: h3 -> [r1,h4,r2]
509509
neighbors:
510-
- ifname: Vlan1000
510+
- gateway:
511+
anycast:
512+
mac: 0200.cafe.00ff
513+
unicast: true
514+
id: 1
515+
ipv4: 172.16.0.1/24
516+
protocol: anycast
517+
vrrp:
518+
group: 1
519+
ifname: Vlan1000
511520
ipv4: 172.16.0.2/24
512521
node: r1
522+
vlan:
523+
mode: irb
524+
name: red
513525
- ifname: eth1
514526
ipv4: 172.16.0.13/24
515527
node: h4
516-
- ifname: Vlan1000
528+
- gateway:
529+
anycast:
530+
mac: 0200.cafe.00ff
531+
unicast: true
532+
id: 1
533+
ipv4: 172.16.0.1/24
534+
protocol: anycast
535+
vrrp:
536+
group: 1
537+
ifname: Vlan1000
517538
ipv4: 172.16.0.3/24
518539
node: r2
540+
vlan:
541+
mode: irb
542+
name: red
519543
type: lan
520544
mgmt:
521545
ifname: eth0
@@ -574,12 +598,36 @@ nodes:
574598
- ifname: eth1
575599
ipv4: 172.16.0.7/24
576600
node: h3
577-
- ifname: Vlan1000
601+
- gateway:
602+
anycast:
603+
mac: 0200.cafe.00ff
604+
unicast: true
605+
id: 1
606+
ipv4: 172.16.0.1/24
607+
protocol: anycast
608+
vrrp:
609+
group: 1
610+
ifname: Vlan1000
578611
ipv4: 172.16.0.2/24
579612
node: r1
580-
- ifname: Vlan1000
613+
vlan:
614+
mode: irb
615+
name: red
616+
- gateway:
617+
anycast:
618+
mac: 0200.cafe.00ff
619+
unicast: true
620+
id: 1
621+
ipv4: 172.16.0.1/24
622+
protocol: anycast
623+
vrrp:
624+
group: 1
625+
ifname: Vlan1000
581626
ipv4: 172.16.0.3/24
582627
node: r2
628+
vlan:
629+
mode: irb
630+
name: red
583631
type: lan
584632
- bridge: input_4
585633
gateway:
@@ -863,9 +911,21 @@ nodes:
863911
- ifname: eth1
864912
ipv4: 172.16.0.13/24
865913
node: h4
866-
- ifname: Vlan1000
914+
- gateway:
915+
anycast:
916+
mac: 0200.cafe.00ff
917+
unicast: true
918+
id: 1
919+
ipv4: 172.16.0.1/24
920+
protocol: anycast
921+
vrrp:
922+
group: 1
923+
ifname: Vlan1000
867924
ipv4: 172.16.0.3/24
868925
node: r2
926+
vlan:
927+
mode: irb
928+
name: red
869929
ospf:
870930
area: 0.0.0.0
871931
passive: false
@@ -1079,9 +1139,21 @@ nodes:
10791139
- ifname: eth1
10801140
ipv4: 172.16.0.7/24
10811141
node: h3
1082-
- ifname: Vlan1000
1142+
- gateway:
1143+
anycast:
1144+
mac: 0200.cafe.00ff
1145+
unicast: true
1146+
id: 1
1147+
ipv4: 172.16.0.1/24
1148+
protocol: anycast
1149+
vrrp:
1150+
group: 1
1151+
ifname: Vlan1000
10831152
ipv4: 172.16.0.2/24
10841153
node: r1
1154+
vlan:
1155+
mode: irb
1156+
name: red
10851157
- ifname: eth1
10861158
ipv4: 172.16.0.13/24
10871159
node: h4
@@ -1203,15 +1275,39 @@ vlans:
12031275
- ifname: eth1
12041276
ipv4: 172.16.0.7/24
12051277
node: h3
1206-
- ifname: Vlan1000
1278+
- gateway:
1279+
anycast:
1280+
mac: 0200.cafe.00ff
1281+
unicast: true
1282+
id: 1
1283+
ipv4: 172.16.0.1/24
1284+
protocol: anycast
1285+
vrrp:
1286+
group: 1
1287+
ifname: Vlan1000
12071288
ipv4: 172.16.0.2/24
12081289
node: r1
1290+
vlan:
1291+
mode: irb
1292+
name: red
12091293
- ifname: eth1
12101294
ipv4: 172.16.0.13/24
12111295
node: h4
1212-
- ifname: Vlan1000
1296+
- gateway:
1297+
anycast:
1298+
mac: 0200.cafe.00ff
1299+
unicast: true
1300+
id: 1
1301+
ipv4: 172.16.0.1/24
1302+
protocol: anycast
1303+
vrrp:
1304+
group: 1
1305+
ifname: Vlan1000
12131306
ipv4: 172.16.0.3/24
12141307
node: r2
1308+
vlan:
1309+
mode: irb
1310+
name: red
12151311
prefix:
12161312
allocation: id_based
12171313
ipv4: 172.16.0.0/24

0 commit comments

Comments
 (0)