@@ -1102,6 +1102,67 @@ def copy_link_gateway(link: Box, nodes: Box) -> None:
11021102 if af in link .gateway :
11031103 intf .gateway [af ] = link .gateway [af ]
11041104
1105+ """
1106+ process_link_ra -- copy link IPv6 RA parameters to node-on-link (future interface) data
1107+
1108+ The link.ra attributes are copied only into the router nodes that support RA
1109+ (features.initial.ra). _netlab_ creates a warning message if a link has an 'ra'
1110+ dictionary but no routers attached, or if no routers attached to the link supports
1111+ 'ra' attribute.
1112+
1113+ Furthermore, when there are no link/intf RA settings, all routers supporting 'ra'
1114+ attributes get the default RA settings when there are hosts attached to the link,
1115+ hopefully simplifying the configuration templates.
1116+
1117+ TODO: If a router is a DHCP relay and supports 'ra', 'ra.dhcp' should be set to 'all'
1118+ """
1119+
1120+ def process_link_ra (link : Box , nodes : Box , defaults : Box ) -> None :
1121+ if 'ra' not in link and not link .get ('prefix.ipv6' ,None ): # Processing RAs makes sense only if
1122+ return # the link contains RA attribute(s) or uses IPv6
1123+
1124+ # Get a list of routers and hosts
1125+ rtr_list = [ intf for intf in link .interfaces if nodes [intf .node ].get ('role' ,'router' ) == 'router' ]
1126+ host_list = [ intf for intf in link .interfaces if nodes [intf .node ].get ('role' ,'' ) == 'host' ]
1127+
1128+ if 'ra' in link and not rtr_list : # Link RA attribute with no hosts attached
1129+ log .warning (
1130+ text = 'Cannot use link IPv6 RA attributes on link {link._linkname} with no routers' ,
1131+ module = 'links' ,flag = 'ra_useless' )
1132+ return
1133+
1134+ if 'ra' not in link and not host_list : # No link RA attributes, no attached hosts
1135+ return # ... there's nothing for us to do
1136+
1137+ if not rtr_list : # No hosts, no routers... what are we doing here?
1138+ return
1139+
1140+ ra_supported = False # Does at least one router support RA attributes?
1141+ link_ra = link .get ('ra' ,{})
1142+ for intf in rtr_list : # Now iterate over routers attached to the link
1143+ n_data = nodes [intf .node ]
1144+ d_features = devices .get_device_features (n_data ,defaults )
1145+ if not d_features .initial .ra : # The router does not support the RA attributes
1146+ if 'ra' in intf :
1147+ log .error (
1148+ f'We did not implement configurable IPv6 RA parameters for { n_data .device } yet' ,
1149+ category = log .IncorrectAttr ,
1150+ module = 'links' ,
1151+ more_data = 'Node {intf.node}, link {link._linkname}' )
1152+ continue
1153+ if 'ra' in intf or link_ra :
1154+ intf .ra = link_ra + intf .ra # Merge link attributes with interface attributes
1155+ elif host_list :
1156+ intf .ra .slaac = True
1157+ ra_supported = True
1158+
1159+ if link_ra and not ra_supported : # At least one node on the link supports RA
1160+ log .warning (
1161+ text = 'None of the routers connected to link {link._linkname} supports netlab IPv6 RA attributes' ,
1162+ module = 'links' ,flag = 'ra_unsupported' )
1163+
1164+ return
1165+
11051166"""
11061167Set node.af flags to indicate that the node has IPv4 and/or IPv6 address family configured on its interfaces
11071168"""
@@ -1250,6 +1311,7 @@ def transform(link_list: typing.Optional[Box], defaults: Box, nodes: Box, pools:
12501311 link_default_pools .append ('lan' )
12511312 assign_link_prefix (link ,link_default_pools ,pools ,nodes ,link ._linkname )
12521313 copy_link_gateway (link ,nodes )
1314+ process_link_ra (link ,nodes ,defaults )
12531315 assign_interface_addresses (link ,pools ,nodes ,defaults )
12541316 create_node_interfaces (link ,pools ,nodes ,defaults = defaults )
12551317
0 commit comments