Skip to content

Commit b7d04b6

Browse files
authored
[minigraph]: Enhancement to minigraph parsing for chassis/multi-asic use case (#14243)
Following changes are done: Added Support where if asic configuration is not present in minigraph sonic-cfggen do not error out but instead process it gracefully. Use Case: In Supervisor we have number of asic are define as max possible but in minigraph configuration of only valid/available asics only are present. Without this change load_minigraph fails. Microsoft ADO: 17956325 Signed-off-by: Abhishek Dosi <abdosi@microsoft.com>
1 parent 6dffa55 commit b7d04b6

File tree

5 files changed

+94
-14
lines changed

5 files changed

+94
-14
lines changed

src/sonic-config-engine/minigraph.py

+27-12
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,21 @@ def parse_dpg(dpg, hname):
456456
aclintfs = None
457457
mgmtintfs = None
458458
subintfs = None
459+
intfs= {}
460+
lo_intfs= {}
461+
mvrf= {}
462+
mgmt_intf= {}
463+
voq_inband_intfs= {}
464+
vlans= {}
465+
vlan_members= {}
466+
dhcp_relay_table= {}
467+
pcs= {}
468+
pc_members= {}
469+
acls= {}
470+
acl_table_types = {}
471+
vni= {}
472+
dpg_ecmp_content= {}
473+
static_routes= {}
459474
tunnelintfs = defaultdict(dict)
460475
tunnelintfs_qos_remap_config = defaultdict(dict)
461476

@@ -575,7 +590,6 @@ def parse_dpg(dpg, hname):
575590
nexthop = ipnh.find(str(QName(ns, "Address"))).text
576591
advertise = ipnh.find(str(QName(ns, "Advertise"))).text
577592
static_routes[prefix] = {'nexthop': nexthop, 'ifname': ifname, 'advertise': advertise}
578-
579593
if port_nhipv4_map and port_nhipv6_map:
580594
subnet_check_ip = list(port_nhipv4_map.values())[0]
581595
for subnet_range in ip_intfs_map:
@@ -659,8 +673,6 @@ def parse_dpg(dpg, hname):
659673
vlans[sonic_vlan_name] = vlan_attributes
660674
vlan_member_list[sonic_vlan_name] = vmbr_list
661675

662-
acls = {}
663-
acl_table_types = {}
664676
for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
665677
if aclintf.find(str(QName(ns, "InAcl"))) is not None:
666678
aclname = aclintf.find(str(QName(ns, "InAcl"))).text.upper().replace(" ", "_").replace("-", "_")
@@ -844,9 +856,8 @@ def parse_dpg(dpg, hname):
844856
for table_key, mg_key in tunnel_qos_remap_table_key_to_mg_key_map.items():
845857
if mg_key in mg_tunnel.attrib:
846858
tunnelintfs_qos_remap_config[tunnel_type][tunnel_name][table_key] = mg_tunnel.attrib[mg_key]
847-
848859
return intfs, lo_intfs, mvrf, mgmt_intf, voq_inband_intfs, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, acl_table_types, vni, tunnelintfs, dpg_ecmp_content, static_routes, tunnelintfs_qos_remap_config
849-
return None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None
860+
return intfs, lo_intfs, mvrf, mgmt_intf, voq_inband_intfs, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, acl_table_types, vni, tunnelintfs, dpg_ecmp_content, static_routes, tunnelintfs_qos_remap_config
850861

851862

852863
def parse_host_loopback(dpg, hname):
@@ -1519,7 +1530,11 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
15191530
if asic_name is None:
15201531
current_device = [devices[key] for key in devices if key.lower() == hostname.lower()][0]
15211532
else:
1522-
current_device = [devices[key] for key in devices if key.lower() == asic_name.lower()][0]
1533+
try:
1534+
current_device = [devices[key] for key in devices if key.lower() == asic_name.lower()][0]
1535+
except:
1536+
print("Warning: no asic configuration found for {} in minigraph".format(asic_name), file=sys.stderr)
1537+
current_device = {}
15231538

15241539
results = {}
15251540
results['DEVICE_METADATA'] = {'localhost': {
@@ -1845,15 +1860,15 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
18451860
results['PORTCHANNEL_INTERFACE'] = pc_intfs
18461861

18471862
# for storage backend subinterface info present in minigraph takes precedence over ResourceType
1848-
if current_device['type'] in backend_device_types and bool(vlan_sub_intfs):
1863+
if current_device and current_device['type'] in backend_device_types and bool(vlan_sub_intfs):
18491864
del results['INTERFACE']
18501865
del results['PORTCHANNEL_INTERFACE']
18511866
is_storage_device = True
18521867
results['VLAN_SUB_INTERFACE'] = vlan_sub_intfs
18531868
# storage backend T0 have all vlan members tagged
18541869
for vlan in vlan_members:
18551870
vlan_members[vlan]["tagging_mode"] = "tagged"
1856-
elif current_device['type'] in backend_device_types and (resource_type is None or 'Storage' in resource_type):
1871+
elif current_device and current_device['type'] in backend_device_types and (resource_type is None or 'Storage' in resource_type):
18571872
del results['INTERFACE']
18581873
del results['PORTCHANNEL_INTERFACE']
18591874
is_storage_device = True
@@ -1930,7 +1945,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
19301945
results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers)
19311946
if len(acl_table_types) > 0:
19321947
results['ACL_TABLE_TYPE'] = acl_table_types
1933-
results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, pc_members, sub_role, current_device['type'], is_storage_device, vlan_members)
1948+
results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, pc_members, sub_role, current_device['type'] if current_device else None, is_storage_device, vlan_members)
19341949
results['FEATURE'] = {
19351950
'telemetry': {
19361951
'state': 'enabled'
@@ -1983,18 +1998,18 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw
19831998
# results['MIRROR_SESSION'] = mirror_sessions
19841999

19852000
# Special parsing for spine chassis frontend routers
1986-
if current_device['type'] == spine_chassis_frontend_role:
2001+
if current_device and current_device['type'] == spine_chassis_frontend_role:
19872002
parse_spine_chassis_fe(results, vni, lo_intfs, phyport_intfs, pc_intfs, pc_members, devices)
19882003

19892004
# Enable console management feature for console swtich
19902005
results['CONSOLE_SWITCH'] = {
19912006
'console_mgmt' : {
1992-
'enabled' : 'yes' if current_device['type'] in console_device_types else 'no'
2007+
'enabled' : 'yes' if current_device and current_device['type'] in console_device_types else 'no'
19932008
}
19942009
}
19952010

19962011
# Enable DHCP Server feature for specific device type
1997-
if current_device['type'] in dhcp_server_enabled_device_types:
2012+
if current_device and current_device['type'] in dhcp_server_enabled_device_types:
19982013
results['DEVICE_METADATA']['localhost']['dhcp_server'] = 'enabled'
19992014

20002015
return results
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"INSTANCES": {
3+
"redis": {
4+
"hostname" : "127.0.0.1",
5+
"port" : 6379,
6+
"unix_socket_path" : "/var/run/redis/redis.sock"
7+
}
8+
},
9+
"DATABASES" : {
10+
"APPL_DB" : {
11+
"id" : 0,
12+
"separator": ":",
13+
"instance" : "redis"
14+
},
15+
"ASIC_DB" : {
16+
"id" : 1,
17+
"separator": ":",
18+
"instance" : "redis"
19+
},
20+
"COUNTERS_DB" : {
21+
"id" : 2,
22+
"separator": ":",
23+
"instance" : "redis"
24+
},
25+
"CONFIG_DB" : {
26+
"id" : 4,
27+
"separator": "|",
28+
"instance" : "redis"
29+
},
30+
"PFC_WD_DB" : {
31+
"id" : 5,
32+
"separator": ":",
33+
"instance" : "redis"
34+
},
35+
"FLEX_COUNTER_DB" : {
36+
"id" : 5,
37+
"separator": ":",
38+
"instance" : "redis"
39+
},
40+
"STATE_DB" : {
41+
"id" : 6,
42+
"separator": "|",
43+
"instance" : "redis"
44+
},
45+
"SNMP_OVERLAY_DB" : {
46+
"id" : 7,
47+
"separator": "|",
48+
"instance" : "redis"
49+
}
50+
},
51+
"VERSION" : "1.1"
52+
}

src/sonic-config-engine/tests/mock_tables/database_global.json

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
{
1919
"namespace" : "asic3",
2020
"include" : "./asic3/database_config.json"
21+
},
22+
{
23+
"namespace" : "asic4",
24+
"include" : "./asic4/database_config.json"
2125
}
2226
],
2327
"VERSION" : "1.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# name lanes alias index asic_port_name role
2+
Ethernet-BP416 29,30,31,32 Eth0-ASIC4 16 Eth0-ASIC4 Int

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ def setUp(self):
3030
self.port_config = []
3131
for asic in range(NUM_ASIC):
3232
self.port_config.append(os.path.join(self.test_data_dir, "sample_port_config-{}.ini".format(asic)))
33+
self.sample_no_asic_port_config = os.path.join(self.test_data_dir, 'sample_port_config-4.ini')
3334
self.output_file = os.path.join(self.test_dir, 'output')
3435
os.environ["CFGGEN_UNIT_TESTING"] = "2"
3536

36-
def run_script(self, argument, check_stderr=False, output_file=None):
37+
def run_script(self, argument, check_stderr=True, output_file=None, validateYang=True):
3738
print('\n Running sonic-cfggen ' + ' '.join(argument))
38-
self.assertTrue(self.yang.validate(argument))
39+
if validateYang:
40+
self.assertTrue(self.yang.validate(argument))
3941
if check_stderr:
4042
output = subprocess.check_output(self.script_file + argument, stderr=subprocess.STDOUT)
4143
else:
@@ -542,5 +544,10 @@ def test_bgpd_frr_frontendasic(self):
542544
def test_bgpd_frr_backendasic(self):
543545
self.assertTrue(*self.run_frr_asic_case('bgpd/bgpd.conf.j2', 'bgpd_frr_backend_asic.conf', "asic3", self.port_config[3]))
544546

547+
def test_no_asic_in_graph(self):
548+
argument = ["-m", self.sample_graph, "-p", self.sample_no_asic_port_config, "-n", "asic4", "--var-json", "PORTCHANNEL"]
549+
output = json.loads(self.run_script(argument, check_stderr=False, validateYang=False))
550+
self.assertDictEqual(output, {})
551+
545552
def tearDown(self):
546553
os.environ["CFGGEN_UNIT_TESTING"] = ""

0 commit comments

Comments
 (0)