From e13801295ee5d6c10bf6f8678db8c7b1318e8f3a Mon Sep 17 00:00:00 2001 From: Praveen Chaudhary Date: Mon, 30 Sep 2019 16:17:19 -0700 Subject: [PATCH] [yang-models]: First version of yang models for Port, VLan and ACL. (#2) * [yang-models]: First version of yang models for Port, VLan and ACL. RB= G=lnos-reviewers R=pchaudhary,pmao,rmolina,samaity,sfardeen,zxu A= * [yangModelTesting.py]: Test code for POC. Minor Corrections in yang model files. * [sonic-interface.yang]: Interface yang model. Minor changes in yang tree and other models. * [Sonic Yang Tree]: Modified YANG models as per Guidelines. Guideline doc: https://github.com/Azure/SONiC/blob/master/doc/mgmt/SONiC_YANG_Model_Guidelines.md --- .../test_code/yangModelTesting.py | 67 +++++ .../yang-models/Sonic Yang Tree | 101 +++++++ .../yang-models/sonic-acl.yang | 272 ++++++++++++++++++ .../yang-models/sonic-head.yang | 72 +++++ .../yang-models/sonic-interface.yang | 78 +++++ .../yang-models/sonic-port.yang | 84 ++++++ .../yang-models/sonic-portchannel.yang | 85 ++++++ .../yang-models/sonic-vlan.yang | 158 ++++++++++ 8 files changed, 917 insertions(+) create mode 100644 src/sonic-yang-mgmt/test_code/yangModelTesting.py create mode 100644 src/sonic-yang-mgmt/yang-models/Sonic Yang Tree create mode 100644 src/sonic-yang-mgmt/yang-models/sonic-acl.yang create mode 100644 src/sonic-yang-mgmt/yang-models/sonic-head.yang create mode 100644 src/sonic-yang-mgmt/yang-models/sonic-interface.yang create mode 100644 src/sonic-yang-mgmt/yang-models/sonic-port.yang create mode 100644 src/sonic-yang-mgmt/yang-models/sonic-portchannel.yang create mode 100644 src/sonic-yang-mgmt/yang-models/sonic-vlan.yang diff --git a/src/sonic-yang-mgmt/test_code/yangModelTesting.py b/src/sonic-yang-mgmt/test_code/yangModelTesting.py new file mode 100644 index 000000000000..8a20578c247e --- /dev/null +++ b/src/sonic-yang-mgmt/test_code/yangModelTesting.py @@ -0,0 +1,67 @@ +import yang as ly +import sonic_yang as sy +import logging + +from os import listdir +from os.path import isfile, join, splitext + +logging.basicConfig(level=logging.DEBUG) +log = logging.getLogger(":") +log.setLevel(logging.DEBUG) +log.addHandler(logging.NullHandler()) + +def main(): + + yangDir = "/sonic/src/sonic-yang-mgmt/models" + yangDataInst = yangDir + "/sonic_config_data.json" + + # get all files + yangFiles = [f for f in listdir(yangDir) if isfile(join(yangDir, f))] + # get all yang files + yangFiles = [f for f in yangFiles if splitext(f)[-1].lower()==".yang"] + yangFiles = [f.split('.')[0] for f in yangFiles] + + # load yang mdoules + ctx = ly.Context(yangDir) + for f in yangFiles: + # load a module m + m = ctx.get_module(f) + if m is not None: + log.error(m.name()) + else: + m = ctx.load_module(f) + if m is not None: + log.info("module: {} is loaded successfully".format(m.name())) + + try: + root = ctx.parse_data_path(yangDataInst, ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) + + if root: + log.info("Tree DFS\n") + p = root.print_mem(ly.LYD_JSON, ly.LYP_WITHSIBLINGS | ly.LYP_FORMAT) + log.info("===================Data=================") + log.info(p) + + sYangInst = sy.sonic_yang(yangDir) + sYangInst.root = root + sYangInst.validate_data_tree(root, ctx) + + xpath = "/sonic-port:PORT/PORT_LIST[port_name='Ethernet1']/port_name" + #find_topo_sort_dependencies(sYangInst, xpath) + refs = sYangInst.find_data_dependencies(xpath) + printList(refs) + + except Exception as e: + print(e) + + +def printList(l): # list l + + print("list: ") + for item in l: + print (item) + + return + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/src/sonic-yang-mgmt/yang-models/Sonic Yang Tree b/src/sonic-yang-mgmt/yang-models/Sonic Yang Tree new file mode 100644 index 000000000000..6dc84d264054 --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/Sonic Yang Tree @@ -0,0 +1,101 @@ +module: sonic-acl + +--rw sonic-acl + +--rw ACL_RULE + | +--rw ACL_RULE_LIST* [ACL_TABLE_NAME RULE_NAME] + | +--rw ACL_TABLE_NAME -> /sonic-acl/ACL_TABLE/ACL_TABLE_LIST/ACL_TABLE_NAME + | +--rw RULE_NAME string + | +--rw PACKET_ACTION? head:packet_action + | +--rw IP_TYPE? head:ip_type + | +--rw PRIORITY? uint32 + | +--rw (ip_prefix)? + | | +--:(ip4_prefix) + | | | +--rw SRC_IP? inet:ipv4-prefix + | | | +--rw DST_IP? inet:ipv4-prefix + | | +--:(ip6_prefix) + | | +--rw SRC_IPV6? inet:ipv6-prefix + | | +--rw DST_IPV6? inet:ipv6-prefix + | +--rw IN_PORTS* uint16 + | +--rw OUT_PORTS* uint16 + | +--rw (src_port)? + | | +--:(l4_src_port) + | | | +--rw L4_SRC_PORT? uint16 + | | +--:(l4_src_port_range) + | | +--rw L4_SRC_PORT_RANGE? string + | +--rw (dst_port)? + | | +--:(l4_dst_port) + | | | +--rw L4_DST_PORT? uint16 + | | +--:(l4_dst_port_range) + | | +--rw L4_DST_PORT_RANGE? string + | +--rw ETHER_TYPE? string + | +--rw IP_PROTOCOL? uint8 + | +--rw TCP_FLAGS? string + | +--rw DSCP? uint8 + | +--rw TC? uint8 + | +--rw (icmp)? + | | +--:(icmp4) + | | | +--rw ICMP_TYPE? uint8 + | | | +--rw ICMP_CODE? uint8 + | | +--:(icmp6) + | | +--rw ICMPV6_TYPE? uint8 + | | +--rw ICMPV6_CODE? uint8 + | +--rw INNER_ETHER_TYPE? string + | +--rw INNER_IP_PROTOCOL? uint8 + | +--rw INNER_L4_SRC_PORT? uint16 + | +--rw INNER_L4_DST_PORT? uint16 + +--rw ACL_TABLE + +--rw ACL_TABLE_LIST* [ACL_TABLE_NAME] + +--rw ACL_TABLE_NAME string + +--rw policy_desc? string + +--rw type? head:acl_table_type + +--rw stage? enumeration + +--rw ports* union +module: sonic-interface + +--rw sonic-interface + +--rw INTERFACE + +--rw INTERFACE_LIST* [interface ip-prefix] + +--rw interface -> /port:sonic-port/PORT/PORT_LIST/port_name + +--rw ip-prefix inet:ip-prefix + +--rw scope? enumeration + +--rw family? head:ip-family +module: sonic-port + +--rw sonic-port + +--rw PORT + +--rw PORT_LIST* [port_name] + +--rw port_name string + +--rw alias? string + +--rw lanes? string + +--rw description? string + +--rw speed? uint32 + +--rw mtu? uint16 + +--rw admin_status head:admin_status +module: sonic-portchannel + +--rw sonic-portchannel + +--rw PORTCHANNEL + +--rw PORTCHANNEL_LIST* [portchannel_name] + +--rw portchannel_name string + +--rw members* -> /port:sonic-port/PORT/PORT_LIST/port_name + +--rw min_links? uint8 + +--rw description? string + +--rw mtu? uint16 + +--rw admin_status head:admin_status +module: sonic-vlan + +--rw sonic-vlan + +--rw VLAN_INTERFACE + | +--rw VLAN_INTERFACE_LIST* [vlanid ip-prefix] + | +--rw vlanid -> ../../../VLAN/VLAN_LIST/vlanid + | +--rw ip-prefix inet:ip-prefix + | +--rw scope? enumeration + | +--rw family? head:ip-family + +--rw VLAN + | +--rw VLAN_LIST* [vlanid] + | +--rw vlanid uint16 + | +--rw description? string + | +--rw dhcp_servers* inet:ip-address + | +--rw mtu? uint16 + | +--rw admin_status head:admin_status + | +--rw members* -> /port:sonic-port/PORT/PORT_LIST/port_name + +--rw VLAN_MEMBER + +--rw VLAN_MEMBER_LIST* [vlanid port] + +--rw vlanid -> ../../../VLAN/VLAN_LIST/vlanid + +--rw port -> /port:sonic-port/PORT/PORT_LIST/port_name + +--rw tagging_mode head:vlan_tagging_mode diff --git a/src/sonic-yang-mgmt/yang-models/sonic-acl.yang b/src/sonic-yang-mgmt/yang-models/sonic-acl.yang new file mode 100644 index 000000000000..cdd5a53f912e --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/sonic-acl.yang @@ -0,0 +1,272 @@ +module sonic-acl { + + namespace "http://github.com/Azure/sonic-acl"; + prefix acl; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-head { + prefix head; + revision-date 2019-07-01; + } + + import sonic-port { + prefix port; + revision-date 2019-07-01; + } + + import sonic-portchannel { + prefix lag; + revision-date 2019-07-01; + } + + organization "Linkedin Corporation"; + + contact "lnos_coders@linkedin.com"; + + description "ACL YANG Module for SONiC OS"; + + revision 2019-07-01 { + description "First Revision"; + } + + container sonic-acl { + + container ACL_RULE { + + description "ACL_RULE part of config_db.json"; + + list ACL_RULE_LIST { + + key "ACL_TABLE_NAME RULE_NAME"; + + leaf ACL_TABLE_NAME { + type leafref { + path "/acl:sonic-acl/acl:ACL_TABLE/acl:ACL_TABLE_LIST/acl:ACL_TABLE_NAME"; + } + } + + leaf RULE_NAME { + type string { + length 1..255; + } + } + + leaf PACKET_ACTION { + type head:packet_action; + } + + leaf IP_TYPE { + type head:ip_type; + } + + leaf PRIORITY { + type uint32 { + range 0..999999; + } + } + + choice ip_prefix { + + case ip4_prefix { + when "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV4' or .='IPV4ANY' or .='ARP'])"; + leaf SRC_IP { + type inet:ipv4-prefix; + } + + leaf DST_IP { + type inet:ipv4-prefix; + } + } + + case ip6_prefix { + when "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV6' or .='IPV6ANY'])"; + leaf SRC_IPV6 { + type inet:ipv6-prefix; + } + + leaf DST_IPV6 { + type inet:ipv6-prefix; + } + } + } + + leaf-list IN_PORTS { + /* Values in leaf list are UNIQUE */ + type uint16; + } + + leaf-list OUT_PORTS { + /* Values in leaf list are UNIQUE */ + type uint16; + } + + choice src_port { + case l4_src_port { + leaf L4_SRC_PORT { + type uint16; + } + } + + case l4_src_port_range { + leaf L4_SRC_PORT_RANGE { + type string { + pattern '([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])-([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])'; + } + } + } + } + + choice dst_port { + case l4_dst_port { + leaf L4_DST_PORT { + type uint16; + } + } + + case l4_dst_port_range { + leaf L4_DST_PORT_RANGE { + type string { + pattern '([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])-([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])'; + } + } + } + } + + leaf ETHER_TYPE { + type string { + pattern "(0x88CC|0x8100|0x8915|0x0806|0x0800|0x86DD|0x8847)"; + } + } + + leaf IP_PROTOCOL { + type uint8 { + range 1..143; + } + } + + leaf TCP_FLAGS { + type string { + pattern '0[x][0-9a-fA-F]{1,2}|0[X][0-9a-fA-F]{1,2}'; + } + } + + leaf DSCP { + type uint8; + } + + leaf TC { + type uint8; + } + + choice icmp { + + case icmp4 { + when "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV4' or .='IPV4ANY' or .='ARP'])"; + leaf ICMP_TYPE { + type uint8 { + range 1..44; + } + } + + leaf ICMP_CODE { + type uint8 { + range 1..16; + } + } + } + + case icmp6 { + when "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV6' or .='IPV6ANY'])"; + leaf ICMPV6_TYPE { + type uint8 { + range 1..44; + } + } + + leaf ICMPV6_CODE { + type uint8 { + range 1..16; + } + } + } + } + + leaf INNER_ETHER_TYPE { + type string { + pattern "(0x88CC|0x8100|0x8915|0x0806|0x0800|0x86DD|0x8847)"; + } + } + + leaf INNER_IP_PROTOCOL { + type uint8 { + range 1..143; + } + } + + leaf INNER_L4_SRC_PORT { + type uint16; + } + + leaf INNER_L4_DST_PORT { + type uint16; + } + } + /* end of ACL_RULE_LIST */ + } + /* end of container ACL_RULE */ + + container ACL_TABLE { + + description "ACL_TABLE part of config_db.json"; + + list ACL_TABLE_LIST { + + key "ACL_TABLE_NAME"; + + leaf ACL_TABLE_NAME { + type string; + } + + leaf policy_desc { + type string { + length 1..255; + } + } + + leaf type { + type head:acl_table_type; + } + + leaf stage { + type enumeration { + enum INGRESS; + enum EGRESS; + } + } + + leaf-list ports { + /* union of leafref is allowed in YANG 1.1 */ + type union { + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + type leafref { + path /lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:portchannel_name; + } + } + } + } + /* end of ACL_TABLE_LIST */ + } + /* end of container ACL_TABLE */ + } + /* end of container sonic-acl */ +} +/* end of module sonic-acl */ diff --git a/src/sonic-yang-mgmt/yang-models/sonic-head.yang b/src/sonic-yang-mgmt/yang-models/sonic-head.yang new file mode 100644 index 000000000000..dd0da92c7152 --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/sonic-head.yang @@ -0,0 +1,72 @@ +module sonic-head { + + namespace "http://sonic-head"; + prefix sonic-head; + + organization "Linkedin Corporation"; + + contact "lnos_coders@linkedin.com"; + + description "Head yang Module for SONiC OS"; + + revision 2019-07-01 { + description "First Revision"; + } + + typedef ip-family { + type enumeration { + enum IPv4; + enum IPv6; + } + } + + typedef admin_status { + type enumeration { + enum up; + enum down; + } + } + + typedef packet_action{ + type enumeration { + enum DROP; + enum FORWARD; + enum REDIRECT; + } + } + + typedef ip_type { + type enumeration { + enum ANY; + enum IP; + enum NON_IP; + enum IPV4; + enum IPV6; + enum IPV4ANY; + enum NON_IPv4; + enum IPV6ANY; + enum NON_IPv6; + enum ARP; + } + } + + typedef acl_table_type { + type enumeration { + enum L2; + enum L3; + enum L3V6; + enum MIRROR; + enum MIRRORV6; + enum MIRROR_DSCP; + enum CTRLPLANE; + } + } + + typedef vlan_tagging_mode { + type enumeration { + enum tagged; + enum untagged; + enum priority_tagged; + } + } +} \ No newline at end of file diff --git a/src/sonic-yang-mgmt/yang-models/sonic-interface.yang b/src/sonic-yang-mgmt/yang-models/sonic-interface.yang new file mode 100644 index 000000000000..dc8bc7389ea1 --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/sonic-interface.yang @@ -0,0 +1,78 @@ +module sonic-interface { + + namespace "http://github.com/Azure/sonic-interface"; + prefix intf; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-head { + prefix head; + revision-date 2019-07-01; + } + + import sonic-port { + prefix port; + revision-date 2019-07-01; + } + + organization "Linkedin Corporation"; + + contact "lnos_coders@linkedin.com"; + + description "INTERFACE yang Module for SONiC OS"; + + revision 2019-07-01 { + description "First Revision"; + } + + container sonic-interface { + container INTERFACE { + + description "INTERFACE part of config_db.json"; + + list INTERFACE_LIST { + + key "interface ip-prefix"; + + leaf interface { + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + } + + leaf ip-prefix { + type inet:ip-prefix; + } + + leaf scope { + type enumeration { + enum global; + enum local; + } + } + + 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. + */ + + must "(contains(../ip-prefix, ':') and current()='IPv6') or + (contains(../ip-prefix, '.') and current()='IPv4')"; + type head:ip-family; + } + } + /* end of INTERFACE_LIST */ + + } + /* end of INTERFACE container */ + } +} diff --git a/src/sonic-yang-mgmt/yang-models/sonic-port.yang b/src/sonic-yang-mgmt/yang-models/sonic-port.yang new file mode 100644 index 000000000000..be04a8aea4bd --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/sonic-port.yang @@ -0,0 +1,84 @@ +module sonic-port{ + + namespace "http://github.com/Azure/sonic-port"; + prefix port; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-head { + prefix head; + revision-date 2019-07-01; + } + + organization "Linkedin Corporation"; + + contact "lnos_coders@linkedin.com"; + + description "PORT yang Module for SONiC OS"; + + revision 2019-07-01 { + description "First Revision"; + } + + container sonic-port{ + container PORT { + + description "PORT part of config_db.json"; + + list PORT_LIST { + + key "port_name"; + + leaf port_name { + type string { + length 1..128; + } + } + + leaf alias { + type string { + length 1..128; + } + } + + leaf lanes { + type string { + length 1..128; + } + } + + leaf description { + type string { + length 1..255; + } + } + + leaf speed { + type uint32 { + range 1..100000; + } + } + + leaf mtu { + type uint16 { + range 1..9216; + } + } + + leaf admin_status { + mandatory true; + type head:admin_status; + } + } /* end of list PORT_LIST */ + + } /* end of container PORT */ + + } /* end of container sonic-port */ + +} /* end of module sonic-port */ diff --git a/src/sonic-yang-mgmt/yang-models/sonic-portchannel.yang b/src/sonic-yang-mgmt/yang-models/sonic-portchannel.yang new file mode 100644 index 000000000000..656351f4e635 --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/sonic-portchannel.yang @@ -0,0 +1,85 @@ +module sonic-portchannel { + + namespace "http://github.com/Azure/sonic-portchannel"; + prefix lag; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-head { + prefix head; + revision-date 2019-07-01; + } + + import sonic-port { + prefix port; + revision-date 2019-07-01; + } + + organization "Linkedin Corporation"; + + contact "lnos_coders@linkedin.com"; + + description "PORTCHANNEL yang Module for SONiC OS"; + + revision 2019-07-01 { + description "First Revision"; + } + + container sonic-portchannel { + container PORTCHANNEL { + + description "PORTCHANNEL part of config_db.json"; + + list PORTCHANNEL_LIST { + + key "portchannel_name"; + + leaf portchannel_name { + type string { + length 1..128; + pattern 'PortChannel[0-9]{1,4}'; + } + } + + leaf-list members { + /* leaf-list members are unique by default */ + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + } + + leaf min_links { + type uint8 { + range 1..128; + } + } + + leaf description { + type string { + length 1..255; + } + } + + leaf mtu { + type uint16 { + range 1..9216; + } + } + + leaf admin_status { + mandatory true; + type head:admin_status; + } + } /* end of list PORTCHANNEL_LIST */ + + } /* end of container PORTCHANNEL */ + + } /* end of container sonic-portchannel */ + +} /* end of module sonic-port */ diff --git a/src/sonic-yang-mgmt/yang-models/sonic-vlan.yang b/src/sonic-yang-mgmt/yang-models/sonic-vlan.yang new file mode 100644 index 000000000000..6058ce3f1bfc --- /dev/null +++ b/src/sonic-yang-mgmt/yang-models/sonic-vlan.yang @@ -0,0 +1,158 @@ +module sonic-vlan { + + namespace "http://github.com/Azure/sonic-vlan"; + prefix vlan; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix inet; + } + + import sonic-head { + prefix head; + revision-date 2019-07-01; + } + + import sonic-port { + prefix port; + revision-date 2019-07-01; + } + + organization "Linkedin Corporation"; + + contact "lnos_coders@linkedin.com"; + + description "VLAN yang Module for SONiC OS"; + + revision 2019-07-01 { + description "First Revision"; + } + + container sonic-vlan { + container VLAN_INTERFACE { + + description "VLAN_INTERFACE part of config_db.json"; + + list VLAN_INTERFACE_LIST { + + key "vlanid ip-prefix"; + + leaf vlanid { + type leafref { + path ../../../VLAN/VLAN_LIST/vlanid; + } + } + + leaf ip-prefix { + mandatory true; + type inet:ip-prefix; + } + + leaf scope { + type enumeration { + enum global; + enum local; + } + } + + 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. + */ + + must "(contains(../ip-prefix, ':') and current()='IPv6') or + (contains(../ip-prefix, '.') and current()='IPv4')"; + type head:ip-family; + } + } + /* end of VLAN_INTERFACE_LIST */ + } + /* end of VLAN_INTERFACE container */ + + container VLAN { + + description "VLAN part of config_db.json"; + + list VLAN_LIST { + + key "vlanid"; + + leaf vlanid { + type uint16 { + range 1..4094; + } + } + + leaf description { + type string { + length 1..255; + } + } + + leaf-list dhcp_servers { + type inet:ip-address; + } + + leaf mtu { + type uint16 { + range 1..9216; + } + } + + leaf admin_status { + mandatory true; + type head:admin_status; + } + + leaf-list members { + /* leaf-list members are unique by default */ + + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + } + } + /* end of VLAN_LIST */ + } + /* end of container VLAN */ + + container VLAN_MEMBER { + + description "VLAN_MEMBER part of config_db.json"; + + list VLAN_MEMBER_LIST { + + key "vlanid port"; + + leaf vlanid { + type leafref { + path ../../../VLAN/VLAN_LIST/vlanid; + } + } + + leaf port { + /* key elements are mandatory by default */ + mandatory true; + type leafref { + path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name; + } + } + + leaf tagging_mode { + mandatory true; + type head:vlan_tagging_mode; + } + } + /* end of list VLAN_MEMBER_LIST */ + } + /* end of container VLAN_MEMBER */ + } + /* end of container sonic-vlan */ +} +/* end of module sonic-vlan */