From 14b625ca50c4e1de11f5dc5fcb136da0385793df Mon Sep 17 00:00:00 2001 From: kellyyeh <42761586+kellyyeh@users.noreply.github.com> Date: Thu, 12 Aug 2021 14:32:23 -0700 Subject: [PATCH 1/2] Cherry-pick Parse DHCP Table --- src/sonic-config-engine/minigraph.py | 34 ++++++++++++++++--- .../tests/simple-sample-graph-case.xml | 12 +++++++ src/sonic-config-engine/tests/test_cfggen.py | 11 ++++++ .../tests/test_minigraph_case.py | 26 ++++++++++++++ 4 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index c5057ebaee4..8ec270bedff 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -567,6 +567,29 @@ def parse_dpg(dpg, hname): vlan_attributes['alias'] = vintfname vlans[sonic_vlan_name] = vlan_attributes + dhcp = child.find(str(QName(ns, "Dhcp"))) + dhcp_table = {} + + if dhcp is not None: + for vintf in dhcp.findall(str(QName(ns, "VlanInterface"))): + vintfname = vintf.find(str(QName(ns, "Name"))).text + + dhcp_attributes = {} + + dhcp_node = vintf.find(str(QName(ns, "Dhcpv6Relays"))) + if dhcp_node is not None and dhcp_node.text is not None: + dhcpservers = dhcp_node.text + vdhcpserver_list = dhcpservers.split(';') + dhcp_attributes['dhcpv6_servers'] = vdhcpserver_list + + option_linklayer_addr = vintf.find(str(QName(ns, "Dhcpv6OptionRfc6939"))) + if option_linklayer_addr is not None and option_linklayer_addr.text == "true": + dhcp_attributes['dhcpv6_option|rfc6939_support'] = "true" + elif option_linklayer_addr is not None and option_linklayer_addr.text == "false": + dhcp_attributes['dhcpv6_option|rfc6939_support'] = "false" + + dhcp_table[vintfname] = dhcp_attributes + acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): if aclintf.find(str(QName(ns, "InAcl"))) is not None: @@ -681,8 +704,8 @@ def parse_dpg(dpg, hname): if mg_key in mg_tunnel.attrib: tunnelintfs[tunnel_type][tunnel_name][table_key] = mg_tunnel.attrib[mg_key] - return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni, tunnelintfs, dpg_ecmp_content - return None, None, None, None, None, None, None, None, None, None + return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni, tunnelintfs, dpg_ecmp_content + return None, None, None, None, None, None, None, None, None, None, None, None, None def parse_host_loopback(dpg, hname): for child in dpg: @@ -1108,6 +1131,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw tunnel_intfs = None vlans = None vlan_members = None + dhcp_table = None pcs = None mgmt_intf = None lo_intfs = None @@ -1167,7 +1191,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw for child in root: if asic_name is None: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, hostname) + (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): @@ -1182,7 +1206,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw (port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku) else: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, asic_name) + (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, asic_name) host_lo_intfs = parse_host_loopback(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, asic_name, local_devices) @@ -1499,7 +1523,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key in {device['name'] for device in neighbors.values()} } results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) - results['DHCPv6_SERVER'] = dict((item, {}) for item in dhcpv6_servers) + results['DHCP'] = dhcp_table results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers) results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, sub_role) diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case.xml b/src/sonic-config-engine/tests/simple-sample-graph-case.xml index c1015b6b536..95398e6913c 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case.xml @@ -148,6 +148,18 @@ + + + Vlan1000 + fc02:2000::1;fc02:2000::2 + true + + + Vlan2000 + fc02:2000::3;fc02:2000::4 + false + + diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index e3f74fb9cf7..502c4b2e416 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -684,3 +684,14 @@ def test_show_run_interfaces(self): argument = '-a \'{"key1":"value"}\' --var-json INTERFACE' output = self.run_script(argument) self.assertEqual(output, '') + + def test_minigraph_dhcp(self): + argument = '-m "' + self.sample_graph_simple_case + '" -p "' + self.port_config + '" -v DHCP' + output = self.run_script(argument) + self.assertEqual( + utils.to_dict(output.strip()), + utils.to_dict( + "{'Vlan1000': {'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2'], 'dhcpv6_option|rfc6939_support': 'true'}, " + "'Vlan2000': {'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4'], 'dhcpv6_option|rfc6939_support': 'false'}}" + ) + ) diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 3308c5641f4..998b66cfb9a 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -357,3 +357,29 @@ def test_minigraph_mux_cable_table(self): utils.to_dict(output.strip()), expected_table ) + + def test_dhcp_table(self): + argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DHCP"' + expected = { + 'Vlan1000': { + 'dhcpv6_servers': [ + "fc02:2000::1", + "fc02:2000::2" + ], + 'dhcpv6_option|rfc6939_support': 'true' + }, + 'Vlan2000': { + 'dhcpv6_servers': [ + "fc02:2000::3", + "fc02:2000::4" + ], + 'dhcpv6_option|rfc6939_support': 'false' + } + } + output = self.run_script(argument) + self.assertEqual( + utils.to_dict(output.strip()), + expected + ) + + From 04c78580947b34424d13ba5603fab80e0746bfd6 Mon Sep 17 00:00:00 2001 From: kellyyeh <42761586+kellyyeh@users.noreply.github.com> Date: Fri, 20 Aug 2021 09:18:48 -0700 Subject: [PATCH 2/2] Cherry pick changing DHCP table to DHCP_RELAY --- src/sonic-config-engine/minigraph.py | 38 +++++-------------- .../tests/simple-sample-graph-case.xml | 14 +------ src/sonic-config-engine/tests/test_cfggen.py | 6 +-- .../tests/test_minigraph_case.py | 12 +++--- 4 files changed, 21 insertions(+), 49 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 8ec270bedff..d4fffc21c43 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -516,6 +516,7 @@ def parse_dpg(dpg, hname): vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlans = {} vlan_members = {} + dhcp_relay_table = {} vlantype_name = "" intf_vlan_mbr = defaultdict(list) for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): @@ -543,6 +544,7 @@ def parse_dpg(dpg, hname): vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'untagged'} vlan_attributes = {'vlanid': vlanid, 'members': vmbr_list } + dhcp_attributes = {} # If this VLAN requires a DHCP relay agent, it will contain a element # containing a list of DHCP server IPs @@ -557,6 +559,9 @@ def parse_dpg(dpg, hname): vintfdhcpservers = vintf_node.text vdhcpserver_list = vintfdhcpservers.split(';') vlan_attributes['dhcpv6_servers'] = vdhcpserver_list + dhcp_attributes['dhcpv6_servers'] = vdhcpserver_list + sonic_vlan_member_name = "Vlan%s" % (vlanid) + dhcp_relay_table[sonic_vlan_member_name] = dhcp_attributes vlanmac = vintf.find(str(QName(ns, "MacAddress"))) if vlanmac is not None and vlanmac.text is not None: @@ -567,29 +572,6 @@ def parse_dpg(dpg, hname): vlan_attributes['alias'] = vintfname vlans[sonic_vlan_name] = vlan_attributes - dhcp = child.find(str(QName(ns, "Dhcp"))) - dhcp_table = {} - - if dhcp is not None: - for vintf in dhcp.findall(str(QName(ns, "VlanInterface"))): - vintfname = vintf.find(str(QName(ns, "Name"))).text - - dhcp_attributes = {} - - dhcp_node = vintf.find(str(QName(ns, "Dhcpv6Relays"))) - if dhcp_node is not None and dhcp_node.text is not None: - dhcpservers = dhcp_node.text - vdhcpserver_list = dhcpservers.split(';') - dhcp_attributes['dhcpv6_servers'] = vdhcpserver_list - - option_linklayer_addr = vintf.find(str(QName(ns, "Dhcpv6OptionRfc6939"))) - if option_linklayer_addr is not None and option_linklayer_addr.text == "true": - dhcp_attributes['dhcpv6_option|rfc6939_support'] = "true" - elif option_linklayer_addr is not None and option_linklayer_addr.text == "false": - dhcp_attributes['dhcpv6_option|rfc6939_support'] = "false" - - dhcp_table[vintfname] = dhcp_attributes - acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): if aclintf.find(str(QName(ns, "InAcl"))) is not None: @@ -704,7 +686,7 @@ def parse_dpg(dpg, hname): if mg_key in mg_tunnel.attrib: tunnelintfs[tunnel_type][tunnel_name][table_key] = mg_tunnel.attrib[mg_key] - return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni, tunnelintfs, dpg_ecmp_content + return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, vni, tunnelintfs, dpg_ecmp_content return None, None, None, None, None, None, None, None, None, None, None, None, None def parse_host_loopback(dpg, hname): @@ -1131,7 +1113,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw tunnel_intfs = None vlans = None vlan_members = None - dhcp_table = None + dhcp_relay_table = None pcs = None mgmt_intf = None lo_intfs = None @@ -1191,7 +1173,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw for child in root: if asic_name is None: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, hostname) + (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): @@ -1206,7 +1188,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw (port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku) else: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, asic_name) + (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, vni, tunnel_intfs, dpg_ecmp_content) = parse_dpg(child, asic_name) host_lo_intfs = parse_host_loopback(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, asic_name, local_devices) @@ -1523,7 +1505,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None, hw results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key in {device['name'] for device in neighbors.values()} } results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers) results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers) - results['DHCP'] = dhcp_table + results['DHCP_RELAY'] = dhcp_relay_table results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers) results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers) results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, sub_role) diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case.xml b/src/sonic-config-engine/tests/simple-sample-graph-case.xml index 95398e6913c..78e81bd6df7 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case.xml @@ -134,6 +134,7 @@ ab1 fortyGigE0/8 192.0.0.1;192.0.0.2 + fc02:2000::1;fc02:2000::2 1000 1000 192.168.0.0/27 @@ -143,23 +144,12 @@ ab2 fortyGigE0/4 192.0.0.1 + fc02:2000::3;fc02:2000::4 2000 2000 - - - Vlan1000 - fc02:2000::1;fc02:2000::2 - true - - - Vlan2000 - fc02:2000::3;fc02:2000::4 - false - - diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index 502c4b2e416..0a0dd54a76d 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -686,12 +686,12 @@ def test_show_run_interfaces(self): self.assertEqual(output, '') def test_minigraph_dhcp(self): - argument = '-m "' + self.sample_graph_simple_case + '" -p "' + self.port_config + '" -v DHCP' + argument = '-m "' + self.sample_graph_simple_case + '" -p "' + self.port_config + '" -v DHCP_RELAY' output = self.run_script(argument) self.assertEqual( utils.to_dict(output.strip()), utils.to_dict( - "{'Vlan1000': {'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2'], 'dhcpv6_option|rfc6939_support': 'true'}, " - "'Vlan2000': {'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4'], 'dhcpv6_option|rfc6939_support': 'false'}}" + "{'Vlan1000': {'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2']}, " + "'Vlan2000': {'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4']}}" ) ) diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 998b66cfb9a..560d0990fdc 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -102,6 +102,7 @@ def test_minigraph_vlans(self): 'Vlan1000': { 'alias': 'ab1', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], + 'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2'], 'vlanid': '1000', 'mac': '00:aa:bb:cc:dd:ee', 'members': ['Ethernet8'] @@ -109,6 +110,7 @@ def test_minigraph_vlans(self): 'Vlan2000': { 'alias': 'ab2', 'dhcp_servers': ['192.0.0.1'], + 'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4'], 'members': ['Ethernet4'], 'vlanid': '2000' } @@ -359,21 +361,19 @@ def test_minigraph_mux_cable_table(self): ) def test_dhcp_table(self): - argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DHCP"' + argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DHCP_RELAY"' expected = { 'Vlan1000': { 'dhcpv6_servers': [ "fc02:2000::1", "fc02:2000::2" - ], - 'dhcpv6_option|rfc6939_support': 'true' + ] }, - 'Vlan2000': { + 'Vlan2000': { 'dhcpv6_servers': [ "fc02:2000::3", "fc02:2000::4" - ], - 'dhcpv6_option|rfc6939_support': 'false' + ] } } output = self.run_script(argument)