Fix tagged VlanInterface if attached to multiple vlan as untagged member (#8927)

#### Why I did it
Fix several bugs:
1. If one vlan member belongs to multiple vlans, and if any of the vlans is "Tagged" type, we respect the tagged type
2. If one vlan member belongs to multiple vlans, and all of the vlans have no "Tagged" type, we override it to be a tagged member
3. make sure `vlantype_name` is assigned correctly in each iteration

#### How to verify it
1. Test the command line to parse a minigraph and make sure the output does not change.
```
./sonic-cfggen -m minigraph.mlnx20.xml
```
The minigraph is for HwSKU Mellanox-SN2700-D40C8S8.

2. Test on a DUT with HwSKU Mellanox-SN2700-D40C8S8
```
sudo config load_minigraph
show vlan brief
```
Checked the "Port Tagging" column in the output.
This commit is contained in:
Qi Luo 2022-04-19 15:47:07 -07:00 committed by GitHub
parent 8b5d908c92
commit 936d93cbcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 11 deletions

View File

@ -536,28 +536,36 @@ def parse_dpg(dpg, hname):
vlan_members = {} vlan_members = {}
vlan_member_list = {} vlan_member_list = {}
dhcp_relay_table = {} dhcp_relay_table = {}
vlantype_name = "" # Dict: vlan member (port/PortChannel) -> set of VlanID, in which the member if an untagged vlan member
intf_vlan_mbr = defaultdict(list) untagged_vlan_mbr = defaultdict(set)
for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))):
vlanid = vintf.find(str(QName(ns, "VlanID"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text
vlantype = vintf.find(str(QName(ns, "Type")))
if vlantype is None:
vlantype_name = ""
else:
vlantype_name = vlantype.text
vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text
vmbr_list = vintfmbr.split(';') vmbr_list = vintfmbr.split(';')
for i, member in enumerate(vmbr_list): if vlantype_name != "Tagged":
intf_vlan_mbr[member].append(vlanid) for member in vmbr_list:
untagged_vlan_mbr[member].add(vlanid)
for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))): for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))):
vintfname = vintf.find(str(QName(ns, "Name"))).text vintfname = vintf.find(str(QName(ns, "Name"))).text
vlanid = vintf.find(str(QName(ns, "VlanID"))).text vlanid = vintf.find(str(QName(ns, "VlanID"))).text
vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text vintfmbr = vintf.find(str(QName(ns, "AttachTo"))).text
vlantype = vintf.find(str(QName(ns, "Type"))) vlantype = vintf.find(str(QName(ns, "Type")))
if vlantype != None: if vlantype is None:
vlantype_name = vintf.find(str(QName(ns, "Type"))).text vlantype_name = ""
else:
vlantype_name = vlantype.text
vmbr_list = vintfmbr.split(';') vmbr_list = vintfmbr.split(';')
for i, member in enumerate(vmbr_list): for i, member in enumerate(vmbr_list):
vmbr_list[i] = port_alias_map.get(member, member) vmbr_list[i] = port_alias_map.get(member, member)
sonic_vlan_member_name = "Vlan%s" % (vlanid) sonic_vlan_member_name = "Vlan%s" % (vlanid)
if vlantype_name == "Tagged": if vlantype_name == "Tagged":
vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'tagged'} vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'tagged'}
elif len(intf_vlan_mbr[member]) > 1: elif len(untagged_vlan_mbr[member]) > 1:
vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'tagged'} vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'tagged'}
else: else:
vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'untagged'} vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'untagged'}

View File

@ -190,6 +190,14 @@
<Tag>1000</Tag> <Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets> <Subnets>192.168.0.0/27</Subnets>
</VlanInterface> </VlanInterface>
<VlanInterface>
<Name>ab4</Name>
<AttachTo>fortyGigE0/8</AttachTo>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1001</VlanID>
<Tag>1001</Tag>
<Subnets>192.168.0.32/27</Subnets>
</VlanInterface>
<VlanInterface> <VlanInterface>
<Name>kk1</Name> <Name>kk1</Name>
<AttachTo>fortyGigE0/12</AttachTo> <AttachTo>fortyGigE0/12</AttachTo>
@ -205,6 +213,7 @@
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays> <DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>2000</VlanID> <VlanID>2000</VlanID>
<Tag>2000</Tag> <Tag>2000</Tag>
<Type>Tagged</Type>
<Subnets>192.168.0.240/27</Subnets> <Subnets>192.168.0.240/27</Subnets>
</VlanInterface> </VlanInterface>
<VlanInterface> <VlanInterface>

View File

@ -208,6 +208,14 @@
<Tag>1000</Tag> <Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets> <Subnets>192.168.0.0/27</Subnets>
</VlanInterface> </VlanInterface>
<VlanInterface>
<Name>ab4</Name>
<AttachTo>fortyGigE0/8</AttachTo>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1001</VlanID>
<Tag>1001</Tag>
<Subnets>192.168.0.32/27</Subnets>
</VlanInterface>
<VlanInterface> <VlanInterface>
<Name>kk1</Name> <Name>kk1</Name>
<AttachTo>fortyGigE0/12</AttachTo> <AttachTo>fortyGigE0/12</AttachTo>

View File

@ -190,6 +190,14 @@
<Tag>1000</Tag> <Tag>1000</Tag>
<Subnets>192.168.0.0/27</Subnets> <Subnets>192.168.0.0/27</Subnets>
</VlanInterface> </VlanInterface>
<VlanInterface>
<Name>ab4</Name>
<AttachTo>fortyGigE0/8</AttachTo>
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>1001</VlanID>
<Tag>1001</Tag>
<Subnets>192.168.0.32/27</Subnets>
</VlanInterface>
<VlanInterface> <VlanInterface>
<Name>kk1</Name> <Name>kk1</Name>
<AttachTo>fortyGigE0/12</AttachTo> <AttachTo>fortyGigE0/12</AttachTo>
@ -205,6 +213,7 @@
<DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays> <DhcpRelays>192.0.0.1;192.0.0.2</DhcpRelays>
<VlanID>2000</VlanID> <VlanID>2000</VlanID>
<Tag>2000</Tag> <Tag>2000</Tag>
<Type>Tagged</Type>
<Subnets>192.168.0.240/27</Subnets> <Subnets>192.168.0.240/27</Subnets>
</VlanInterface> </VlanInterface>
<VlanInterface> <VlanInterface>

View File

@ -151,6 +151,7 @@ class TestCfgGen(TestCase):
utils.to_dict(output.strip()), utils.to_dict(output.strip()),
utils.to_dict( utils.to_dict(
'{\n "Vlan1000|Ethernet8": {\n "tagging_mode": "tagged"\n },' '{\n "Vlan1000|Ethernet8": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan1001|Ethernet8": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan2000|Ethernet12": {\n "tagging_mode": "tagged"\n },' ' \n "Vlan2000|Ethernet12": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan2001|Ethernet12": {\n "tagging_mode": "tagged"\n },' ' \n "Vlan2001|Ethernet12": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan2020|Ethernet12": {\n "tagging_mode": "tagged"\n }\n}' ' \n "Vlan2020|Ethernet12": {\n "tagging_mode": "tagged"\n }\n}'
@ -160,9 +161,10 @@ class TestCfgGen(TestCase):
self.assertEqual( self.assertEqual(
utils.to_dict(output.strip()), utils.to_dict(output.strip()),
utils.to_dict( utils.to_dict(
'{\n "Vlan1000|Ethernet8": {\n "tagging_mode": "untagged"\n },' '{\n "Vlan1000|Ethernet8": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan1001|Ethernet8": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan2000|Ethernet12": {\n "tagging_mode": "tagged"\n },' ' \n "Vlan2000|Ethernet12": {\n "tagging_mode": "tagged"\n },'
' \n "Vlan2001|Ethernet12": {\n "tagging_mode": "tagged"\n },' ' \n "Vlan2001|Ethernet12": {\n "tagging_mode": "untagged"\n },'
' \n "Vlan2020|Ethernet12": {\n "tagging_mode": "tagged"\n }\n}' ' \n "Vlan2020|Ethernet12": {\n "tagging_mode": "tagged"\n }\n}'
) )
) )
@ -249,6 +251,7 @@ class TestCfgGen(TestCase):
utils.to_dict(output.strip()), utils.to_dict(output.strip()),
utils.to_dict( utils.to_dict(
"{'Vlan1000': {'alias': 'ab1', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '1000'}, " "{'Vlan1000': {'alias': 'ab1', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '1000'}, "
"'Vlan1001': {'alias': 'ab4', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '1001'},"
"'Vlan2001': {'alias': 'ab3', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '2001'}," "'Vlan2001': {'alias': 'ab3', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '2001'},"
"'Vlan2000': {'alias': 'ab2', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '2000'}," "'Vlan2000': {'alias': 'ab2', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '2000'},"
"'Vlan2020': {'alias': 'kk1', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '2020'}}" "'Vlan2020': {'alias': 'kk1', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '2020'}}"
@ -265,6 +268,7 @@ class TestCfgGen(TestCase):
utils.to_dict(output.strip()), utils.to_dict(output.strip()),
utils.to_dict( utils.to_dict(
"{('Vlan2000', 'Ethernet12'): {'tagging_mode': 'tagged'}, " "{('Vlan2000', 'Ethernet12'): {'tagging_mode': 'tagged'}, "
"('Vlan1001', 'Ethernet8'): {'tagging_mode': 'tagged'}, "
"('Vlan1000', 'Ethernet8'): {'tagging_mode': 'tagged'}, " "('Vlan1000', 'Ethernet8'): {'tagging_mode': 'tagged'}, "
"('Vlan2020', 'Ethernet12'): {'tagging_mode': 'tagged'}, " "('Vlan2020', 'Ethernet12'): {'tagging_mode': 'tagged'}, "
"('Vlan2001', 'Ethernet12'): {'tagging_mode': 'tagged'}}" "('Vlan2001', 'Ethernet12'): {'tagging_mode': 'tagged'}}"
@ -275,9 +279,10 @@ class TestCfgGen(TestCase):
utils.to_dict(output.strip()), utils.to_dict(output.strip()),
utils.to_dict( utils.to_dict(
"{('Vlan2000', 'Ethernet12'): {'tagging_mode': 'tagged'}, " "{('Vlan2000', 'Ethernet12'): {'tagging_mode': 'tagged'}, "
"('Vlan1000', 'Ethernet8'): {'tagging_mode': 'untagged'}, " "('Vlan1000', 'Ethernet8'): {'tagging_mode': 'tagged'}, "
"('Vlan1001', 'Ethernet8'): {'tagging_mode': 'tagged'}, "
"('Vlan2020', 'Ethernet12'): {'tagging_mode': 'tagged'}, " "('Vlan2020', 'Ethernet12'): {'tagging_mode': 'tagged'}, "
"('Vlan2001', 'Ethernet12'): {'tagging_mode': 'tagged'}}" "('Vlan2001', 'Ethernet12'): {'tagging_mode': 'untagged'}}"
) )
) )
@ -704,6 +709,9 @@ class TestCfgGen(TestCase):
def test_minigraph_sub_port_interfaces(self, check_stderr=True): def test_minigraph_sub_port_interfaces(self, check_stderr=True):
self.verify_sub_intf(check_stderr=check_stderr) self.verify_sub_intf(check_stderr=check_stderr)
def test_minigraph_sub_port_intf_resource_type_non_backend_tor(self, check_stderr=True):
self.verify_sub_intf_non_backend_tor(graph_file=self.sample_resource_graph, check_stderr=check_stderr)
def test_minigraph_sub_port_intf_resource_type(self, check_stderr=True): def test_minigraph_sub_port_intf_resource_type(self, check_stderr=True):
self.verify_sub_intf(graph_file=self.sample_resource_graph, check_stderr=check_stderr) self.verify_sub_intf(graph_file=self.sample_resource_graph, check_stderr=check_stderr)
@ -737,6 +745,14 @@ class TestCfgGen(TestCase):
output = self.run_script(argument) output = self.run_script(argument)
self.assertEqual(output.strip(), "{}") self.assertEqual(output.strip(), "{}")
def verify_sub_intf_non_backend_tor(self, **kwargs):
graph_file = kwargs.get('graph_file', self.sample_graph_simple)
# All the other tables stay unchanged
self.test_var_json_data(graph_file=graph_file)
self.test_minigraph_vlans(graph_file=graph_file)
self.test_minigraph_vlan_members(graph_file=graph_file)
def verify_sub_intf(self, **kwargs): def verify_sub_intf(self, **kwargs):
graph_file = kwargs.get('graph_file', self.sample_graph_simple) graph_file = kwargs.get('graph_file', self.sample_graph_simple)
check_stderr = kwargs.get('check_stderr', True) check_stderr = kwargs.get('check_stderr', True)