[sonic-yang-models]: First version of yang models for Port, VLan, Interface, PortChannel, loopback and ACL. (#3730)

[sonic-yang-models]: First version of yang models for Port, VLan, Interface, PortChannel, loopback and ACL.

YANG models as per Guidelines.

Guideline doc: https://github.com/Azure/SONiC/blob/master/doc/mgmt/SONiC_YANG_Model_Guidelines.md

[sonic-yang-models/tests]: YANG model test code and JSON input for testing.

[sonic-yang-models/setup.py]: Build infra for yang models.

**- What I did**
Created Yang model for Sonic.
Tables:  PORT, VLAN, VLAN_INTERFACE, VLAN_MEMBER, ACL_RULE, ACL_TABLE, INTERFACE.

Created build infra files using which a new package (sonic-yang-models) can be build and can be deployed on sonic switches. Yang models will be part of this new package.

**- How I did it**
Wrote yang models based on Guideline doc: 
https://github.com/Azure/SONiC/blob/master/doc/mgmt/SONiC_YANG_Model_Guidelines.md
and 
https://github.com/Azure/SONiC/wiki/Configuration.

Wrote python wheel Package infra which runs test for these Yang models using a json files which consists configuration as per yang models. These configs are for negative tests, which means we want to test that most must condition, pattern and when condition works as expected.

**- How to verify it**
Build Logs and testing:
———————————————————————————————————

```
/sonic/src/sonic-yang-models /sonic
running test
running egg_info
writing top-level names to sonic_yang_models.egg-info/top_level.txt
writing dependency_links to sonic_yang_models.egg-info/dependency_links.txt
writing sonic_yang_models.egg-info/PKG-INFO
reading manifest file 'sonic_yang_models.egg-info/SOURCES.txt'
writing manifest file 'sonic_yang_models.egg-info/SOURCES.txt'
running build_ext

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK
running bdist_wheel
running build
running build_py
(Reading database ... 155852 files and directories currently installed.)
Preparing to unpack .../libyang_1.0.73_amd64.deb ...
Unpacking libyang (1.0.73) over (1.0.73) ...
Setting up libyang (1.0.73) ...
Processing triggers for libc-bin (2.24-11+deb9u4) ...
Processing triggers for man-db (2.7.6.1-2) ...
(Reading database ... 155852 files and directories currently installed.)
Preparing to unpack .../libyang-cpp_1.0.73_amd64.deb ...
Unpacking libyang-cpp (1.0.73) over (1.0.73) ...
Setting up libyang-cpp (1.0.73) ...
Processing triggers for libc-bin (2.24-11+deb9u4) ...
(Reading database ... 155852 files and directories currently installed.)
Preparing to unpack .../python3-yang_1.0.73_amd64.deb ...
Unpacking python3-yang (1.0.73) over (1.0.73) ...
Setting up python3-yang (1.0.73) ...
INFO:YANG-TEST:module: sonic-vlan is loaded successfully
ERROR:YANG-TEST:Could not get module: sonic-head
INFO:YANG-TEST:module: sonic-portchannel is loaded successfully
INFO:YANG-TEST:module: sonic-acl is loaded successfully
INFO:YANG-TEST:module: sonic-loopback-interface is loaded successfully
ERROR:YANG-TEST:Could not get module: sonic-port
INFO:YANG-TEST:module: sonic-interface is loaded successfully
INFO:YANG-TEST:
------------------- Test 1: Configure a member port in VLAN_MEMBER table which does not exist.---------------------
libyang[0]: Leafref "/sonic-port:sonic-port/sonic-port:PORT/sonic-port:PORT_LIST/sonic-port:port_name" of value "Ethernet156" points to a non
-existing leaf. (path: /sonic-vlan:sonic-vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlan_name='Vlan100'][port='Ethernet156']/port)
INFO:YANG-TEST:Configure a member port in VLAN_MEMBER table which does not exist. Passed

INFO:YANG-TEST:
------------------- Test 2: Configure non-existing ACL_TABLE in ACL_RULE.---------------------
libyang[0]: Leafref "/sonic-acl:sonic-acl/sonic-acl:ACL_TABLE/sonic-acl:ACL_TABLE_LIST/sonic-acl:ACL_TABLE_NAME" of value "NOT-EXIST" points
to a non-existing leaf. (path: /sonic-acl:sonic-acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='NOT-EXIST'][RULE_NAME='Rule_20']/ACL_TABLE_NAME)
INFO:YANG-TEST:Configure non-existing ACL_TABLE in ACL_RULE. Passed

INFO:YANG-TEST:
------------------- Test 3: Configure IP_TYPE as ARP and ICMPV6_CODE in ACL_RULE.---------------------
libyang[0]: When condition "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV6' or .='IPv6ANY'])" not satisfied. (path: /sonic-acl:sonic-acl/ACL_RU
LE/ACL_RULE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V4'][RULE_NAME='Rule_40']/ICMPV6_CODE)
INFO:YANG-TEST:Configure IP_TYPE as ARP and ICMPV6_CODE in ACL_RULE. Passed
INFO:YANG-TEST:

INFO:YANG-TEST:
------------------- Test 4: Configure IP_TYPE as ipv4any and SRC_IPV6 in ACL_RULE.---------------------
libyang[0]: When condition "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV6' or .='IPv6ANY'])" not satisfied. (path: /sonic-acl:sonic-acl/ACL_RU
LE/ACL_RULE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V4'][RULE_NAME='Rule_20']/SRC_IPV6)
INFO:YANG-TEST:Configure IP_TYPE as ipv4any and SRC_IPV6 in ACL_RULE. Passed

------------------- Test 5: Configure l4_src_port_range as 99999-99999 in ACL_RULE---------------------
libyang[0]: Value "99999-99999" does not satisfy the constraint "([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])" (range, length, or pattern). (path: /sonic-acl:sonic-acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V6'][RULE_NAME='Rule_20']/L4_SRC_PORT_RANGE)
INFO:YANG-TEST:Configure l4_src_port_range as 99999-99999 in ACL_RULE Passed

INFO:YANG-TEST:
------------------- Test 6: Configure empty string as ip-prefix in INTERFACE table.---------------------
libyang[0]: Invalid value "" in "ip-prefix" element. (path: /sonic-interface:sonic-interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='']/ip-prefix)
INFO:YANG-TEST:Configure empty string as ip-prefix in INTERFACE table. Passed

INFO:YANG-TEST:
------------------- Test 7: Configure Wrong family with ip-prefix for VLAN_Interface Table---------------------
libyang[0]: Must condition "(contains(../ip-prefix, ':') and current()='IPv6') or                               (contains(../ip-prefix, '.') and current()='IPv4')" not satisfied. (path: /sonic-vlan:sonic-vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='100'][ip-prefix='2a04:5555:66:7777::1/64']/family)
INFO:YANG-TEST:Configure Wrong family with ip-prefix for VLAN_Interface Table Passed

INFO:YANG-TEST:
------------------- Test 8: Configure IP_TYPE as ARP and DST_IPV6 in ACL_RULE.---------------------
libyang[0]: When condition "boolean(IP_TYPE[.='ANY' or .='IP' or .='IPV6' or .='IPV6ANY'])" not satisfied. (path: /sonic-acl:sonic-acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='NO-NS
W-PACL-V6'][RULE_NAME='Rule_20']/DST_IPV6)
INFO:YANG-TEST:Configure IP_TYPE as ARP and DST_IPV6 in ACL_RULE. Passed

INFO:YANG-TEST:
------------------- Test 9: Configure INNER_ETHER_TYPE as 0x080C in ACL_RULE.---------------------
libyang[0]: Value "0x080C" does not satisfy the constraint "(0x88CC|0x8100|0x8915|0x0806|0x0800|0x86DD|0x8847)" (range, length, or pattern). (path: /sonic-acl:sonic-acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V4'][RULE_NAME='Rule_40']/INNER_ETHER_TYPE)
INFO:YANG-TEST:Configure INNER_ETHER_TYPE as 0x080C in ACL_RULE. Passed

INFO:YANG-TEST:
------------------- Test 10: Add dhcp_server which is not in correct ip-prefix format.---------------------
libyang[0]: Invalid value "10.186.72.566" in "dhcp_servers" element. (path: /sonic-vlan:sonic-vlan/VLAN/VLAN_LIST/dhcp_servers[.='10.186.72.566'])
INFO:YANG-TEST:Add dhcp_server which is not in correct ip-prefix format. Passed

INFO:YANG-TEST:
------------------- Test 11: Configure undefined acl_table_type in ACL_TABLE table.---------------------
libyang[0]: Invalid value "LAYER3V4" in "type" element. (path: /sonic-acl:sonic-acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='NO-NSW-PACL-V6']/type)
INFO:YANG-TEST:Configure undefined acl_table_type in ACL_TABLE table. Passed

INFO:YANG-TEST:
------------------- Test 12: Configure undefined packet_action in ACL_RULE table.---------------------
libyang[0]: Invalid value "SEND" in "PACKET_ACTION" element. (path: /sonic-acl:sonic-acl/ACL_RULE/ACL_RULE_LIST/PACKET_ACTION)
INFO:YANG-TEST:Configure undefined packet_action in ACL_RULE table. Passed

INFO:YANG-TEST:
------------------- Test 13: Configure wrong value for tagging_mode.---------------------
libyang[0]: Invalid value "non-tagged" in "tagging_mode" element. (path: /sonic-vlan:sonic-vlan/VLAN_MEMBER/VLAN_MEMBER_LIST/tagging_mode)
INFO:YANG-TEST:Configure wrong value for tagging_mode. Passed

INFO:YANG-TEST:
------------------- Test 14: Configure vlan-id in VLAN_MEMBER table which does not exist in VLAN  table.---------------------
libyang[0]: Leafref "../../../VLAN/VLAN_LIST/vlanid" of value "200" points to a non-existing leaf. (path: /sonic-vlan:sonic-vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='200'][port='Ethernet0']/vlanid)
libyang[0]: Leafref "../../../VLAN/VLAN_LIST/vlanid" of value "200" points to a non-existing leaf. (path: /sonic-vlan:sonic-vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='200'][port='Ethernet0']/vlanid)
INFO:YANG-TEST:Configure vlan-id in VLAN_MEMBER table which does not exist in VLAN  table. Passed

INFO:YANG-TEST:All Test Passed
../../target/debs/stretch/libyang0.16_0.16.105-1_amd64.deb installtion failed
../../target/debs/stretch/libyang-cpp0.16_0.16.105-1_amd64.deb installtion failed
../../target/debs/stretch/python2-yang_0.16.105-1_amd64.deb installtion failed
YANG Tests passed
Passed: pyang -f tree ./yang-models/*.yang > ./yang-models/sonic_yang_tree
copying tests/yangModelTesting.py -> build/lib/tests
copying tests/test_sonic_yang_models.py -> build/lib/tests
copying tests/__init__.py -> build/lib/tests
running egg_info
writing top-level names to sonic_yang_models.egg-info/top_level.txt
writing dependency_links to sonic_yang_models.egg-info/dependency_links.txt
writing sonic_yang_models.egg-info/PKG-INFO
reading manifest file 'sonic_yang_models.egg-info/SOURCES.txt'
writing manifest file 'sonic_yang_models.egg-info/SOURCES.txt'
installing to build/bdist.linux-x86_64/wheel
running install
running install_lib
creating build/bdist.linux-x86_64/wheel
creating build/bdist.linux-x86_64/wheel/tests
copying build/lib/tests/yangModelTesting.py -> build/bdist.linux-x86_64/wheel/tests
copying build/lib/tests/test_sonic_yang_models.py -> build/bdist.linux-x86_64/wheel/tests
copying build/lib/tests/__init__.py -> build/bdist.linux-x86_64/wheel/tests
running install_data
creating build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data
creating build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data
creating build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-head.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-acl.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-interface.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-loopback-interface.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-port.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-portchannel.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
copying ./yang-models/sonic-vlan.yang -> build/bdist.linux-x86_64/wheel/sonic_yang_models-1.0.data/data/yang-models
```
This commit is contained in:
Praveen Chaudhary 2020-04-14 15:36:02 -07:00 committed by GitHub
parent e04eb806b6
commit a02255e2f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 2795 additions and 2 deletions

View File

@ -116,6 +116,15 @@ sudo cp {{swsssdk_py2_wheel_path}} $FILESYSTEM_ROOT/$SWSSSDK_PY2_WHEEL_NAME
sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install $SWSSSDK_PY2_WHEEL_NAME
sudo rm -rf $FILESYSTEM_ROOT/$SWSSSDK_PY2_WHEEL_NAME
# Install sonic-yang-models py3 package, install dependencies
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libyang_*.deb
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libyang-cpp_*.deb
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/python2-yang_*.deb
SONIC_YANG_MODEL_PY3_WHEEL_NAME=$(basename {{sonic_yang_models_py3_wheel_path}})
sudo cp {{sonic_yang_models_py3_wheel_path}} $FILESYSTEM_ROOT/$SONIC_YANG_MODEL_PY3_WHEEL_NAME
sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip3 install $SONIC_YANG_MODEL_PY3_WHEEL_NAME
sudo rm -rf $FILESYSTEM_ROOT/$SONIC_YANG_MODEL_PY3_WHEEL_NAME
# Install sonic-platform-common Python 2 package
PLATFORM_COMMON_PY2_WHEEL_NAME=$(basename {{platform_common_py2_wheel_path}})
sudo cp {{platform_common_py2_wheel_path}} $FILESYSTEM_ROOT/$PLATFORM_COMMON_PY2_WHEEL_NAME

View File

@ -0,0 +1,7 @@
SONIC_YANG_MODELS_PY3 = sonic_yang_models-1.0-py3-none-any.whl
$(SONIC_YANG_MODELS_PY3)_SRC_PATH = $(SRC_PATH)/sonic-yang-models
$(SONIC_YANG_MODELS_PY3)_PYTHON_VERSION = 3
$(SONIC_YANG_MODELS_PY3)_DEBS_DEPENDS = $(LIBYANG)
SONIC_PYTHON_WHEELS += $(SONIC_YANG_MODELS_PY3)
export SONIC_YANG_MODELS_PY3

View File

@ -49,6 +49,8 @@ export BUILD_NUMBER
export BUILD_TIMESTAMP
export CONFIGURED_PLATFORM
export CONFIGURED_ARCH
export STRETCH_DEBS_PATH
export PYTHON_WHEELS_PATH
###############################################################################
## Utility rules
@ -525,7 +527,8 @@ SONIC_TARGET_LIST += $(addprefix $(PYTHON_DEBS_PATH)/, $(SONIC_PYTHON_STDEB_DEBS
# $(SOME_NEW_WHL)_DEPENDS = $(SOME_OTHER_WHL1) $(SOME_OTHER_WHL2) ...
# SONIC_PYTHON_WHEELS += $(SOME_NEW_WHL)
$(addprefix $(PYTHON_WHEELS_PATH)/, $(SONIC_PYTHON_WHEELS)) : $(PYTHON_WHEELS_PATH)/% : .platform $$(addsuffix -install,$$(addprefix $(PYTHON_WHEELS_PATH)/,$$($$*_DEPENDS))) \
$(call dpkg_depend,$(PYTHON_WHEELS_PATH)/%.dep)
$(call dpkg_depend,$(PYTHON_WHEELS_PATH)/%.dep) \
$$(addsuffix -install,$$(addprefix $(DEBS_PATH)/,$$($$*_DEBS_DEPENDS)))
$(HEADER)
@ -750,7 +753,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_CONFIG_ENGINE)) \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_COMMON_PY2)) \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(REDIS_DUMP_LOAD_PY2)) \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_API_PY2))
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_API_PY2)) \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_YANG_MODELS_PY3))
$(HEADER)
# Pass initramfs and linux kernel explicitly. They are used for all platforms
export debs_path="$(STRETCH_DEBS_PATH)"
@ -780,6 +784,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \
export platform_common_py2_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_COMMON_PY2))"
export redis_dump_load_py2_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(REDIS_DUMP_LOAD_PY2))"
export install_debug_image="$(INSTALL_DEBUG_TOOLS)"
export sonic_yang_models_py3_wheel_path="$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_YANG_MODELS_PY3))"
export multi_instance="false"
$(foreach docker, $($*_DOCKERS),\

View File

@ -367,6 +367,13 @@ RUN pip install mockredispy==2.9.3
RUN pip install pytest-runner==4.4
RUN pip install setuptools==40.8.0
# For sonic_yang_mgmt build
RUN pip install ijson==2.6.1
RUN pip3 install ijson==2.6.1
RUN pip install jsondiff==1.2.0
RUN pip install xmltodict==0.12.0
RUN pip install pyang==2.1.1
# For mgmt-framework build
RUN pip install mmh3

View File

@ -0,0 +1,14 @@
=======
Credits
=======
Development Lead
----------------
LNOS-CODERS <lnos-coders@linkedin.com>
MSFT-LINUX-DEV <linuxnetdev@microsoft.com>
Contributors
------------
Praveen Chaudhary <pchaudhary@linkedin.com>

View File

@ -0,0 +1,13 @@
Copyright 2019 Microsoft, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,4 @@
"
This Package contains YANG models for sonic which are written with guidelines mentioned in
https://github.com/Azure/SONiC/blob/master/doc/mgmt/SONiC_YANG_Model_Guidelines.md.
"

View File

@ -0,0 +1,114 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""The setup script."""
from setuptools import setup, find_packages
from setuptools.command.build_py import build_py
from os import system, environ
from sys import exit
# find path of pkgs from environment vars
prefix = '/sonic'; debs = environ["STRETCH_DEBS_PATH"]
deps_path = '{}/{}'.format(prefix, debs)
# dependencies
libyang = '{}/{}'.format(deps_path, environ["LIBYANG"])
libyangCpp = '{}/{}'.format(deps_path, environ["LIBYANG_CPP"])
libyangPy2 = '{}/{}'.format(deps_path, environ["LIBYANG_PY2"])
libyangPy3 = '{}/{}'.format(deps_path, environ["LIBYANG_PY3"])
# important reuirements parameters
build_requirements = [libyang, libyangCpp, libyangPy2, libyangPy3,]
setup_requirements = ['pytest-runner']
test_requirements = ['pytest>=3']
# read me
with open('README.rst') as readme_file:
readme = readme_file.read()
# class for prerequisites to build this package
class pkgBuild(build_py):
"""Custom Build PLY"""
def run (self):
# install libyang
for req in build_requirements:
if '.deb'in req:
pkg_install_cmd = "sudo dpkg -i {}".format(req)
if (system(pkg_install_cmd)):
print("{} installation failed".format(req))
exit(1)
else:
print("{} installed".format(req))
# json file for YANG model test cases.
test_yangJson_file = './tests/yang_model_tests/yangTest.json'
# YANG models are in below dir
yang_model_dir = './yang-models/'
# yang model tester python module
yang_test_py = './tests/yang_model_tests/yangModelTesting.py'
# run tests for yang models
test_yang_cmd = "python {} -f {} -y {}".format(yang_test_py, test_yangJson_file, yang_model_dir)
if (system(test_yang_cmd)):
print("YANG Tests failed\n")
# below line will be uncommented after libyang python support PR #
exit(1)
else:
print("YANG Tests passed\n")
# Generate YANG Tree
pyang_tree_cmd = "pyang -f tree ./yang-models/*.yang > ./yang-models/sonic_yang_tree"
if (system(pyang_tree_cmd)):
print("Failed: {}".format(pyang_tree_cmd))
else:
print("Passed: {}".format(pyang_tree_cmd))
# Continue usual build steps
build_py.run(self)
setup(
cmdclass={
'build_py': pkgBuild,
},
author="lnos-coders",
author_email='lnos-coders@linkedin.com',
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Natural Language :: English',
"Programming Language :: Python :: 2",
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
description="Package contains YANG models for sonic.",
tests_require = test_requirements,
license="GNU General Public License v3",
long_description=readme + '\n\n',
include_package_data=True,
keywords='sonic_yang_models',
name='sonic_yang_models',
py_modules=[],
packages=find_packages(),
setup_requires=setup_requirements,
version='1.0',
data_files=[
('yang-models', ['./yang-models/sonic-types.yang',
'./yang-models/sonic-extension.yang',
'./yang-models/sonic-acl.yang',
'./yang-models/sonic-interface.yang',
'./yang-models/sonic-loopback-interface.yang',
'./yang-models/sonic-port.yang',
'./yang-models/sonic-portchannel.yang',
'./yang-models/sonic-vlan.yang',
'./yang-models/sonic_yang_tree']),
],
zip_safe=False,
)

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
"""Unit test package for sonic_yang_models."""

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tests for `sonic_yang_models` package."""
import pytest
@pytest.fixture
def response():
"""Sample pytest fixture.
See more at: http://doc.pytest.org/en/latest/fixture.html
"""
# import requests
# return requests.get('https://github.com/audreyr/cookiecutter-pypackage')
def test_content(response):
"""Sample pytest test function with the pytest fixture as an argument."""
# from bs4 import BeautifulSoup
# assert 'GitHub' in BeautifulSoup(response.content).title.string

View File

@ -0,0 +1,288 @@
# This script is used to
import yang as ly
import logging
import argparse
import sys
import ijson
import json
#import sonic_yang as sy
from glob import glob
from os import listdir
from os.path import isfile, join, splitext
#Globals vars
PASS = 0
FAIL = 1
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger("YANG-TEST")
log.setLevel(logging.INFO)
log.addHandler(logging.NullHandler())
# Global functions
def printExceptionDetails():
try:
excType, excObj, traceBack = sys.exc_info()
fileName = traceBack.tb_frame.f_code.co_filename
lineNumber = traceBack.tb_lineno
log.error(" Exception >{}< in {}:{}".format(excObj, fileName, lineNumber))
except Exception as e:
log.error(" Exception in printExceptionDetails")
return
# class for YANG Model YangModelTesting
# Run function will run all the tests
# from a user given list.
class YangModelTesting:
def __init__(self, tests, yangDir, jsonFile):
self.defaultYANGFailure = {
'Must': ['Must condition', 'not satisfied'],
'InvalidValue': ['Invalid value'],
'LeafRef': ['Leafref', 'non-existing'],
'When': ['When condition', 'not satisfied'],
'Pattern': ['pattern', 'does not satisfy'],
'None': ['']
}
self.ExceptionTests = {
'WRONG_FAMILY_WITH_IP_PREFIX': {
'desc': 'Configure Wrong family with ip-prefix for VLAN_Interface Table',
'eStr': self.defaultYANGFailure['Must']
},
'DHCP_SERVER_INCORRECT_FORMAT': {
'desc': 'Add dhcp_server which is not in correct ip-prefix format.',
'eStr': self.defaultYANGFailure['InvalidValue'] + ['dhcp_servers']
},
'VLAN_WITH_NON_EXIST_PORT': {
'desc': 'Configure a member port in VLAN_MEMBER table which does not exist.',
'eStr': self.defaultYANGFailure['LeafRef']
},
'VLAN_MEMEBER_WITH_NON_EXIST_VLAN': {
'desc': 'Configure vlan-id in VLAN_MEMBER table which does not exist in VLAN table.',
'eStr': self.defaultYANGFailure['LeafRef']
},
'TAGGING_MODE_WRONG_VALUE': {
'desc': 'Configure wrong value for tagging_mode.',
'eStr': self.defaultYANGFailure['InvalidValue'] + ['tagging_mode']
},
'INTERFACE_IP_PREFIX_EMPTY_STRING': {
'desc': 'Configure empty string as ip-prefix in INTERFACE table.',
'eStr': self.defaultYANGFailure['InvalidValue'] + ['ip-prefix']
},
'ACL_RULE_UNDEFINED_PACKET_ACTION': {
'desc': 'Configure undefined packet_action in ACL_RULE table.',
'eStr': self.defaultYANGFailure['InvalidValue'] + ['PACKET_ACTION']
},
'ACL_TABLE_UNDEFINED_TABLE_TYPE': {
'desc': 'Configure undefined acl_table_type in ACL_TABLE table.',
'eStr': self.defaultYANGFailure['InvalidValue'] + ['type']
},
'ACL_RULE_WITH_NON_EXIST_ACL_TABLE': {
'desc': 'Configure non-existing ACL_TABLE in ACL_RULE.',
'eStr': self.defaultYANGFailure['LeafRef']
},
'ACL_RULE_IP_TYPE_SRC_IPV6_MISMATCH': {
'desc': 'Configure IP_TYPE as ipv4any and SRC_IPV6 in ACL_RULE.',
'eStr': self.defaultYANGFailure['When'] + ['IP_TYPE']
},
'ACL_RULE_ARP_TYPE_DST_IPV6_MISMATCH': {
'desc': 'Configure IP_TYPE as ARP and DST_IPV6 in ACL_RULE.',
'eStr': self.defaultYANGFailure['When'] + ['IP_TYPE']
},
'ACL_RULE_WRONG_L4_SRC_PORT_RANGE': {
'desc': 'Configure l4_src_port_range as 99999-99999 in ACL_RULE',
'eStr': self.defaultYANGFailure['Pattern']
},
'ACL_RULE_ARP_TYPE_ICMPV6_CODE_MISMATCH': {
'desc': 'Configure IP_TYPE as ARP and ICMPV6_CODE in ACL_RULE.',
'eStr': self.defaultYANGFailure['When'] + ['IP_TYPE']
},
'ACL_RULE_WRONG_INNER_ETHER_TYPE': {
'desc': 'Configure INNER_ETHER_TYPE as 0x080C in ACL_RULE.',
'eStr': self.defaultYANGFailure['Pattern']
},
'INTERFACE_IPPREFIX_PORT_MUST_CONDITION_FALSE': {
'desc': 'Interface Ip-prefix port-name must condition failure.',
'eStr': self.defaultYANGFailure['Must']
},
'INTERFACE_IPPREFIX_PORT_MUST_CONDITION_TRUE': {
'desc': 'Interface Ip-prefix port-name must condition pass.',
'eStr': self.defaultYANGFailure['None']
},
'VLAN_INTERFACE_IPPREFIX_MUST_CONDITION_FALSE': {
'desc': 'Vlan Interface Ip-prefix must condition failure.',
'eStr': self.defaultYANGFailure['Must']
},
'LOOPBACK_IPPREFIX_PORT_MUST_CONDITION_FALSE': {
'desc': 'Loopback Ip-prefix port-name must condition failure.',
'eStr': self.defaultYANGFailure['Must']
}
}
self.tests = tests
if (self.tests == None):
self.tests = self.ExceptionTests.keys()
self.yangDir = yangDir
self.jsonFile = jsonFile
self.testNum = 1
# other class vars
# self.ctx
return
"""
load all YANG models before test run
"""
def loadYangModel(self, yangDir):
try:
# create context
self.ctx = ly.Context(yangDir)
# get all files
yangFiles = glob(yangDir +"/*.yang")
# load yang modules
for file in yangFiles:
log.debug(file)
m = self.ctx.parse_module_path(file, ly.LYS_IN_YANG)
if m is not None:
log.info("module: {} is loaded successfully".format(m.name()))
else:
log.info("Could not load module: {}".format(file))
except Exception as e:
printExceptionDetails()
raise e
return
"""
Run all tests from list self.tests
"""
def run(self):
try:
self.loadYangModel(self.yangDir)
ret = 0
for test in self.tests:
test = test.strip()
if test in self.ExceptionTests:
ret = ret + self.runExceptionTest(test);
except Exception as e:
printExceptionDetails()
raise e
return ret
"""
Get the JSON input based on func name
and return jsonInput
"""
def readJsonInput(self, test):
try:
# load test specific Dictionary, using Key = func
# this is to avoid loading very large JSON in memory
log.debug(" Read JSON Section: " + test)
jInput = ""
with open(self.jsonFile, 'rb') as f:
jInst = ijson.items(f, test)
for it in jInst:
jInput = jInput + json.dumps(it)
log.debug(jInput)
except Exception as e:
printExceptionDetails()
return jInput
"""
Log the start of a test
"""
def logStartTest(self, desc):
log.info("\n------------------- Test "+ str(self.testNum) +\
": " + desc + "---------------------")
self.testNum = self.testNum + 1
return
"""
Load Config Data and return Exception as String
"""
def loadConfigData(self, jInput):
s = ""
try:
node = self.ctx.parse_data_mem(jInput, ly.LYD_JSON, \
ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT)
except Exception as e:
s = str(e)
log.debug(s)
return s
"""
Run Exception Test
"""
def runExceptionTest(self, test):
try:
desc = self.ExceptionTests[test]['desc']
self.logStartTest(desc)
jInput = self.readJsonInput(test)
# load the data, expect a exception with must condition failure
s = self.loadConfigData(jInput)
eStr = self.ExceptionTests[test]['eStr']
log.debug(eStr)
if (sum(1 for str in eStr if str not in s) == 0):
log.info(desc + " Passed\n")
return PASS
except Exception as e:
printExceptionDetails()
log.info(desc + " Failed\n")
return FAIL
# End of Class
"""
Start Here
"""
def main():
parser = argparse.ArgumentParser(description='Script to run YANG model tests',
formatter_class=argparse.RawTextHelpFormatter,
epilog="""
Usage:
python yangModelTesting.py -h
""")
parser.add_argument('-t', '--tests', type=str, \
help='tests to run separated by comma')
parser.add_argument('-f', '--json-file', type=str, \
help='JSON input for tests ', required=True)
parser.add_argument('-y', '--yang-dir', type=str, \
help='Path to YANG models', required=True)
parser.add_argument('-v', '--verbose-level', \
help='Verbose mode', action='store_true')
parser.add_argument('-l', '--list-tests', \
help='list all tests', action='store_true')
args = parser.parse_args()
try:
tests = args.tests
jsonFile = args.json_file
yangDir = args.yang_dir
logLevel = args.verbose_level
listTests = args.list_tests
if logLevel:
log.setLevel(logging.DEBUG)
# Make a list
if (tests):
tests = tests.split(",")
yTest = YangModelTesting(tests, yangDir, jsonFile)
if (listTests):
for key in yTest.ExceptionTests.keys():
log.info(key)
sys.exit(0)
ret = yTest.run()
if ret == 0:
log.info("All Test Passed")
sys.exit(ret)
except Exception as e:
printExceptionDetails()
sys.exit(1)
return
if __name__ == '__main__':
main()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
module sonic-acl {
yang-version 1.1;
namespace "http://github.com/Azure/sonic-acl";
prefix acl;
import ietf-yang-types {
prefix yang;
}
import ietf-inet-types {
prefix inet;
}
import sonic-types {
prefix stypes;
revision-date 2019-07-01;
}
import sonic-extension {
prefix ext;
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;
}
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";
ext:key-regex-configdb-to-yang "^([a-zA-Z0-9_-]+)|([a-zA-Z0-9_-]+)$";
ext:key-regex-yang-to-configdb "<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 stypes:packet_action;
}
leaf IP_TYPE {
type stypes: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";
ext:key-regex-configdb-to-yang "^([a-zA-Z0-9-_]+)$";
ext:key-regex-yang-to-configdb "<ACL_TABLE_NAME>";
leaf ACL_TABLE_NAME {
type string;
}
leaf policy_desc {
type string {
length 1..255;
}
}
leaf type {
type stypes: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 */

View File

@ -0,0 +1,23 @@
module sonic-extension {
yang-version 1.1;
namespace "http://github.com/Azure/sonic-extension";
prefix sonic-extension;
description "Extension yang Module for SONiC OS";
revision 2019-07-01 {
description "First Revision";
}
extension key-regex-configdb-to-yang {
description "Key regex used to convert config DB keys to YANG Config";
argument "value";
}
extension key-regex-yang-to-configdb {
description "Key regex used to convert config DB keys to YANG Config";
argument "value";
}
}

View File

@ -0,0 +1,122 @@
module sonic-interface {
yang-version 1.1;
namespace "http://github.com/Azure/sonic-interface";
prefix intf;
import ietf-yang-types {
prefix yang;
}
import ietf-inet-types {
prefix inet;
}
import sonic-types {
prefix stypes;
revision-date 2019-07-01;
}
import sonic-extension {
prefix ext;
revision-date 2019-07-01;
}
import sonic-port {
prefix port;
revision-date 2019-07-01;
}
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 {
description "INTERFACE part of config_db.json with vrf";
key "port_name";
ext:key-regex-configdb-to-yang "^(Ethernet[0-9]+)$";
ext:key-regex-yang-to-configdb "<port_name>";
leaf port_name {
type leafref {
path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name;
}
}
leaf vrf_name {
type string {
pattern "Vrf[a-zA-Z0-9_-]+";
length 3..255;
}
}
}
/* end of INTERFACE_LIST */
list INTERFACE_IPPREFIX_LIST {
description "INTERFACE part of config_db.json with ip-prefix";
key "port_name ip-prefix";
ext:key-regex-configdb-to-yang "^(Ethernet[0-9]+)|([a-fA-F0-9:./]+)$";
ext:key-regex-yang-to-configdb "<port_name>|<ip-prefix>";
leaf port_name {
/* This node must be present in INTERFACE_LIST */
must "(current() = ../../INTERFACE_LIST[port_name=current()]/port_name)"
{
error-message "Must condition not satisfied, Try adding PORT: {}, Example: 'Ethernet0': {}";
}
type leafref {
path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name;
}
}
leaf ip-prefix {
type union {
type stypes:sonic-ip4-prefix;
type stypes:sonic-ip6-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 stypes:ip-family;
}
}
/* end of INTERFACE_IPPREFIX_LIST */
}
/* end of INTERFACE container */
}
}

View File

@ -0,0 +1,98 @@
module sonic-loopback-interface {
namespace "http://github.com/Azure/sonic-loopback-interface";
prefix lointf;
import ietf-inet-types {
prefix inet;
}
import sonic-types {
prefix stypes;
revision-date 2019-07-01;
}
import sonic-extension {
prefix ext;
revision-date 2019-07-01;
}
description
"SONIC LOOPBACK INTERFACE";
revision 2020-02-05 {
description "First Revision";
}
container sonic-loopback-interface {
container LOOPBACK_INTERFACE {
list LOOPBACK_INTERFACE_LIST {
key "loopback_interface_name";
ext:key-regex-configdb-to-yang "^([a-zA-Z0-9-_]+)$";
ext:key-regex-yang-to-configdb "<loopback_interface_name>";
leaf loopback_interface_name{
type string;
}
leaf vrf_name {
type string {
pattern "Vrf[a-zA-Z0-9_-]+";
length 3..255;
}
}
}
/* end of LOOPBACK_INTERFACE_LIST */
list LOOPBACK_INTERFACE_IPPREFIX_LIST {
key "loopback_interface_name ip-prefix";
ext:key-regex-configdb-to-yang "^([a-zA-Z0-9-_]+)|([a-fA-F0-9:./]+$)";
ext:key-regex-yang-to-configdb "<loopback_interface_name>|<ip-prefix>";
leaf loopback_interface_name{
/* This node must be present in LOOPBACK_INTERFACE_LIST */
must "(current() = ../../LOOPBACK_INTERFACE_LIST[loopback_interface_name=current()]/loopback_interface_name)"
{
error-message "Must condition not satisfied, Try adding lo<>: {}, Example: 'lo1': {}";
}
type string;
}
leaf ip-prefix {
type union {
type stypes:sonic-ip4-prefix;
type stypes:sonic-ip6-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 stypes:ip-family;
}
}
}
/* end of LOOPBACK_INTERFACE_IPPREFIX_LIST */
}
}

View File

@ -0,0 +1,105 @@
module sonic-port{
yang-version 1.1;
namespace "http://github.com/Azure/sonic-port";
prefix port;
import ietf-yang-types {
prefix yang;
}
import ietf-inet-types {
prefix inet;
}
import sonic-types {
prefix stypes;
revision-date 2019-07-01;
}
import sonic-extension {
prefix ext;
revision-date 2019-07-01;
}
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";
ext:key-regex-configdb-to-yang "^(Ethernet[0-9]+)$";
ext:key-regex-yang-to-configdb "<port_name>";
leaf port_name {
type string {
length 1..128;
}
}
leaf alias {
type string {
length 1..128;
}
}
leaf lanes {
mandatory true;
type string {
length 1..128;
}
}
leaf description {
type string {
length 0..255;
}
}
leaf speed {
mandatory true;
type uint32 {
range 1..100000;
}
}
leaf mtu {
type uint16 {
range 1..9216;
}
}
leaf index {
type uint16 {
range 0..256;
}
}
leaf admin_status {
type stypes:admin_status;
}
leaf fec {
type string {
pattern "rc|fc|None";
}
}
} /* end of list PORT_LIST */
} /* end of container PORT */
} /* end of container sonic-port */
} /* end of module sonic-port */

View File

@ -0,0 +1,92 @@
module sonic-portchannel {
yang-version 1.1;
namespace "http://github.com/Azure/sonic-portchannel";
prefix lag;
import ietf-yang-types {
prefix yang;
}
import ietf-inet-types {
prefix inet;
}
import sonic-types {
prefix stypes;
revision-date 2019-07-01;
}
import sonic-extension {
prefix ext;
revision-date 2019-07-01;
}
import sonic-port {
prefix port;
revision-date 2019-07-01;
}
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";
ext:key-regex-configdb-to-yang "^(Ethernet[0-9]+)$";
ext:key-regex-yang-to-configdb "<port_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 stypes:admin_status;
}
} /* end of list PORTCHANNEL_LIST */
} /* end of container PORTCHANNEL */
} /* end of container sonic-portchannel */
} /* end of module sonic-port */

View File

@ -0,0 +1,92 @@
module sonic-types {
yang-version 1.1;
namespace "http://github.com/Azure/sonic-head";
prefix sonic-types;
description "SONiC type for yang Models of SONiC OS";
revision 2019-07-01 {
description "First Revision";
}
typedef ip-family {
type enumeration {
enum IPv4;
enum IPv6;
}
}
typedef sonic-ip4-prefix {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
}
}
typedef sonic-ip6-prefix {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(/.+)';
}
}
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_IP4;
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;
}
}
}

View File

@ -0,0 +1,209 @@
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-types {
prefix stypes;
revision-date 2019-07-01;
}
import sonic-extension {
prefix ext;
revision-date 2019-07-01;
}
import sonic-port {
prefix port;
revision-date 2019-07-01;
}
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 {
description "VLAN INTERFACE part of config_db.json with vrf";
key "vlan_name";
ext:key-regex-configdb-to-yang "^(Vlan[a-zA-Z0-9_-]+)$";
ext:key-regex-yang-to-configdb "<vlan_name>";
leaf vlan_name {
type leafref {
path /vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlan_name;
}
}
leaf vrf_name {
type string {
pattern "Vrf[a-zA-Z0-9_-]+";
length 3..255;
}
}
}
/* end of VLAN_INTERFACE_LIST */
list VLAN_INTERFACE_IPPREFIX_LIST {
key "vlan_name ip-prefix";
ext:key-regex-configdb-to-yang "^(Vlan[a-zA-Z0-9_-]+)|([a-fA-F0-9:./]+$)";
ext:key-regex-yang-to-configdb "<vlan_name>|<ip-prefix>";
leaf vlan_name {
/* This node must be present in VLAN_INTERFACE_LIST */
must "(current() = ../../VLAN_INTERFACE_LIST[vlan_name=current()]/vlan_name)"
{
error-message "Must condition not satisfied, Try adding Vlan<vlanid>: {}, Example: 'Vlan100': {}";
}
type leafref {
path "/vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlan_name";
}
}
leaf ip-prefix {
type union {
type stypes:sonic-ip4-prefix;
type stypes:sonic-ip6-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 stypes: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 "vlan_name";
ext:key-regex-configdb-to-yang "^(Vlan[a-zA-Z0-9_-]+)$";
ext:key-regex-yang-to-configdb "<vlan_name>";
leaf vlan_name {
type string {
pattern 'Vlan([0-9]{1,3}|[0-3][0-9]{4}|[4][0][0-8][0-9]|[4][0][9][0-4])';
}
}
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 {
type stypes: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 "vlan_name port";
ext:key-regex-configdb-to-yang "^(Vlan[a-zA-Z0-9-_]+)|(Ethernet[0-9]+)$";
ext:key-regex-yang-to-configdb "<vlan_name>|<port>";
leaf vlan_name {
type leafref {
path "/vlan:sonic-vlan/vlan:VLAN/vlan:VLAN_LIST/vlan:vlan_name";
}
}
leaf port {
/* key elements are mandatory by default */
type leafref {
path /port:sonic-port/port:PORT/port:PORT_LIST/port:port_name;
}
}
leaf tagging_mode {
mandatory true;
type stypes:vlan_tagging_mode;
}
}
/* end of list VLAN_MEMBER_LIST */
}
/* end of container VLAN_MEMBER */
}
/* end of container sonic-vlan */
}
/* end of module sonic-vlan */