Skip to content

Commit 7d06c7f

Browse files
lolyuyxieca
authored andcommitted
[minigraph][dualtor] Support parsing soc_ip out of dpg (#11207)
Why I did it To further support parse out soc_ipv4 and soc_ipv6 out of Dpg: <DeviceDataPlaneInfo> <IPSecTunnels /> <LoopbackIPInterfaces xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution"> <a:LoopbackIPInterface> <ElementType>LoopbackInterface</ElementType> <Name>HostIP</Name> <AttachTo>Loopback0</AttachTo> <a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux"> <b:IPPrefix>10.10.10.2/32</b:IPPrefix> </a:Prefix> <a:PrefixStr>10.10.10.2/32</a:PrefixStr> </a:LoopbackIPInterface> <a:LoopbackIPInterface> <ElementType>LoopbackInterface</ElementType> <Name>HostIP1</Name> <AttachTo>Loopback0</AttachTo> <a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux"> <b:IPPrefix>fe80::0002/128</b:IPPrefix> </a:Prefix> <a:PrefixStr>fe80::0002/128</a:PrefixStr> </a:LoopbackIPInterface> <a:LoopbackIPInterface> <ElementType>LoopbackInterface</ElementType> <Name>SoCHostIP0</Name> <AttachTo>server2SOC</AttachTo> <a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux"> <b:IPPrefix>10.10.10.3/32</b:IPPrefix> </a:Prefix> <a:PrefixStr>10.10.10.3/32</a:PrefixStr> </a:LoopbackIPInterface> <a:LoopbackIPInterface> <ElementType>LoopbackInterface</ElementType> <Name>SoCHostIP1</Name> <AttachTo>server2SOC</AttachTo> <a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux"> <b:IPPrefix>fe80::0003/128</b:IPPrefix> </a:Prefix> <a:PrefixStr>fe80::0003/128</a:PrefixStr> </a:LoopbackIPInterface> </LoopbackIPInterfaces> </DeviceDataPlaneInfo> Signed-off-by: Longxiang Lyu [email protected] How I did it For servers loopback definitions in Dpg, if they contain LoopbackIPInterface with tags AttachTo, which has value of format like <server_name>SOC, the address will be regarded as a SoC IP, and sonic-cfggen now will treat the port connected to the server as active-active if the redundancy_type is either Libra or Mixed. How to verify it Pass the unittest. Signed-off-by: Longxiang Lyu <[email protected]>
1 parent 187f351 commit 7d06c7f

3 files changed

Lines changed: 143 additions & 82 deletions

File tree

src/sonic-config-engine/minigraph.py

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def formulate_fine_grained_ecmp(version, dpg_ecmp_content, port_device_map, port
185185
fine_grained_content = {"FG_NHG_MEMBER": FG_NHG_MEMBER, "FG_NHG": FG_NHG, "NEIGH": NEIGH}
186186
return fine_grained_content
187187

188+
188189
def parse_png(png, hname, dpg_ecmp_content = None):
189190
neighbors = {}
190191
devices = {}
@@ -400,9 +401,9 @@ def parse_asic_png(png, asic_name, hostname):
400401
device_data['lo_addr_v6']= lo_prefix_v6
401402
devices[name] = device_data
402403

403-
404404
return (neighbors, devices, port_speeds)
405405

406+
406407
def parse_loopback_intf(child):
407408
lointfs = child.find(str(QName(ns, "LoopbackIPInterfaces")))
408409
lo_intfs = {}
@@ -412,6 +413,7 @@ def parse_loopback_intf(child):
412413
lo_intfs[(intfname, ipprefix)] = {}
413414
return lo_intfs
414415

416+
415417
def parse_dpg(dpg, hname):
416418
aclintfs = None
417419
mgmtintfs = None
@@ -455,7 +457,7 @@ def parse_dpg(dpg, hname):
455457
ipprefix = ipintf.find(str(QName(ns, "Prefix"))).text
456458
intfs[(intfname, ipprefix)] = {}
457459
ip_intfs_map[ipprefix] = intfalias
458-
lo_intfs = parse_loopback_intf(child)
460+
lo_intfs = parse_loopback_intf(child)
459461

460462
subintfs = child.find(str(QName(ns, "SubInterfaces")))
461463
if subintfs is not None:
@@ -757,7 +759,6 @@ def parse_dpg(dpg, hname):
757759
return None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None
758760

759761

760-
761762
def parse_host_loopback(dpg, hname):
762763
for child in dpg:
763764
hostname = child.find(str(QName(ns, "Hostname")))
@@ -766,6 +767,7 @@ def parse_host_loopback(dpg, hname):
766767
lo_intfs = parse_loopback_intf(child)
767768
return lo_intfs
768769

770+
769771
def parse_cpg(cpg, hname, local_devices=[]):
770772
bgp_sessions = {}
771773
bgp_internal_sessions = {}
@@ -891,6 +893,7 @@ def parse_meta(meta, hname):
891893
max_cores = None
892894
kube_data = {}
893895
macsec_profile = {}
896+
redundancy_type = None
894897
device_metas = meta.find(str(QName(ns, "Devices")))
895898
for device in device_metas.findall(str(QName(ns1, "DeviceMetadata"))):
896899
if device.find(str(QName(ns1, "Name"))).text.lower() == hname.lower():
@@ -933,7 +936,9 @@ def parse_meta(meta, hname):
933936
kube_data["ip"] = value
934937
elif name == 'MacSecProfile':
935938
macsec_profile = parse_macsec_profile(value)
936-
return syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data, macsec_profile
939+
elif name == "RedundancyType":
940+
redundancy_type = value
941+
return syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data, macsec_profile, redundancy_type
937942

938943

939944
def parse_system_defaults(meta):
@@ -1313,6 +1318,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
13131318
static_routes = {}
13141319
system_defaults = {}
13151320
macsec_profile = {}
1321+
redundancy_type = None
13161322

13171323
hwsku_qn = QName(ns, "HwSku")
13181324
hostname_qn = QName(ns, "Hostname")
@@ -1343,7 +1349,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
13431349
elif child.tag == str(QName(ns, "UngDec")):
13441350
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname, None)
13451351
elif child.tag == str(QName(ns, "MetadataDeclaration")):
1346-
(syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data, macsec_profile) = parse_meta(child, hostname)
1352+
(syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, resource_type, downstream_subrole, switch_id, switch_type, max_cores, kube_data, macsec_profile, redundancy_type) = parse_meta(child, hostname)
13471353
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
13481354
linkmetas = parse_linkmeta(child, hostname)
13491355
elif child.tag == str(QName(ns, "DeviceInfos")):
@@ -1567,11 +1573,6 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
15671573
if macsec_enabled and 'PrimaryKey' in macsec_profile:
15681574
port['macsec'] = macsec_profile['PrimaryKey']
15691575

1570-
# If connected to a smart cable, get the connection position
1571-
for port_name, port in ports.items():
1572-
if port_name in mux_cable_ports:
1573-
port['mux_cable'] = "true"
1574-
15751576
# set port description if parsed from deviceinfo
15761577
for port_name in port_descriptions:
15771578
# ignore port not in port_config.ini
@@ -1713,7 +1714,13 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
17131714
# Add src_ip and qos remapping config into TUNNEL table if tunnel_qos_remap is enabled
17141715
results['TUNNEL'] = get_tunnel_entries(tunnel_intfs, tunnel_intfs_qos_remap_config, lo_intfs, system_defaults.get('tunnel_qos_remap', {}), mux_tunnel_name, peer_switch_ip)
17151716

1716-
results['MUX_CABLE'] = get_mux_cable_entries(mux_cable_ports, neighbors, devices)
1717+
active_active_ports = get_ports_in_active_active(root, devices, neighbors)
1718+
results['MUX_CABLE'] = get_mux_cable_entries(ports, mux_cable_ports, active_active_ports, neighbors, devices, redundancy_type)
1719+
1720+
# If connected to a smart cable, get the connection position
1721+
for port_name, port in results['PORT'].items():
1722+
if port_name in results['MUX_CABLE']:
1723+
port['mux_cable'] = "true"
17171724

17181725
if static_routes:
17191726
results['STATIC_ROUTE'] = static_routes
@@ -1826,46 +1833,76 @@ def get_tunnel_entries(tunnel_intfs, tunnel_intfs_qos_remap_config, lo_intfs, tu
18261833

18271834
return tunnels
18281835

1829-
def get_mux_cable_entries(mux_cable_ports, neighbors, devices):
1836+
1837+
def get_ports_in_active_active(root, devices, neighbors):
1838+
"""Parse out ports in active-active cable type."""
1839+
servers = {hostname.lower(): device_data for hostname, device_data in devices.items() if device_data["type"] == "Server"}
1840+
ports_in_active_active = {}
1841+
dpg_section = root.find(str(QName(ns, "DpgDec")))
1842+
neighbor_to_port_mapping = {neighbor["name"].lower(): port for port, neighbor in neighbors.items()}
1843+
if dpg_section is not None:
1844+
for child in dpg_section:
1845+
hostname = child.find(str(QName(ns, "Hostname")))
1846+
if hostname is None:
1847+
continue
1848+
hostname = hostname.text.lower()
1849+
if hostname not in servers:
1850+
continue
1851+
lo_intfs = parse_loopback_intf(child)
1852+
soc_intfs = {}
1853+
for intfname, ipprefix in lo_intfs.keys():
1854+
intfname_lower = intfname.lower()
1855+
if hostname + "soc" == intfname_lower:
1856+
ipprefix = str(ipaddress.ip_network(UNICODE_TYPE(ipprefix.split("/")[0])))
1857+
if "." in ipprefix:
1858+
soc_intfs["soc_ipv4"] = ipprefix
1859+
elif ":" in ipprefix:
1860+
soc_intfs["soc_ipv6"] = ipprefix
1861+
if hostname in neighbor_to_port_mapping and soc_intfs:
1862+
ports_in_active_active[neighbor_to_port_mapping[hostname]] = soc_intfs
1863+
return ports_in_active_active
1864+
1865+
1866+
def get_mux_cable_entries(ports, mux_cable_ports, active_active_ports, neighbors, devices, redundancy_type):
18301867
mux_cable_table = {}
1868+
if redundancy_type:
1869+
redundancy_type = redundancy_type.lower()
1870+
1871+
for port in ports:
1872+
is_active_active = redundancy_type in ("libra", "mixed") and port in active_active_ports
1873+
is_active_standby = port in mux_cable_ports
1874+
if is_active_active and is_active_standby:
1875+
print("Warning: skip %s as it is defined as active-standby and actie-active" % port, file=sys.stderr)
1876+
continue
1877+
if not (is_active_active or is_active_standby):
1878+
continue
18311879

1832-
for intf, cable_name in mux_cable_ports.items():
1833-
if intf in neighbors:
1834-
entry = {}
1835-
neighbor = neighbors[intf]['name']
1836-
entry['state'] = 'auto'
1837-
1838-
if devices[neighbor]['lo_addr'] is not None:
1839-
# Always force a /32 prefix for server IPv4 loopbacks
1840-
server_ipv4_lo_addr = devices[neighbor]['lo_addr'].split("/")[0]
1841-
server_ipv4_lo_prefix = ipaddress.ip_network(UNICODE_TYPE(server_ipv4_lo_addr))
1842-
entry['server_ipv4'] = str(server_ipv4_lo_prefix)
1843-
1844-
if 'lo_addr_v6' in devices[neighbor] and devices[neighbor]['lo_addr_v6'] is not None:
1845-
server_ipv6_lo_addr = devices[neighbor]['lo_addr_v6'].split('/')[0]
1846-
server_ipv6_lo_prefix = ipaddress.ip_network(UNICODE_TYPE(server_ipv6_lo_addr))
1847-
entry['server_ipv6'] = str(server_ipv6_lo_prefix)
1848-
mux_cable_table[intf] = entry
1849-
else:
1850-
print("Warning: no server IPv4 loopback found for {}, skipping mux cable table entry".format(neighbor), file=sys.stderr)
1880+
entry = {}
1881+
neighbor = neighbors[port]['name']
1882+
entry['state'] = 'auto'
18511883

1852-
if cable_name in devices:
1853-
cable_type = devices[cable_name].get('subtype')
1854-
if cable_type is None:
1855-
continue
1856-
if cable_type in dualtor_cable_types:
1857-
mux_cable_table[intf]['cable_type'] = cable_type
1858-
if cable_type == 'active-active':
1859-
soc_ipv4 = devices[cable_name]['lo_addr'].split('/')[0]
1860-
soc_ipv4_prefix = ipaddress.ip_network(UNICODE_TYPE(soc_ipv4))
1861-
mux_cable_table[intf]['soc_ipv4'] = str(soc_ipv4_prefix)
1862-
else:
1863-
print("Warning: skip parsing device %s for mux cable entry, cable type %s not supported" % (cable_name, cable_type), file=sys.stderr)
1884+
if devices[neighbor]['lo_addr'] is not None:
1885+
# Always force a /32 prefix for server IPv4 loopbacks
1886+
server_ipv4_lo_addr = devices[neighbor]['lo_addr'].split("/")[0]
1887+
server_ipv4_lo_prefix = ipaddress.ip_network(UNICODE_TYPE(server_ipv4_lo_addr))
1888+
entry['server_ipv4'] = str(server_ipv4_lo_prefix)
1889+
1890+
if 'lo_addr_v6' in devices[neighbor] and devices[neighbor]['lo_addr_v6'] is not None:
1891+
server_ipv6_lo_addr = devices[neighbor]['lo_addr_v6'].split('/')[0]
1892+
server_ipv6_lo_prefix = ipaddress.ip_network(UNICODE_TYPE(server_ipv6_lo_addr))
1893+
entry['server_ipv6'] = str(server_ipv6_lo_prefix)
1894+
1895+
if is_active_active:
1896+
entry['cable_type'] = 'active-active'
1897+
entry.update(active_active_ports[port])
1898+
1899+
mux_cable_table[port] = entry
18641900
else:
1865-
print("Warning: skip parsing device %s for mux cable entry, device definition not found" % cable_name, file=sys.stderr)
1901+
print("Warning: no server IPv4 loopback found for {}, skipping mux cable table entry".format(neighbor), file=sys.stderr)
18661902

18671903
return mux_cable_table
18681904

1905+
18691906
def parse_device_desc_xml(filename):
18701907
root = ET.parse(filename).getroot()
18711908
(lo_prefix, lo_prefix_v6, mgmt_prefix, mgmt_prefix_v6, hostname, hwsku, d_type, _, _, _) = parse_device(root)

src/sonic-config-engine/tests/simple-sample-graph-case.xml

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,62 @@
198198
<DownstreamSummaries/>
199199
<DownstreamSummarySet xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution"/>
200200
</DeviceDataPlaneInfo>
201+
<DeviceDataPlaneInfo>
202+
<IPSecTunnels />
203+
<LoopbackIPInterfaces xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution">
204+
<a:LoopbackIPInterface>
205+
<ElementType>LoopbackInterface</ElementType>
206+
<Name>HostIP</Name>
207+
<AttachTo>Loopback0</AttachTo>
208+
<a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux">
209+
<b:IPPrefix>10.10.10.2/32</b:IPPrefix>
210+
</a:Prefix>
211+
<a:PrefixStr>10.10.10.2/32</a:PrefixStr>
212+
</a:LoopbackIPInterface>
213+
<a:LoopbackIPInterface>
214+
<ElementType>LoopbackInterface</ElementType>
215+
<Name>HostIP1</Name>
216+
<AttachTo>Loopback0</AttachTo>
217+
<a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux">
218+
<b:IPPrefix>fe80::0002/128</b:IPPrefix>
219+
</a:Prefix>
220+
<a:PrefixStr>fe80::0002/128</a:PrefixStr>
221+
</a:LoopbackIPInterface>
222+
<a:LoopbackIPInterface>
223+
<ElementType>LoopbackInterface</ElementType>
224+
<Name>SoCHostIP0</Name>
225+
<AttachTo>server2SOC</AttachTo>
226+
<a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux">
227+
<b:IPPrefix>10.10.10.3/32</b:IPPrefix>
228+
</a:Prefix>
229+
<a:PrefixStr>10.10.10.3/32</a:PrefixStr>
230+
</a:LoopbackIPInterface>
231+
<a:LoopbackIPInterface>
232+
<ElementType>LoopbackInterface</ElementType>
233+
<Name>SoCHostIP1</Name>
234+
<AttachTo>server2SOC</AttachTo>
235+
<a:Prefix xmlns:b="Microsoft.Search.Autopilot.NetMux">
236+
<b:IPPrefix>fe80::0003/128</b:IPPrefix>
237+
</a:Prefix>
238+
<a:PrefixStr>fe80::0003/128</a:PrefixStr>
239+
</a:LoopbackIPInterface>
240+
</LoopbackIPInterfaces>
241+
<ManagementIPInterfaces xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" />
242+
<ManagementVIPInterfaces xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" />
243+
<MplsInterfaces />
244+
<MplsTeInterfaces />
245+
<RsvpInterfaces />
246+
<Hostname>server2</Hostname>
247+
<PortChannelInterfaces />
248+
<SubInterfaces />
249+
<VlanInterfaces />
250+
<IPInterfaces />
251+
<DataAcls />
252+
<AclInterfaces />
253+
<NatInterfaces xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" />
254+
<DownstreamSummaries />
255+
<DownstreamSummarySet xmlns:a="http://schemas.datacontract.org/2004/07/Microsoft.Search.Autopilot.Evolution" />
256+
</DeviceDataPlaneInfo>
201257
</DpgDec>
202258
<PngDec>
203259
<DeviceInterfaceLinks>
@@ -262,17 +318,6 @@
262318
<StartPort>L</StartPort>
263319
<Validate>true</Validate>
264320
</DeviceLinkBase>
265-
<DeviceLinkBase i:type="LogicalLink">
266-
<ElementType>LogicalLink</ElementType>
267-
<Bandwidth>10000</Bandwidth>
268-
<ChassisInternal>false</ChassisInternal>
269-
<EndDevice>switch-t0</EndDevice>
270-
<EndPort>fortyGigE0/8</EndPort>
271-
<FlowControl>true</FlowControl>
272-
<StartDevice>server2-SC</StartDevice>
273-
<StartPort>U</StartPort>
274-
<Validate>true</Validate>
275-
</DeviceLinkBase>
276321
<DeviceLinkBase i:type="LogicalLink">
277322
<ElementType>LogicalLink</ElementType>
278323
<Bandwidth>0</Bandwidth>
@@ -349,25 +394,6 @@
349394
<Hostname>server1</Hostname>
350395
<HwSku>server-sku</HwSku>
351396
</Device>
352-
<Device i:type="SmartCable">
353-
<ElementType>SmartCable</ElementType>
354-
<SubType>active-active</SubType>
355-
<Address xmlns:d5p1="Microsoft.Search.Autopilot.NetMux">
356-
<d5p1:IPPrefix>10.10.10.3/32</d5p1:IPPrefix>
357-
</Address>
358-
<AddressV6 xmlns:d5p1="Microsoft.Search.Autopilot.NetMux">
359-
<d5p1:IPPrefix>::/0</d5p1:IPPrefix>
360-
</AddressV6>
361-
<ManagementAddress xmlns:d5p1="Microsoft.Search.Autopilot.NetMux">
362-
<d5p1:IPPrefix>0.0.0.0/0</d5p1:IPPrefix>
363-
</ManagementAddress>
364-
<ManagementAddressV6 xmlns:d5p1="Microsoft.Search.Autopilot.NetMux">
365-
<d5p1:IPPrefix>::/0</d5p1:IPPrefix>
366-
</ManagementAddressV6>
367-
<SerialNumber i:nil="true" />
368-
<Hostname>server2-SC</Hostname>
369-
<HwSku>smartcable-sku</HwSku>
370-
</Device>
371397
<Device i:type="Server">
372398
<ElementType>Server</ElementType>
373399
<Address xmlns:d5p1="Microsoft.Search.Autopilot.NetMux">
@@ -506,6 +532,11 @@
506532
<a:Reference i:nil="true"/>
507533
<a:Value>Storage</a:Value>
508534
</a:DeviceProperty>
535+
<a:DeviceProperty>
536+
<a:Name>RedundancyType</a:Name>
537+
<a:Reference i:nil="true"/>
538+
<a:Value>Mixed</a:Value>
539+
</a:DeviceProperty>
509540
</a:Properties>
510541
</a:DeviceMetadata>
511542
</Devices>

src/sonic-config-engine/tests/test_minigraph_case.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,6 @@ def test_minigraph_neighbor_metadata(self):
236236
'lo_addr_v6': '::/0',
237237
'mgmt_addr': '0.0.0.0/0',
238238
'type': 'SmartCable'
239-
},
240-
'server2-SC': {
241-
'hwsku': 'smartcable-sku',
242-
'lo_addr': '10.10.10.3/32',
243-
'lo_addr_v6': '::/0',
244-
'mgmt_addr': '0.0.0.0/0',
245-
'type': 'SmartCable',
246-
'subtype': 'active-active'
247239
}
248240
}
249241
output = self.run_script(argument)
@@ -421,6 +413,7 @@ def test_minigraph_mux_cable_table(self):
421413
'server_ipv4': '10.10.10.2/32',
422414
'server_ipv6': 'fe80::2/128',
423415
'soc_ipv4': '10.10.10.3/32',
416+
'soc_ipv6': 'fe80::3/128',
424417
'cable_type': 'active-active'
425418
}
426419
}

0 commit comments

Comments
 (0)