diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case-remap-disabled.xml b/src/sonic-config-engine/tests/simple-sample-graph-case-remap-disabled.xml index 4ae1b33023..2d26bc9106 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case-remap-disabled.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case-remap-disabled.xml @@ -142,7 +142,7 @@ ab2 - fortyGigE0/4 + PortChannel01 192.0.0.1 fc02:2000::3;fc02:2000::4 2000 diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled-no-tunnel-attributes.xml b/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled-no-tunnel-attributes.xml index 6bc2a6db1b..650f56e4de 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled-no-tunnel-attributes.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled-no-tunnel-attributes.xml @@ -142,7 +142,7 @@ ab2 - fortyGigE0/4 + PortChannel01 192.0.0.1 fc02:2000::3;fc02:2000::4 2000 diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled.xml b/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled.xml index 8c69f04962..b290eb7c6c 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case-remap-enabled.xml @@ -142,7 +142,7 @@ ab2 - fortyGigE0/4 + PortChannel01 192.0.0.1 fc02:2000::3;fc02:2000::4 2000 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 ddb5f03c58..008719c85b 100644 --- a/src/sonic-config-engine/tests/simple-sample-graph-case.xml +++ b/src/sonic-config-engine/tests/simple-sample-graph-case.xml @@ -143,7 +143,7 @@ ab2 - fortyGigE0/4 + PortChannel01 192.0.0.1 fc02:2000::3;fc02:2000::4 2000 diff --git a/src/sonic-config-engine/tests/t0-sample-graph-two-mgmt.xml b/src/sonic-config-engine/tests/t0-sample-graph-two-mgmt.xml index da1b56fe13..5d201cc3e2 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph-two-mgmt.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph-two-mgmt.xml @@ -281,7 +281,7 @@ Vlan2000 - fortyGigE0/112;fortyGigE0/116;fortyGigE0/120 + PortChannel01;PortChannel02;PortChannel03 False 0.0.0.0/0 diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml index 05db8246ec..b343a8b5e3 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph.xml @@ -265,7 +265,7 @@ Vlan2000 - fortyGigE0/112;fortyGigE0/116;fortyGigE0/120 + PortChannel01;PortChannel02;PortChannel03 False 0.0.0.0/0 diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 8bad0f5f35..a5578b841d 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -129,7 +129,7 @@ class TestCfgGenCaseInsensitive(TestCase): output = self.run_script(argument) expected = { 'Vlan1000|Ethernet8': {'tagging_mode': 'untagged'}, - 'Vlan2000|Ethernet4': {'tagging_mode': 'untagged'} + 'Vlan2000|PortChannel01': {'tagging_mode': 'untagged'} } self.assertEqual( utils.to_dict(output.strip()), diff --git a/src/sonic-yang-models/tests/files/sample_config_db.json b/src/sonic-yang-models/tests/files/sample_config_db.json index 050f4433ba..720ee29568 100644 --- a/src/sonic-yang-models/tests/files/sample_config_db.json +++ b/src/sonic-yang-models/tests/files/sample_config_db.json @@ -1185,10 +1185,7 @@ "Vlan111|Ethernet0": { "tagging_mode": "untagged" }, - "Vlan111|Ethernet1": { - "tagging_mode": "untagged" - }, - "Vlan111|Ethernet2": { + "Vlan111|PortChannel0004": { "tagging_mode": "untagged" }, "Vlan111|Ethernet3": { @@ -2262,7 +2259,7 @@ "span": { "direction": "RX", "type": "SPAN", - "dst_port": "Ethernet2", + "dst_port": "Ethernet7", "src_port": "Ethernet3,Ethernet4" } }, diff --git a/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py b/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py index d776f479cd..d80293587a 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py +++ b/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py @@ -234,8 +234,8 @@ class Test_yang_models: desc = self.SpecialTests[test]['desc'] self.logStartTest(desc) jInput = json.loads(self.readJsonInput(test)) - # check all Vlan from 1 to 4094 - for i in range(4095): + # check all Vlan from 2 to 4094 + for i in range(2,4095): vlan = 'Vlan'+str(i) jInput["sonic-vlan:sonic-vlan"]["sonic-vlan:VLAN"]["VLAN_LIST"]\ [0]["name"] = vlan diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/vlan.json b/src/sonic-yang-models/tests/yang_model_tests/tests/vlan.json index 7f1cb4eb35..a795a7e3b3 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/vlan.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/vlan.json @@ -86,5 +86,33 @@ "VLAN_INTERFACE_INVALID_ENABLE_IPV6_LINK_LOCAL": { "desc": "Enable the ipv6 link-local as true.", "eStr": "Invalid value \"true\" in \"ipv6_use_link_local_only\" element." + }, + "VLAN_MEMBERS_WITHOUT_CREATING_VLAN":{ + "desc": "Vlan members without Creating Vlan", + "eStrKey": "LeafRef" + }, + "VLAN_CREATE_VLAN_WITH_MISSMATCHING_NAME": { + "desc": "Create Vlan so that name doesn't match id", + "eStr": "The vlanid must correspond to the VLAN name" + }, + "IP_PREFIX_WITHOUT_CREATNG_VLAN": { + "desc": "Create IP on not created Vlan", + "eStrKey": "LeafRef" + }, + "MIRROR_SESSION_ON_VLAN_MEMBER_PORT": { + "desc": "Set mirror dst port to a Vlan member", + "eStr": "Port is used as a destination port in a mirror session" + }, + "VLAN_ADD_PORT_CHANNEL_MEMBER": { + "desc": "Add port channel member to Vlan", + "eStr": "Port is a member of a port channel" + }, + "VLAN_ADD_PORT_THAT_IS_UNTAGGED": { + "desc": "Add port that is already untagged", + "eStr": "Port can be untagged in at most one VLAN" + }, + "VLAN_ADD_PORT_THAT_IS_ROUTER_INTERFACE": { + "desc": "Add to Vlan port that is router interface", + "eStr": "Port is a router interface" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/vlan.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/vlan.json index 9f3086b60c..b4288472cf 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/vlan.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/vlan.json @@ -719,5 +719,248 @@ ] } } + }, + + "VLAN_MEMBERS_WITHOUT_CREATING_VLAN": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "name": "Ethernet0" + } + ] + } + }, + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN_MEMBER": { + "VLAN_MEMBER_LIST": [ + { + "port": "Ethernet0", + "tagging_mode": "tagged", + "name": "Vlan100" + } + ] + } + } + }, + "VLAN_CREATE_VLAN_WITH_MISSMATCHING_NAME": { + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN": { + "VLAN_LIST": [ + { + "name": "Vlan10", + "vlanid":11 + } + ] + } + } + }, + "IP_PREFIX_WITHOUT_CREATNG_VLAN": { + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN": { + "VLAN_LIST": [ + { + "description": "server_vlan", + "name": "Vlan10" + } + ] + }, + "sonic-vlan:VLAN_INTERFACE": { + "VLAN_INTERFACE_IPPREFIX_LIST": [ + { + "family": "IPv4", + "ip-prefix": "20.0.0.1/24", + "scope": "global", + "name": "Vlan100" + } + ], + "VLAN_INTERFACE_LIST": [ + { + "name": "Vlan100" + } + ] + } + } + }, + "MIRROR_SESSION_ON_VLAN_MEMBER_PORT": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "name": "Ethernet1", + "speed": 25000, + "lanes": "1" + }, + { + "admin_status": "up", + "name": "Ethernet2", + "speed": 25000, + "lanes": "1" + } + ] + } + }, + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN": { + "VLAN_LIST": [ + { + "name": "Vlan10" + } + ] + }, + "sonic-vlan:VLAN_MEMBER": { + "VLAN_MEMBER_LIST": [ + { + "port": "Ethernet2", + "tagging_mode": "tagged", + "name": "Vlan10" + } + ] + } + }, + "sonic-mirror-session:sonic-mirror-session": { + "sonic-mirror-session:MIRROR_SESSION": { + "MIRROR_SESSION_LIST": [ { + "name":"mirror_session_dscp", + "type": "SPAN", + "src_port": "Ethernet1", + "dst_port": "Ethernet2" + }] + } + } + }, + "VLAN_ADD_PORT_CHANNEL_MEMBER": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [{ + "admin_status": "up", + "name": "Ethernet1", + "speed": 25000, + "lanes": "1" + }] + } + }, + "sonic-portchannel:sonic-portchannel": { + "sonic-portchannel:PORTCHANNEL": { + "PORTCHANNEL_LIST": [ + { + "admin_status": "up", + "min_links": "1", + "mtu": "9100", + "tpid": "0x8100", + "lacp_key": "auto", + "name": "PortChannel0001", + "fast_rate": "false", + "fallback" : "false", + "mode" : "routed" + } + ] + }, + "sonic-portchannel:PORTCHANNEL_MEMBER": { + "PORTCHANNEL_MEMBER_LIST": [ + { + "name": "PortChannel0001", + "port": "Ethernet1" + } + ] + } + }, + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN": { + "VLAN_LIST": [ + { + "name": "Vlan10" + } + ] + }, + "sonic-vlan:VLAN_MEMBER": { + "VLAN_MEMBER_LIST": [ + { + "port": "Ethernet1", + "tagging_mode": "tagged", + "name": "Vlan10" + } + ] + } + } + }, + "VLAN_ADD_PORT_THAT_IS_UNTAGGED": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [{ + "admin_status": "up", + "name": "Ethernet1", + "speed": 25000, + "lanes": "1" + }] + } + }, + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN": { + "VLAN_LIST": [ + { + "name": "Vlan10" + }, + { + "name": "Vlan11" + } + ] + }, + "sonic-vlan:VLAN_MEMBER": { + "VLAN_MEMBER_LIST": [ + { + "port": "Ethernet1", + "tagging_mode": "untagged", + "name": "Vlan10" + }, + { + "port": "Ethernet1", + "tagging_mode": "untagged", + "name": "Vlan11" + } + ] + } + } + }, + "VLAN_ADD_PORT_THAT_IS_ROUTER_INTERFACE": { + "sonic-interface:sonic-interface": { + "sonic-interface:INTERFACE": { + "INTERFACE_LIST": [ + { + "name": "Ethernet1" + } + ] + } + }, + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [{ + "admin_status": "up", + "name": "Ethernet1", + "speed": 25000, + "lanes": "1" + }] + } + }, + "sonic-vlan:sonic-vlan": { + "sonic-vlan:VLAN": { + "VLAN_LIST": [ + { + "name": "Vlan10" + } + ] + }, + "sonic-vlan:VLAN_MEMBER": { + "VLAN_MEMBER_LIST": [ + { + "port": "Ethernet1", + "tagging_mode": "untagged", + "name": "Vlan10" + } + ] + } + } } } diff --git a/src/sonic-yang-models/yang-models/sonic-vlan.yang b/src/sonic-yang-models/yang-models/sonic-vlan.yang index ad1ab8d743..f0f1aa603e 100644 --- a/src/sonic-yang-models/yang-models/sonic-vlan.yang +++ b/src/sonic-yang-models/yang-models/sonic-vlan.yang @@ -1,6 +1,6 @@ module sonic-vlan { - yang-version 1.1; + yang-version 1.1; namespace "http://github.com/sonic-net/sonic-vlan"; prefix vlan; @@ -34,8 +34,19 @@ module sonic-vlan { prefix vrf; } + import sonic-mirror-session { + prefix sms; + } + import sonic-interface { + prefix intf; + } + description "VLAN yang Module for SONiC OS"; + revision 2024-03-07 { + description "Add Constraints that are implemented in CLI"; + } + revision 2021-04-22 { description "Modify Vlan Member to include PortChannel along with Port"; } @@ -62,7 +73,7 @@ module sonic-vlan { leaf name { type leafref { - path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:name; + path "/vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:name"; } } @@ -80,7 +91,7 @@ module sonic-vlan { error-app-tag nat-zone-invalid; } } - default "0"; + default "0"; } leaf mpls { description "Enable/disable MPLS routing for the vlan interface"; @@ -109,10 +120,10 @@ module sonic-vlan { } - leaf loopback_action { - description "Packet action when a packet ingress and gets routed on the same IP interface"; - type stypes:loopback_action; - } + leaf loopback_action { + description "Packet action when a packet ingress and gets routed on the same IP interface"; + type stypes:loopback_action; + } } /* end of VLAN_INTERFACE_LIST */ @@ -149,9 +160,9 @@ module sonic-vlan { leaf family { /* family leaf needed for backward compatibility - Both ip4 and ip6 address are string in IETF RFC 6021, - so must statement can check based on : or ., family - should be IPv4 or IPv6 according. + Both ip4 and ip6 address are string in IETF RFC 6021, + so must statement can check based on : or ., family + should be IPv4 or IPv6 according. */ must "(contains(../ip-prefix, ':') and current()='IPv6') or @@ -164,7 +175,7 @@ module sonic-vlan { type boolean; } } - /* end of VLAN_INTERFACE_LIST */ + /* end of VLAN_INTERFACE_IPPREFIX_LIST */ } /* end of VLAN_INTERFACE container */ @@ -178,13 +189,15 @@ module sonic-vlan { leaf name { type string { - pattern 'Vlan([0-9]{1,3}|[1-3][0-9]{3}|[4][0][0-8][0-9]|[4][0][9][0-4])'; + pattern 'Vlan(409[0-5]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[2-9])'; } } - leaf vlanid { type uint16 { - range 1..4094; + range 2..4094; + } + must "substring-after(../name, 'Vlan') = current()"{ + error-message "The vlanid must correspond to the VLAN name"; } } @@ -239,7 +252,6 @@ module sonic-vlan { path "/vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:name"; } } - leaf port { /* key elements are mandatory by default */ type union { @@ -250,17 +262,29 @@ module sonic-vlan { path "/lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:name"; } } + must "not(/sms:sonic-mirror-session/sms:MIRROR_SESSION/sms:MIRROR_SESSION_LIST[sms:dst_port=current()])" + { + error-message "Port is used as a destination port in a mirror session."; + } + must "not(/lag:sonic-portchannel/lag:PORTCHANNEL_MEMBER/lag:PORTCHANNEL_MEMBER_LIST[lag:port=current()]/lag:name)" { + error-message "Port is a member of a port channel."; + } + must "not(/intf:sonic-interface/intf:INTERFACE/intf:INTERFACE_LIST[intf:name=current()])" { + error-message "Port is a router interface."; + } + must "count(../../vlan:VLAN_MEMBER_LIST[vlan:port=current() and vlan:tagging_mode='untagged']) <= 1" { + error-message "Port can be untagged in at most one VLAN."; + } } - leaf tagging_mode { mandatory true; type stypes:vlan_tagging_mode; } } - /* end of list VLAN_MEMBER_LIST */ + /* end of list VLAN_MEMBER_LIST */ } - /* end of container VLAN_MEMBER */ + /* end of container VLAN_MEMBER */ } - /* end of container sonic-vlan */ + /* end of container sonic-vlan */ } /* end of module sonic-vlan */