From fe735e35c64af107f050a7ce1b4fb20412b39690 Mon Sep 17 00:00:00 2001 From: ShiyanWangMS Date: Tue, 31 Oct 2023 09:44:55 +0800 Subject: [PATCH 01/10] Upgrade Ansible to 6.7.0 and make Python3 as the default interpreter in sonic-mgmt-docker (#17021) Why I did it This PR is part of sonic-mgmt-docker Python3 migration project. Work item tracking Microsoft ADO (number only): 24397943 How I did it Upgrade Ansible to 6.7.0 Make Python3 as the default interpreter. python is a soft link to python3. If you want to use python2, use the command python2 explicitly. Upgrade some pip packages to higher version in order to meet security requirement. How to verify it Build a private sonic-mgmt-docker successfully. Verify python is python3. Verify python2 is working with 202012 and 202205 branch. Verify python3 is working with master branch. Verify with github PR test. --- ...ributeError-in-multi-thread-scenario.patch | 46 ++++++++++++ dockers/docker-sonic-mgmt/Dockerfile.j2 | 74 ++++++++----------- 2 files changed, 78 insertions(+), 42 deletions(-) create mode 100644 dockers/docker-sonic-mgmt/0001-Fix-getattr-AttributeError-in-multi-thread-scenario.patch diff --git a/dockers/docker-sonic-mgmt/0001-Fix-getattr-AttributeError-in-multi-thread-scenario.patch b/dockers/docker-sonic-mgmt/0001-Fix-getattr-AttributeError-in-multi-thread-scenario.patch new file mode 100644 index 000000000000..b7f49c4e884f --- /dev/null +++ b/dockers/docker-sonic-mgmt/0001-Fix-getattr-AttributeError-in-multi-thread-scenario.patch @@ -0,0 +1,46 @@ +From e323263795a0af4c9c61992bd7a3347d8928db39 Mon Sep 17 00:00:00 2001 +From: Xin Wang +Date: Thu, 14 Sep 2023 16:52:54 +0800 +Subject: [PATCH] Fix getattr AttributeError in multi-thread scenario + +When multi-thread is used, the plugin loader may raise AttributeError +while getting "ActionModule" from an action plugin. + +The reason is that cache is used while loading module. Before a module +is fully loaded, it is already put into the sys.modules cache. When another +thread tries to load the same module, it would load an incompletely loaded +module from the sys.modules cache. Then while getting "ActionModule" +attribute from this module, exception AttributeError could be raised. + +Signed-off-by: Xin Wang +--- + lib/ansible/plugins/loader.py | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/lib/ansible/plugins/loader.py b/lib/ansible/plugins/loader.py +index 74bdeb5719..251531b62e 100644 +--- a/lib/ansible/plugins/loader.py ++++ b/lib/ansible/plugins/loader.py +@@ -801,15 +801,14 @@ class PluginLoader: + warnings.simplefilter("ignore", RuntimeWarning) + spec = importlib.util.spec_from_file_location(to_native(full_name), to_native(path)) + module = importlib.util.module_from_spec(spec) +- +- # mimic import machinery; make the module-being-loaded available in sys.modules during import +- # and remove if there's a failure... +- sys.modules[full_name] = module +- + try: + spec.loader.exec_module(module) ++ # mimic import machinery; make the module-being-loaded available in sys.modules during import ++ # and remove if there's a failure... ++ sys.modules[full_name] = module + except Exception: +- del sys.modules[full_name] ++ if full_name in sys.modules: ++ del sys.modules[full_name] + raise + + return module +-- +2.25.1 diff --git a/dockers/docker-sonic-mgmt/Dockerfile.j2 b/dockers/docker-sonic-mgmt/Dockerfile.j2 index 2c02e47ef1ed..e4f3e07d63f6 100755 --- a/dockers/docker-sonic-mgmt/Dockerfile.j2 +++ b/dockers/docker-sonic-mgmt/Dockerfile.j2 @@ -38,10 +38,10 @@ RUN apt-get update && apt-get install -y apt-transport-https \ telnet \ vim -RUN pip3 install --upgrade pip setuptools wheel -RUN pip3 install aiohttp \ +RUN python3 -m pip install --upgrade pip setuptools wheel +RUN python3 -m pip install aiohttp \ allure-pytest==2.8.22 \ - ansible==2.9.27 \ + ansible==6.7.0 \ azure-storage-blob==12.9.0 \ azure-kusto-data \ azure-kusto-ingest \ @@ -49,7 +49,7 @@ RUN pip3 install aiohttp \ celery[redis]==5.2.7 \ cffi \ contextlib2==0.6.0.post1 \ - cryptography==3.3.2 \ + cryptography==41.0.2 \ ctypesgen \ dpkt \ dpugen==0.1.1 \ @@ -60,7 +60,7 @@ RUN pip3 install aiohttp \ ixload \ ixnetwork-restpy==1.0.64 \ ixnetwork-open-traffic-generator==0.0.79 \ - jinja2==2.10.1 \ + jinja2==3.1.2 \ jsonpatch \ lxml \ markupsafe==2.0.1 \ @@ -84,12 +84,12 @@ RUN pip3 install aiohttp \ pyro4 \ pysnmp==4.4.12 \ pysubnettree \ - pytest-ansible \ + pytest-ansible==4.0.0 \ pytest-html \ pytest-repeat \ pytest-xdist==1.28.0 \ python-dateutil \ - pytest==7.1.3 \ + pytest==7.4.0 \ PyYAML \ redis \ requests \ @@ -99,7 +99,7 @@ RUN pip3 install aiohttp \ scapy==2.4.5 \ setuptools-rust \ six \ - snappi[ixnetwork,convergence]==0.7.44 \ + snappi[ixnetwork,convergence]==0.11.16 \ tabulate \ textfsm==1.1.2 \ thrift==0.11.0 \ @@ -115,21 +115,15 @@ RUN pip3 install aiohttp \ && cd ../.. \ && rm -fr nanomsg-1.2 \ && rm -f 1.2.tar.gz \ - && pip3 install nnpy - -RUN curl -fsSL http://archive.ubuntu.com/ubuntu/pool/universe/s/scapy/python-scapy_2.3.3-3_all.deb \ - --output python-scapy_2.3.3-3_all.deb \ - && dpkg -i python-scapy_2.3.3-3_all.deb \ - && rm -f python-scapy_2.3.3-3_all.deb + && python3 -m pip install nnpy RUN curl -fsSL https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py \ && python2 get-pip.py \ - && rm -f get-pip.py \ - && ln -sf `which pip2` /usr/bin/pip + && rm -f get-pip.py -RUN pip install --upgrade pip setuptools wheel -RUN pip install allure-pytest==2.8.22 \ - ansible==2.8.12 \ +RUN python2 -m pip install --upgrade pip setuptools wheel +RUN python2 -m pip install allure-pytest==2.8.22 \ + ansible==2.8.20 \ azure-storage-blob==12.9.0 \ celery[redis]==4.4.7 \ cffi==1.12.0 \ @@ -156,11 +150,13 @@ RUN pip install allure-pytest==2.8.22 \ netmiko==2.4.2 \ nnpy \ pandas \ - paramiko==2.7.1 \ + paramiko==2.7.2 \ passlib \ pexpect \ prettytable \ + protobuf==3.15.0 \ psutil \ + ptf \ pyaml==21.10.1 \ pyasn1==0.1.9 \ pycryptodome==3.9.8 \ @@ -181,19 +177,14 @@ RUN pip install allure-pytest==2.8.22 \ retry \ rpyc \ scandir \ + scapy==2.4.5 \ six \ - snappi[ixnetwork,convergence]==0.7.44 \ + snappi[ixnetwork,convergence]==0.11.16 \ statistics \ tabulate \ textfsm==1.1.3 \ thrift==0.11.0 \ - virtualenv \ - && git clone https://github.com/p4lang/scapy-vxlan.git \ - && cd scapy-vxlan \ - && python setup.py install \ - && cd .. \ - && rm -fr scapy-vxlan \ - && pip install scapy==2.4.5 --upgrade --ignore-installed + virtualenv # Install docker-ce-cli RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \ @@ -209,16 +200,9 @@ RUN mkdir -p /etc/apt/keyrings \ && apt-get update && apt-get install -y azure-cli ## Copy and install sonic-mgmt docker dependencies -COPY \ -{% for deb in docker_sonic_mgmt_debs.split(' ') -%} -debs/{{ deb }}{{' '}} -{%- endfor -%} -debs/ +COPY debs/sonic-device-data_*.deb debs/ -RUN dpkg -i \ -{% for deb in docker_sonic_mgmt_debs.split(' ') -%} -debs/{{ deb }}{{' '}} -{%- endfor %} +RUN dpkg -i debs/sonic-device-data_*.deb # Install protobuf 3.21.12 which is from https://deb.debian.org/debian/pool/main/p/protobuf/protobuf_3.21.12-3.dsc RUN mkdir -p /tmp/protobuf \ @@ -293,7 +277,7 @@ RUN python3 -m pip install aiohttp \ celery[redis]==5.2.7 \ cffi \ contextlib2==0.6.0.post1 \ - cryptography==3.3.2 \ + cryptography==41.0.2 \ ctypesgen \ dpkt \ dpugen==0.1.1 \ @@ -316,7 +300,7 @@ RUN python3 -m pip install aiohttp \ netmiko==2.4.2 \ nnpy \ pandas \ - paramiko==2.7.1 \ + paramiko==2.7.2 \ passlib \ pexpect \ prettytable \ @@ -344,7 +328,7 @@ RUN python3 -m pip install aiohttp \ scapy==2.4.5 \ setuptools-rust \ six \ - snappi[ixnetwork,convergence]==0.7.44 \ + snappi[ixnetwork,convergence]==0.11.16 \ sshconf==0.2.5 \ tabulate \ textfsm==1.1.2 \ @@ -356,8 +340,14 @@ ENV PATH="$BACKUP_OF_PATH" USER root WORKDIR /azp -COPY ./start.sh . -RUN chmod +x start.sh +COPY start.sh \ + 0001-Fix-getattr-AttributeError-in-multi-thread-scenario.patch \ + ./ +RUN chmod +x start.sh \ + && ln -sf /usr/bin/python3 /usr/bin/python \ + && ln -sf `which pip3` /usr/bin/pip \ + && ln -sf `which pip3` /usr/local/sbin/pip \ + && patch -u -b /usr/local/lib/python3.8/dist-packages/ansible/plugins/loader.py -i /azp/0001-Fix-getattr-AttributeError-in-multi-thread-scenario.patch USER $user WORKDIR /var/$user From bf1333bc2f3983430e02820ee9f246ccae01e415 Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:43:20 +0800 Subject: [PATCH 02/10] [submodule] Update submodule sonic-snmpagent to the latest HEAD automatically (#17047) --- src/sonic-snmpagent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-snmpagent b/src/sonic-snmpagent index bdaddca5db1a..347a6e452211 160000 --- a/src/sonic-snmpagent +++ b/src/sonic-snmpagent @@ -1 +1 @@ -Subproject commit bdaddca5db1a4b7071c05bdff324257685e889d6 +Subproject commit 347a6e4522111111e13ee1ab4fd4e0a58adcf612 From ca15c6ff93a9857f88717a8f42a68344d3967051 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Tue, 31 Oct 2023 15:51:48 -0700 Subject: [PATCH 03/10] [eventd]: Disabling eventd tests (#17053) Disabling eventd unit tests until #16996 is addressed --- src/sonic-eventd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-eventd/Makefile b/src/sonic-eventd/Makefile index 835d0732a0cd..f9cc5bf8b5fa 100644 --- a/src/sonic-eventd/Makefile +++ b/src/sonic-eventd/Makefile @@ -29,7 +29,7 @@ endif -include rsyslog_plugin/subdir.mk -include rsyslog_plugin_tests/subdir.mk -all: sonic-eventd eventd-tests eventd-tool rsyslog-plugin rsyslog-plugin-tests +all: sonic-eventd eventd-tool rsyslog-plugin sonic-eventd: $(OBJS) @echo 'Building target: $@' From 3bacbc94adf6091393bf0dfcdfc7cac476b49e43 Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Wed, 1 Nov 2023 10:37:01 +0800 Subject: [PATCH 04/10] [submodule] Update submodule sonic-swss to the latest HEAD automatically (#17048) #### Why I did it src/sonic-swss ``` * 917c21e0 - (HEAD -> master, origin/master, origin/HEAD) Add more debug information when PFC WD is triggered (#2858) (10 hours ago) [Stephen Sun] ``` #### How I did it #### How to verify it #### Description for the changelog --- src/sonic-swss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss b/src/sonic-swss index a9867e67c369..917c21e0199f 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit a9867e67c36932312ea5696ccf9a65874e71a64b +Subproject commit 917c21e0199f3897479f70827333841cecc3d8b3 From f61590d5e2b75a7ffb220a4ea0564463cd02bbed Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:54:43 +0800 Subject: [PATCH 05/10] [submodule] Update submodule sonic-utilities to the latest HEAD automatically (#17057) --- src/sonic-utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-utilities b/src/sonic-utilities index 0ae5d2d28e12..6833e6cac8ca 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 0ae5d2d28e12bb4ed94c9cdf77bb1b924fec72d0 +Subproject commit 6833e6cac8ca0879fde6f5462a994abfa685716d From d8f9f232e69f1290bdf6714e487760e9435fa809 Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Wed, 1 Nov 2023 16:32:34 +0800 Subject: [PATCH 06/10] [submodule] Update submodule sonic-linux-kernel to the latest HEAD automatically (#17056) #### Why I did it src/sonic-linux-kernel ``` * a75a3df - (HEAD -> master, origin/master, origin/HEAD) arm64: Kconfig inclusions to fix PCI hang and MTD detection (#350) (3 hours ago) [Pavan Naregundi] ``` #### How I did it #### How to verify it #### Description for the changelog --- src/sonic-linux-kernel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index 6508505bea84..a75a3dfeae77 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit 6508505bea84ed786fa72ff9d7bbb195932c66d9 +Subproject commit a75a3dfeae77556b4d62faf19b7ead29e2e48d52 From 845bb80a3c2cf9c4f2dcf580964b2629298bd111 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Thu, 2 Nov 2023 06:50:14 +0200 Subject: [PATCH 07/10] [ppi]: Enable global port late create for all Mellanox HWSKUs. (#16945) HLD: sonic-net/SONiC#1084 To improve FAST reboot dataplane downtime Signed-off-by: Nazarii Hnydyn --- .../ACS-MSN2010/sai_2010.xml | 339 ++++---- .../ACS-MSN2100/sai_2100.xml | 253 +++--- .../ACS-MSN2410/sai_2410.xml | 815 +++++++++--------- .../ACS-MSN2700/sai_2700.xml | 479 +++++----- .../sai_2700_8x50g_28x100g.xml | 487 +++++------ .../sai_2700_8x100g_40x50g_8x10g.xml | 5 +- .../sai_2700_44x50g_10x100g.xml | 4 +- .../sai_2700_48x50g_8x100g.xml | 527 +++++------ .../ACS-MSN2740/sai_2740.xml | 479 +++++----- .../ACS-MSN3420/sai_3420.xml | 7 +- .../ACS-MSN3700/sai_3700.xml | 479 +++++----- .../ACS-MSN3800/sai_3800.xml | 9 +- .../sai_3800_2x10g_100x50g_12x100g.xml | 10 +- .../sai_3800_112x50g_8x100g.xml | 7 +- .../sai_3800_24x50g_52x100g.xml | 9 +- .../sai_3800_1x10g_28x50g_49x100g.xml | 9 +- .../sai_3800_28x50g_52x100g.xml | 9 +- .../ACS-MSN4410/sai_4410.xml | 14 +- .../ACS-MSN4600/sai_4600.xml | 8 +- .../ACS-MSN4600C/sai_4600C.xml | 9 +- .../sai_4600c_100x50g_12x100g_2x10g.xml | 6 +- .../sai_4600c_112x50g_8x100g.xml | 7 +- .../sai_4600c_48x50g_40x100g.xml | 5 +- .../ACS-MSN4700/sai_4700.xml | 14 +- .../sai_4700_8x200g_8x100g_96x25g.xml | 12 +- .../sai_4700_128x100g.xml | 14 +- .../sai_4700_8x400g_48x100g.xml | 12 +- .../sai_4700_32x100g_48x200g.xml | 12 +- .../ACS-SN2201/sai_2201.xml | 9 +- .../ACS-SN4800/sai_4800.xml | 6 +- .../ACS-SN5600/sai_5600.xml | 1 - .../ACS-SN5600/sai_5600.xml | 11 +- 32 files changed, 2068 insertions(+), 1999 deletions(-) diff --git a/device/mellanox/x86_64-mlnx_msn2010-r0/ACS-MSN2010/sai_2010.xml b/device/mellanox/x86_64-mlnx_msn2010-r0/ACS-MSN2010/sai_2010.xml index 6d8e9c910419..a51aec41c71d 100644 --- a/device/mellanox/x86_64-mlnx_msn2010-r0/ACS-MSN2010/sai_2010.xml +++ b/device/mellanox/x86_64-mlnx_msn2010-r0/ACS-MSN2010/sai_2010.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 22 + + 22 - - - - 1 - 1 - 14 + + 1 - - 0 + + + + 1 + 1 + 14 - - 939524096 - - - 2 - 1 - 15 - 0 - 939524096 - - - 3 - 1 - 16 - 0 - 939524096 - - - 4 - 1 - 17 - 0 - 939524096 - - - 5 - 4 - 19 - 3 - 11534336 - - - 9 - 4 - 18 - 3 - 11534336 - - - 13 - 4 - 21 - 3 - 11534336 - - - 17 - 4 - 20 - 3 - 11534336 - - - 33 - 1 - 10 - 0 - 939524096 - - - 34 - 1 - 11 - 0 - 939524096 - - - 35 - 1 - 12 - 0 - 939524096 - - - 36 - 1 - 13 - 0 - 939524096 - - - 37 - 1 - 6 - 0 - 939524096 - - - 38 - 1 - 7 - 0 - 939524096 - - - 39 - 1 - 8 - 0 - 939524096 - - - 40 - 1 - 9 - 0 - 939524096 - - - 41 - 1 - 2 - 0 - 939524096 - - - 42 - 1 - 3 - 0 - 939524096 - - - 43 - 1 - 4 - 0 - 939524096 - - - 44 - 1 - 5 - 0 - 939524096 - - - 45 - 1 - 0 - 0 - 939524096 - - - 46 - 1 - 1 - 0 - 939524096 - - - + + 0 + + + 939524096 + + + 2 + 1 + 15 + 0 + 939524096 + + + 3 + 1 + 16 + 0 + 939524096 + + + 4 + 1 + 17 + 0 + 939524096 + + + 5 + 4 + 19 + 3 + 11534336 + + + 9 + 4 + 18 + 3 + 11534336 + + + 13 + 4 + 21 + 3 + 11534336 + + + 17 + 4 + 20 + 3 + 11534336 + + + 33 + 1 + 10 + 0 + 939524096 + + + 34 + 1 + 11 + 0 + 939524096 + + + 35 + 1 + 12 + 0 + 939524096 + + + 36 + 1 + 13 + 0 + 939524096 + + + 37 + 1 + 6 + 0 + 939524096 + + + 38 + 1 + 7 + 0 + 939524096 + + + 39 + 1 + 8 + 0 + 939524096 + + + 40 + 1 + 9 + 0 + 939524096 + + + 41 + 1 + 2 + 0 + 939524096 + + + 42 + 1 + 3 + 0 + 939524096 + + + 43 + 1 + 4 + 0 + 939524096 + + + 44 + 1 + 5 + 0 + 939524096 + + + 45 + 1 + 0 + 0 + 939524096 + + + 46 + 1 + 1 + 0 + 939524096 + + + diff --git a/device/mellanox/x86_64-mlnx_msn2100-r0/ACS-MSN2100/sai_2100.xml b/device/mellanox/x86_64-mlnx_msn2100-r0/ACS-MSN2100/sai_2100.xml index 3460f80e074c..b5fb1dd476a0 100644 --- a/device/mellanox/x86_64-mlnx_msn2100-r0/ACS-MSN2100/sai_2100.xml +++ b/device/mellanox/x86_64-mlnx_msn2100-r0/ACS-MSN2100/sai_2100.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 16 + + 16 - - - - 25 - 4 - 0 + + 1 - - 3 + + + + 25 + 4 + 0 + + + 3 - - 98368 - - - 29 - 4 - 1 - 3 - 98368 - - - 17 - 4 - 2 - 3 - 98368 - - - 21 - 4 - 3 - 3 - 98368 - - - 9 - 4 - 4 - 3 - 98368 - - - 13 - 4 - 5 - 3 - 98368 - - - 1 - 4 - 6 - 3 - 98368 - - - 5 - 4 - 7 - 3 - 98368 - - - 37 - 4 - 8 - 3 - 98368 - - - 33 - 4 - 9 - 3 - 98368 - - - 45 - 4 - 10 - 3 - 98368 - - - 41 - 4 - 11 - 3 - 98368 - - - 53 - 4 - 12 - 3 - 98368 - - - 49 - 4 - 13 - 3 - 98368 - - - 61 - 4 - 14 - 3 - 98368 - - - 57 - 4 - 15 - 3 - 98368 - + + 98368 + + + 29 + 4 + 1 + 3 + 98368 + + + 17 + 4 + 2 + 3 + 98368 + + + 21 + 4 + 3 + 3 + 98368 + + + 9 + 4 + 4 + 3 + 98368 + + + 13 + 4 + 5 + 3 + 98368 + + + 1 + 4 + 6 + 3 + 98368 + + + 5 + 4 + 7 + 3 + 98368 + + + 37 + 4 + 8 + 3 + 98368 + + + 33 + 4 + 9 + 3 + 98368 + + + 45 + 4 + 10 + 3 + 98368 + + + 41 + 4 + 11 + 3 + 98368 + + + 53 + 4 + 12 + 3 + 98368 + + + 49 + 4 + 13 + 3 + 98368 + + + 61 + 4 + 14 + 3 + 98368 + + + 57 + 4 + 15 + 3 + 98368 + - + diff --git a/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml b/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml index a4cb1df39571..9d9ce42f0f67 100644 --- a/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml +++ b/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 56 + + 56 - - - - 1 - 32 - 1 + + 1 - - 0 + + + + 1 + 32 + 1 - - 939524096 - - - 2 - 33 - 1 - 0 - 939524096 - - - 3 - 34 - 1 - 0 - 939524096 - - - 4 - 35 - 1 - 0 - 939524096 - - - 5 - 36 - 1 - 0 - 939524096 - - - 6 - 37 - 1 - 0 - 939524096 - - - 7 - 38 - 1 - 0 - 939524096 - - - 8 - 39 - 1 - 0 - 939524096 - - - 9 - 40 - 1 - 0 - 939524096 - - - 10 - 41 - 1 - 0 - 939524096 - - - 11 - 42 - 1 - 0 - 939524096 - - - 12 - 43 - 1 - 0 - 939524096 - - - 13 - 44 - 1 - 0 - 939524096 - - - 14 - 45 - 1 - 0 - 939524096 - - - 15 - 46 - 1 - 0 - 939524096 - - - 16 - 47 - 1 - 0 - 939524096 - - - 17 - 48 - 4 - 3 - 11534336 - - - 19 - 49 - 4 - 1 - 11534336 - - - 21 - 50 - 4 - 3 - 11534336 - - - 23 - 51 - 4 - 1 - 11534336 - - - 25 - 52 - 4 - 3 - 11534336 - - - 27 - 53 - 4 - 1 - 11534336 - - - 29 - 54 - 4 - 3 - 11534336 - - - 31 - 55 - 4 - 1 - 11534336 - - - 33 - 28 - 1 - 0 - 939524096 - - - 34 - 29 - 1 - 0 - 939524096 - - - 35 - 30 - 1 - 0 - 939524096 - - - 36 - 31 - 1 - 0 - 939524096 - - - 37 - 24 - 1 - 0 - 939524096 - - - 38 - 25 - 1 - 0 - 939524096 - - - 39 - 26 - 1 - 0 - 939524096 - - - 40 - 27 - 1 - 0 - 939524096 - - - 41 - 20 - 1 - 0 - 939524096 - - - 42 - 21 - 1 - 0 - 939524096 - - - 43 - 22 - 1 - 0 - 939524096 - - - 44 - 23 - 1 - 0 - 939524096 - - - 45 - 16 - 1 - 0 - 939524096 - - - 46 - 17 - 1 - 0 - 939524096 - - - 47 - 18 - 1 - 0 - 939524096 - - - 48 - 19 - 1 - 0 - 939524096 - - - 49 - 12 - 1 - 0 - 939524096 - - - 50 - 13 - 1 - 0 - 939524096 - - - 51 - 14 - 1 - 0 - 939524096 - - - 52 - 15 - 1 - 0 - 939524096 - - - 53 - 8 - 1 - 0 - 939524096 - - - 54 - 9 - 1 - 0 - 939524096 - - - 55 - 10 - 1 - 0 - 939524096 - - - 56 - 11 - 1 - 0 - 939524096 - - - 57 - 4 - 1 - 0 - 939524096 - - - 58 - 5 - 1 - 0 - 939524096 - - - 59 - 6 - 1 - 0 - 939524096 - - - 60 - 7 - 1 - 0 - 939524096 - - - 61 - 0 - 1 - 0 - 939524096 - - - 62 - 1 - 1 - 0 - 939524096 - - - 63 - 2 - 1 - 0 - 939524096 - - - 64 - 3 - 1 - 0 - 939524096 - - - + + 0 + + + 939524096 + + + 2 + 33 + 1 + 0 + 939524096 + + + 3 + 34 + 1 + 0 + 939524096 + + + 4 + 35 + 1 + 0 + 939524096 + + + 5 + 36 + 1 + 0 + 939524096 + + + 6 + 37 + 1 + 0 + 939524096 + + + 7 + 38 + 1 + 0 + 939524096 + + + 8 + 39 + 1 + 0 + 939524096 + + + 9 + 40 + 1 + 0 + 939524096 + + + 10 + 41 + 1 + 0 + 939524096 + + + 11 + 42 + 1 + 0 + 939524096 + + + 12 + 43 + 1 + 0 + 939524096 + + + 13 + 44 + 1 + 0 + 939524096 + + + 14 + 45 + 1 + 0 + 939524096 + + + 15 + 46 + 1 + 0 + 939524096 + + + 16 + 47 + 1 + 0 + 939524096 + + + 17 + 48 + 4 + 3 + 11534336 + + + 19 + 49 + 4 + 1 + 11534336 + + + 21 + 50 + 4 + 3 + 11534336 + + + 23 + 51 + 4 + 1 + 11534336 + + + 25 + 52 + 4 + 3 + 11534336 + + + 27 + 53 + 4 + 1 + 11534336 + + + 29 + 54 + 4 + 3 + 11534336 + + + 31 + 55 + 4 + 1 + 11534336 + + + 33 + 28 + 1 + 0 + 939524096 + + + 34 + 29 + 1 + 0 + 939524096 + + + 35 + 30 + 1 + 0 + 939524096 + + + 36 + 31 + 1 + 0 + 939524096 + + + 37 + 24 + 1 + 0 + 939524096 + + + 38 + 25 + 1 + 0 + 939524096 + + + 39 + 26 + 1 + 0 + 939524096 + + + 40 + 27 + 1 + 0 + 939524096 + + + 41 + 20 + 1 + 0 + 939524096 + + + 42 + 21 + 1 + 0 + 939524096 + + + 43 + 22 + 1 + 0 + 939524096 + + + 44 + 23 + 1 + 0 + 939524096 + + + 45 + 16 + 1 + 0 + 939524096 + + + 46 + 17 + 1 + 0 + 939524096 + + + 47 + 18 + 1 + 0 + 939524096 + + + 48 + 19 + 1 + 0 + 939524096 + + + 49 + 12 + 1 + 0 + 939524096 + + + 50 + 13 + 1 + 0 + 939524096 + + + 51 + 14 + 1 + 0 + 939524096 + + + 52 + 15 + 1 + 0 + 939524096 + + + 53 + 8 + 1 + 0 + 939524096 + + + 54 + 9 + 1 + 0 + 939524096 + + + 55 + 10 + 1 + 0 + 939524096 + + + 56 + 11 + 1 + 0 + 939524096 + + + 57 + 4 + 1 + 0 + 939524096 + + + 58 + 5 + 1 + 0 + 939524096 + + + 59 + 6 + 1 + 0 + 939524096 + + + 60 + 7 + 1 + 0 + 939524096 + + + 61 + 0 + 1 + 0 + 939524096 + + + 62 + 1 + 1 + 0 + 939524096 + + + 63 + 2 + 1 + 0 + 939524096 + + + 64 + 3 + 1 + 0 + 939524096 + + + diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/sai_2700.xml b/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/sai_2700.xml index fc3d46a4b057..76e8c3fbc4fd 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/sai_2700.xml +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/ACS-MSN2700/sai_2700.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 32 + + 32 - - - - 1 - 4 - 16 + + 1 - - 3 + + + + 1 + 4 + 16 - - 98368 - - - 3 - 4 - 17 - 1 - 98368 - - - 5 - 4 - 18 - 3 - 98368 - - - 7 - 4 - 19 - 1 - 98368 - - - 9 - 4 - 20 - 3 - 98368 - - - 11 - 4 - 21 - 1 - 98368 - - - 13 - 4 - 22 - 3 - 98368 - - - 15 - 4 - 23 - 1 - 98368 - - - 17 - 4 - 24 - 3 - 98368 - - - 19 - 4 - 25 - 1 - 98368 - - - 21 - 4 - 26 - 3 - 98368 - - - 23 - 4 - 27 - 1 - 98368 - - - 25 - 4 - 28 - 3 - 98368 - - - 27 - 4 - 29 - 1 - 98368 - - - 29 - 4 - 30 - 3 - 98368 - - - 31 - 4 - 31 - 1 - 98368 - - - 33 - 4 - 14 - 3 - 98368 - - - 35 - 4 - 15 - 1 - 98368 - - - 37 - 4 - 12 - 3 - 98368 - - - 39 - 4 - 13 - 1 - 98368 - - - 41 - 4 - 10 - 3 - 98368 - - - 43 - 4 - 11 - 1 - 98368 - - - 45 - 4 - 8 - 3 - 98368 - - - 47 - 4 - 9 - 1 - 98368 - - - 49 - 4 - 6 - 3 - 98368 - - - 51 - 4 - 7 - 1 - 98368 - - - 53 - 4 - 4 - 3 - 98368 - - - 55 - 4 - 5 - 1 - 98368 - - - 57 - 4 - 2 - 3 - 98368 - - - 59 - 4 - 3 - 1 - 98368 - - - 61 - 4 - 0 - 3 - 98368 - - - 63 - 4 - 1 - 1 - 98368 - - - + + 3 + + + 98368 + + + 3 + 4 + 17 + 1 + 98368 + + + 5 + 4 + 18 + 3 + 98368 + + + 7 + 4 + 19 + 1 + 98368 + + + 9 + 4 + 20 + 3 + 98368 + + + 11 + 4 + 21 + 1 + 98368 + + + 13 + 4 + 22 + 3 + 98368 + + + 15 + 4 + 23 + 1 + 98368 + + + 17 + 4 + 24 + 3 + 98368 + + + 19 + 4 + 25 + 1 + 98368 + + + 21 + 4 + 26 + 3 + 98368 + + + 23 + 4 + 27 + 1 + 98368 + + + 25 + 4 + 28 + 3 + 98368 + + + 27 + 4 + 29 + 1 + 98368 + + + 29 + 4 + 30 + 3 + 98368 + + + 31 + 4 + 31 + 1 + 98368 + + + 33 + 4 + 14 + 3 + 98368 + + + 35 + 4 + 15 + 1 + 98368 + + + 37 + 4 + 12 + 3 + 98368 + + + 39 + 4 + 13 + 1 + 98368 + + + 41 + 4 + 10 + 3 + 98368 + + + 43 + 4 + 11 + 1 + 98368 + + + 45 + 4 + 8 + 3 + 98368 + + + 47 + 4 + 9 + 1 + 98368 + + + 49 + 4 + 6 + 3 + 98368 + + + 51 + 4 + 7 + 1 + 98368 + + + 53 + 4 + 4 + 3 + 98368 + + + 55 + 4 + 5 + 1 + 98368 + + + 57 + 4 + 2 + 3 + 98368 + + + 59 + 4 + 3 + 1 + 98368 + + + 61 + 4 + 0 + 3 + 98368 + + + 63 + 4 + 1 + 1 + 98368 + + + diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-C28D8/sai_2700_8x50g_28x100g.xml b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-C28D8/sai_2700_8x50g_28x100g.xml index d7e64e106454..1568be7c2340 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-C28D8/sai_2700_8x50g_28x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-C28D8/sai_2700_8x50g_28x100g.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 32 + + 32 - - - - 1 - 4 - 16 + + 1 - - 3 + + + + 1 + 4 + 16 - - 11534336 - - - 3 - 4 - 17 - 1 - 11534336 - - - 5 - 4 - 18 - 3 - 11534336 - - - 7 - 4 - 19 - 1 - 11534336 - - - 9 - 4 - 20 - 3 - 11534336 - - - 11 - 4 - 21 - 1 - 11534336 - - - 13 - 4 - 22 - 3 - 11534336 - - - 15 - 4 - 23 - 1 - 11534336 - - - 17 - 4 - 24 - 3 - 11534336 - - - 19 - 4 - 25 - 1 - 11534336 - - - 21 - 4 - 26 - 3 - 11534336 - - - 23 - 4 - 27 - 1 - 11534336 - - - 25 - 4 - 28 - 3 - 3221487616 - 2 - - - 27 - 4 - 29 - 1 - 3221487616 - 2 - - - 29 - 4 - 30 - 3 - 3221487616 - 2 - - - 31 - 4 - 31 - 1 - 3221487616 - 2 - - - 33 - 4 - 14 - 3 - 11534336 - - - 35 - 4 - 15 - 1 - 11534336 - - - 37 - 4 - 12 - 3 - 11534336 - - - 39 - 4 - 13 - 1 - 11534336 - - - 41 - 4 - 10 - 3 - 11534336 - - - 43 - 4 - 11 - 1 - 11534336 - - - 45 - 4 - 8 - 3 - 11534336 - - - 47 - 4 - 9 - 1 - 11534336 - - - 49 - 4 - 6 - 3 - 11534336 - - - 51 - 4 - 7 - 1 - 11534336 - - - 53 - 4 - 4 - 3 - 11534336 - - - 55 - 4 - 5 - 1 - 11534336 - - - 57 - 4 - 2 - 3 - 11534336 - - - 59 - 4 - 3 - 1 - 11534336 - - - 61 - 4 - 0 - 3 - 11534336 - - - 63 - 4 - 1 - 1 - 11534336 - - - + + 3 + + + 11534336 + + + 3 + 4 + 17 + 1 + 11534336 + + + 5 + 4 + 18 + 3 + 11534336 + + + 7 + 4 + 19 + 1 + 11534336 + + + 9 + 4 + 20 + 3 + 11534336 + + + 11 + 4 + 21 + 1 + 11534336 + + + 13 + 4 + 22 + 3 + 11534336 + + + 15 + 4 + 23 + 1 + 11534336 + + + 17 + 4 + 24 + 3 + 11534336 + + + 19 + 4 + 25 + 1 + 11534336 + + + 21 + 4 + 26 + 3 + 11534336 + + + 23 + 4 + 27 + 1 + 11534336 + + + 25 + 4 + 28 + 3 + 3221487616 + 2 + + + 27 + 4 + 29 + 1 + 3221487616 + 2 + + + 29 + 4 + 30 + 3 + 3221487616 + 2 + + + 31 + 4 + 31 + 1 + 3221487616 + 2 + + + 33 + 4 + 14 + 3 + 11534336 + + + 35 + 4 + 15 + 1 + 11534336 + + + 37 + 4 + 12 + 3 + 11534336 + + + 39 + 4 + 13 + 1 + 11534336 + + + 41 + 4 + 10 + 3 + 11534336 + + + 43 + 4 + 11 + 1 + 11534336 + + + 45 + 4 + 8 + 3 + 11534336 + + + 47 + 4 + 9 + 1 + 11534336 + + + 49 + 4 + 6 + 3 + 11534336 + + + 51 + 4 + 7 + 1 + 11534336 + + + 53 + 4 + 4 + 3 + 11534336 + + + 55 + 4 + 5 + 1 + 11534336 + + + 57 + 4 + 2 + 3 + 11534336 + + + 59 + 4 + 3 + 1 + 11534336 + + + 61 + 4 + 0 + 3 + 11534336 + + + 63 + 4 + 1 + 1 + 11534336 + + + diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D40C8S8/sai_2700_8x100g_40x50g_8x10g.xml b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D40C8S8/sai_2700_8x100g_40x50g_8x10g.xml index ec4cdf11cad8..f1624e70ab7a 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D40C8S8/sai_2700_8x100g_40x50g_8x10g.xml +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D40C8S8/sai_2700_8x100g_40x50g_8x10g.xml @@ -1,6 +1,6 @@ 32 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D44C10/sai_2700_44x50g_10x100g.xml b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D44C10/sai_2700_44x50g_10x100g.xml index 27dffa864d13..566ebb999bdc 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D44C10/sai_2700_44x50g_10x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D44C10/sai_2700_44x50g_10x100g.xml @@ -15,7 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -28,6 +27,9 @@ 32 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D48C8/sai_2700_48x50g_8x100g.xml b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D48C8/sai_2700_48x50g_8x100g.xml index 44e1962fa110..0aa6e5f24451 100644 --- a/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D48C8/sai_2700_48x50g_8x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn2700-r0/Mellanox-SN2700-D48C8/sai_2700_48x50g_8x100g.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 32 + + 32 - - - - 1 - 4 - 16 + + 1 - - 3 + + + + 1 + 4 + 16 - - 3221487616 - 2 - - - 3 - 4 - 17 - 1 - 3221487616 - 2 - - - 5 - 4 - 18 - 3 - 3221487616 - 2 - - - 7 - 4 - 19 - 1 - 3221487616 - 2 - - - 9 - 4 - 20 - 3 - 3221487616 - 2 - - - 11 - 4 - 21 - 1 - 3221487616 - 2 - - - 13 - 4 - 22 - 3 - 11534336 - - - 15 - 4 - 23 - 1 - 11534336 - - - 17 - 4 - 24 - 3 - 11534336 - - - 19 - 4 - 25 - 1 - 11534336 - - - 21 - 4 - 26 - 3 - 3221487616 - 2 - - - 23 - 4 - 27 - 1 - 3221487616 - 2> - - - 25 - 4 - 28 - 3 - 3221487616 - 2 - - - 27 - 4 - 29 - 1 - 3221487616 - 2 - - - 29 - 4 - 30 - 3 - 3221487616 - 2 - - - 31 - 4 - 31 - 1 - 3221487616 - 2 - - - 33 - 4 - 14 - 3 - 3221487616 - 2 - - - 35 - 4 - 15 - 1 - 3221487616 - 2 - - - 37 - 4 - 12 - 3 - 3221487616 - 2 - - - 39 - 4 - 13 - 1 - 3221487616 - 2 - - - 41 - 4 - 10 - 3 - 3221487616 - 2 - - - 43 - 4 - 11 - 1 - 3221487616 - 2 - - - 45 - 4 - 8 - 3 - 11534336 - - - 47 - 4 - 9 - 1 - 11534336 - - - 49 - 4 - 6 - 3 - 11534336 - - - 51 - 4 - 7 - 1 - 11534336 - - - 53 - 4 - 4 - 3 - 3221487616 - 2 - - - 55 - 4 - 5 - 1 - 3221487616 - 2 - - - 57 - 4 - 2 - 3 - 3221487616 - 2 - - - 59 - 4 - 3 - 1 - 3221487616 - 2 - - - 61 - 4 - 0 - 3 - 3221487616 - 2 - - - 63 - 4 - 1 - 1 - 3221487616 - 2 - - - + + 3 + + + 3221487616 + 2 + + + 3 + 4 + 17 + 1 + 3221487616 + 2 + + + 5 + 4 + 18 + 3 + 3221487616 + 2 + + + 7 + 4 + 19 + 1 + 3221487616 + 2 + + + 9 + 4 + 20 + 3 + 3221487616 + 2 + + + 11 + 4 + 21 + 1 + 3221487616 + 2 + + + 13 + 4 + 22 + 3 + 11534336 + + + 15 + 4 + 23 + 1 + 11534336 + + + 17 + 4 + 24 + 3 + 11534336 + + + 19 + 4 + 25 + 1 + 11534336 + + + 21 + 4 + 26 + 3 + 3221487616 + 2 + + + 23 + 4 + 27 + 1 + 3221487616 + 2> + + + 25 + 4 + 28 + 3 + 3221487616 + 2 + + + 27 + 4 + 29 + 1 + 3221487616 + 2 + + + 29 + 4 + 30 + 3 + 3221487616 + 2 + + + 31 + 4 + 31 + 1 + 3221487616 + 2 + + + 33 + 4 + 14 + 3 + 3221487616 + 2 + + + 35 + 4 + 15 + 1 + 3221487616 + 2 + + + 37 + 4 + 12 + 3 + 3221487616 + 2 + + + 39 + 4 + 13 + 1 + 3221487616 + 2 + + + 41 + 4 + 10 + 3 + 3221487616 + 2 + + + 43 + 4 + 11 + 1 + 3221487616 + 2 + + + 45 + 4 + 8 + 3 + 11534336 + + + 47 + 4 + 9 + 1 + 11534336 + + + 49 + 4 + 6 + 3 + 11534336 + + + 51 + 4 + 7 + 1 + 11534336 + + + 53 + 4 + 4 + 3 + 3221487616 + 2 + + + 55 + 4 + 5 + 1 + 3221487616 + 2 + + + 57 + 4 + 2 + 3 + 3221487616 + 2 + + + 59 + 4 + 3 + 1 + 3221487616 + 2 + + + 61 + 4 + 0 + 3 + 3221487616 + 2 + + + 63 + 4 + 1 + 1 + 3221487616 + 2 + + + diff --git a/device/mellanox/x86_64-mlnx_msn2740-r0/ACS-MSN2740/sai_2740.xml b/device/mellanox/x86_64-mlnx_msn2740-r0/ACS-MSN2740/sai_2740.xml index fe584ea7a027..660235760c56 100644 --- a/device/mellanox/x86_64-mlnx_msn2740-r0/ACS-MSN2740/sai_2740.xml +++ b/device/mellanox/x86_64-mlnx_msn2740-r0/ACS-MSN2740/sai_2740.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 32 + + 32 - - - - 1 - 4 - 16 + + 1 - - 3 + + + + 1 + 4 + 16 - - 98368 - - - 3 - 4 - 17 - 1 - 98368 - - - 5 - 4 - 18 - 3 - 98368 - - - 7 - 4 - 19 - 1 - 98368 - - - 9 - 4 - 20 - 3 - 98368 - - - 11 - 4 - 21 - 1 - 98368 - - - 13 - 4 - 22 - 3 - 98368 - - - 15 - 4 - 23 - 1 - 98368 - - - 17 - 4 - 24 - 3 - 98368 - - - 19 - 4 - 25 - 1 - 98368 - - - 21 - 4 - 26 - 3 - 98368 - - - 23 - 4 - 27 - 1 - 98368 - - - 25 - 4 - 28 - 3 - 98368 - - - 27 - 4 - 29 - 1 - 98368 - - - 29 - 4 - 30 - 3 - 98368 - - - 31 - 4 - 31 - 1 - 98368 - - - 33 - 4 - 14 - 3 - 98368 - - - 35 - 4 - 15 - 1 - 98368 - - - 37 - 4 - 12 - 3 - 98368 - - - 39 - 4 - 13 - 1 - 98368 - - - 41 - 4 - 10 - 3 - 98368 - - - 43 - 4 - 11 - 1 - 98368 - - - 45 - 4 - 8 - 3 - 98368 - - - 47 - 4 - 9 - 1 - 98368 - - - 49 - 4 - 6 - 3 - 98368 - - - 51 - 4 - 7 - 1 - 98368 - - - 53 - 4 - 4 - 3 - 98368 - - - 55 - 4 - 5 - 1 - 98368 - - - 57 - 4 - 2 - 3 - 98368 - - - 59 - 4 - 3 - 1 - 98368 - - - 61 - 4 - 0 - 3 - 98368 - - - 63 - 4 - 1 - 1 - 98368 - - - + + 3 + + + 98368 + + + 3 + 4 + 17 + 1 + 98368 + + + 5 + 4 + 18 + 3 + 98368 + + + 7 + 4 + 19 + 1 + 98368 + + + 9 + 4 + 20 + 3 + 98368 + + + 11 + 4 + 21 + 1 + 98368 + + + 13 + 4 + 22 + 3 + 98368 + + + 15 + 4 + 23 + 1 + 98368 + + + 17 + 4 + 24 + 3 + 98368 + + + 19 + 4 + 25 + 1 + 98368 + + + 21 + 4 + 26 + 3 + 98368 + + + 23 + 4 + 27 + 1 + 98368 + + + 25 + 4 + 28 + 3 + 98368 + + + 27 + 4 + 29 + 1 + 98368 + + + 29 + 4 + 30 + 3 + 98368 + + + 31 + 4 + 31 + 1 + 98368 + + + 33 + 4 + 14 + 3 + 98368 + + + 35 + 4 + 15 + 1 + 98368 + + + 37 + 4 + 12 + 3 + 98368 + + + 39 + 4 + 13 + 1 + 98368 + + + 41 + 4 + 10 + 3 + 98368 + + + 43 + 4 + 11 + 1 + 98368 + + + 45 + 4 + 8 + 3 + 98368 + + + 47 + 4 + 9 + 1 + 98368 + + + 49 + 4 + 6 + 3 + 98368 + + + 51 + 4 + 7 + 1 + 98368 + + + 53 + 4 + 4 + 3 + 98368 + + + 55 + 4 + 5 + 1 + 98368 + + + 57 + 4 + 2 + 3 + 98368 + + + 59 + 4 + 3 + 1 + 98368 + + + 61 + 4 + 0 + 3 + 98368 + + + 63 + 4 + 1 + 1 + 98368 + + + diff --git a/device/mellanox/x86_64-mlnx_msn3420-r0/ACS-MSN3420/sai_3420.xml b/device/mellanox/x86_64-mlnx_msn3420-r0/ACS-MSN3420/sai_3420.xml index 73ab81a18b1a..80d52a442de9 100644 --- a/device/mellanox/x86_64-mlnx_msn3420-r0/ACS-MSN3420/sai_3420.xml +++ b/device/mellanox/x86_64-mlnx_msn3420-r0/ACS-MSN3420/sai_3420.xml @@ -1,6 +1,6 @@ 60 + + 1 + @@ -455,4 +458,4 @@ - \ No newline at end of file + diff --git a/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/sai_3700.xml b/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/sai_3700.xml index 4234a4c1d000..3023b8311ae1 100644 --- a/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/sai_3700.xml +++ b/device/mellanox/x86_64-mlnx_msn3700-r0/ACS-MSN3700/sai_3700.xml @@ -1,6 +1,6 @@ - + - - 00:02:03:04:05:00 + + 00:02:03:04:05:00 - - 1 + + 1 - - 32 + + 32 - - - - 1 - 4 - 16 + + 1 - - 3 + + + + 1 + 4 + 16 - - 1536 - - - 5 - 4 - 17 - 3 - 1536 - - - 9 - 4 - 18 - 3 - 1536 - - - 13 - 4 - 19 - 3 - 1536 - - - 17 - 4 - 20 - 3 - 1536 - - - 21 - 4 - 21 - 3 - 1536 - - - 25 - 4 - 22 - 3 - 1536 - - - 29 - 4 - 23 - 3 - 1536 - - - 33 - 4 - 14 - 3 - 1536 - - - 37 - 4 - 15 - 3 - 1536 - - - 41 - 4 - 12 - 3 - 1536 - - - 45 - 4 - 13 - 3 - 1536 - - - 49 - 4 - 10 - 3 - 1536 - - - 53 - 4 - 11 - 3 - 1536 - - - 57 - 4 - 8 - 3 - 1536 - - - 61 - 4 - 9 - 3 - 1536 - - - 65 - 4 - 30 - 3 - 1536 - - - 69 - 4 - 31 - 3 - 1536 - - - 73 - 4 - 28 - 3 - 1536 - - - 77 - 4 - 29 - 3 - 1536 - - - 81 - 4 - 26 - 3 - 1536 - - - 85 - 4 - 27 - 3 - 1536 - - - 89 - 4 - 24 - 3 - 1536 - - - 93 - 4 - 25 - 3 - 1536 - - - 97 - 4 - 0 - 3 - 1536 - - - 101 - 4 - 1 - 3 - 1536 - - - 105 - 4 - 2 - 3 - 1536 - - - 109 - 4 - 3 - 3 - 1536 - - - 113 - 4 - 4 - 3 - 1536 - - - 117 - 4 - 5 - 3 - 1536 - - - 121 - 4 - 6 - 3 - 1536 - - - 125 - 4 - 7 - 3 - 1536 - - - + + 3 + + + 1536 + + + 5 + 4 + 17 + 3 + 1536 + + + 9 + 4 + 18 + 3 + 1536 + + + 13 + 4 + 19 + 3 + 1536 + + + 17 + 4 + 20 + 3 + 1536 + + + 21 + 4 + 21 + 3 + 1536 + + + 25 + 4 + 22 + 3 + 1536 + + + 29 + 4 + 23 + 3 + 1536 + + + 33 + 4 + 14 + 3 + 1536 + + + 37 + 4 + 15 + 3 + 1536 + + + 41 + 4 + 12 + 3 + 1536 + + + 45 + 4 + 13 + 3 + 1536 + + + 49 + 4 + 10 + 3 + 1536 + + + 53 + 4 + 11 + 3 + 1536 + + + 57 + 4 + 8 + 3 + 1536 + + + 61 + 4 + 9 + 3 + 1536 + + + 65 + 4 + 30 + 3 + 1536 + + + 69 + 4 + 31 + 3 + 1536 + + + 73 + 4 + 28 + 3 + 1536 + + + 77 + 4 + 29 + 3 + 1536 + + + 81 + 4 + 26 + 3 + 1536 + + + 85 + 4 + 27 + 3 + 1536 + + + 89 + 4 + 24 + 3 + 1536 + + + 93 + 4 + 25 + 3 + 1536 + + + 97 + 4 + 0 + 3 + 1536 + + + 101 + 4 + 1 + 3 + 1536 + + + 105 + 4 + 2 + 3 + 1536 + + + 109 + 4 + 3 + 3 + 1536 + + + 113 + 4 + 4 + 3 + 1536 + + + 117 + 4 + 5 + 3 + 1536 + + + 121 + 4 + 6 + 3 + 1536 + + + 125 + 4 + 7 + 3 + 1536 + + + diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/ACS-MSN3800/sai_3800.xml b/device/mellanox/x86_64-mlnx_msn3800-r0/ACS-MSN3800/sai_3800.xml index 85d33f9da6c8..1430faaf25ba 100644 --- a/device/mellanox/x86_64-mlnx_msn3800-r0/ACS-MSN3800/sai_3800.xml +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/ACS-MSN3800/sai_3800.xml @@ -1,6 +1,6 @@ 00:02:03:04:05:00 - - 1 + + 1 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D100C12S2/sai_3800_2x10g_100x50g_12x100g.xml b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D100C12S2/sai_3800_2x10g_100x50g_12x100g.xml index b50bc30fb9a1..1713792c4791 100644 --- a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D100C12S2/sai_3800_2x10g_100x50g_12x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D100C12S2/sai_3800_2x10g_100x50g_12x100g.xml @@ -1,6 +1,6 @@ 00:02:03:04:05:00 - - 1 + + 1 64 + + 1 + @@ -534,4 +537,3 @@ - diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D112C8/sai_3800_112x50g_8x100g.xml b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D112C8/sai_3800_112x50g_8x100g.xml index 250c4269f891..d563c6db3149 100644 --- a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D112C8/sai_3800_112x50g_8x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D112C8/sai_3800_112x50g_8x100g.xml @@ -1,6 +1,6 @@ 64 + + 1 + @@ -539,4 +542,4 @@ - \ No newline at end of file + diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D24C52/sai_3800_24x50g_52x100g.xml b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D24C52/sai_3800_24x50g_52x100g.xml index 0ce4e0d8e66b..0d194e4dea1c 100644 --- a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D24C52/sai_3800_24x50g_52x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D24C52/sai_3800_24x50g_52x100g.xml @@ -1,6 +1,6 @@ 00:02:03:04:05:00 - - 1 + + 1 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C49S1/sai_3800_1x10g_28x50g_49x100g.xml b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C49S1/sai_3800_1x10g_28x50g_49x100g.xml index ed308a83aabb..c914d21bf53f 100644 --- a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C49S1/sai_3800_1x10g_28x50g_49x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C49S1/sai_3800_1x10g_28x50g_49x100g.xml @@ -1,6 +1,6 @@ 00:02:03:04:05:00 - - 1 + + 1 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C50/sai_3800_28x50g_52x100g.xml b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C50/sai_3800_28x50g_52x100g.xml index 0ce4e0d8e66b..0d194e4dea1c 100644 --- a/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C50/sai_3800_28x50g_52x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn3800-r0/Mellanox-SN3800-D28C50/sai_3800_28x50g_52x100g.xml @@ -1,6 +1,6 @@ 00:02:03:04:05:00 - - 1 + + 1 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn4410-r0/ACS-MSN4410/sai_4410.xml b/device/mellanox/x86_64-mlnx_msn4410-r0/ACS-MSN4410/sai_4410.xml index cb721bd52c22..b1ba9ef51b9b 100644 --- a/device/mellanox/x86_64-mlnx_msn4410-r0/ACS-MSN4410/sai_4410.xml +++ b/device/mellanox/x86_64-mlnx_msn4410-r0/ACS-MSN4410/sai_4410.xml @@ -1,6 +1,6 @@ 32 + + 1 + 1 8 17 + + 3 + + 1536 @@ -215,11 +222,7 @@ 105 8 0 - - 3 - - 1536 @@ -260,4 +263,3 @@ - diff --git a/device/mellanox/x86_64-mlnx_msn4600-r0/ACS-MSN4600/sai_4600.xml b/device/mellanox/x86_64-mlnx_msn4600-r0/ACS-MSN4600/sai_4600.xml index a16f49cb317d..d70e4583e54d 100644 --- a/device/mellanox/x86_64-mlnx_msn4600-r0/ACS-MSN4600/sai_4600.xml +++ b/device/mellanox/x86_64-mlnx_msn4600-r0/ACS-MSN4600/sai_4600.xml @@ -1,6 +1,6 @@ 1 - + 64 + + 1 + @@ -484,4 +487,3 @@ - diff --git a/device/mellanox/x86_64-mlnx_msn4600c-r0/ACS-MSN4600C/sai_4600C.xml b/device/mellanox/x86_64-mlnx_msn4600c-r0/ACS-MSN4600C/sai_4600C.xml index 88defea78508..a2c95bb8a73e 100644 --- a/device/mellanox/x86_64-mlnx_msn4600c-r0/ACS-MSN4600C/sai_4600C.xml +++ b/device/mellanox/x86_64-mlnx_msn4600c-r0/ACS-MSN4600C/sai_4600C.xml @@ -1,6 +1,6 @@ 1 - + 64 + + 1 + @@ -483,4 +486,4 @@ - \ No newline at end of file + diff --git a/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D100C12S2/sai_4600c_100x50g_12x100g_2x10g.xml b/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D100C12S2/sai_4600c_100x50g_12x100g_2x10g.xml index fe91dc678e77..6aaaad56c79d 100644 --- a/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D100C12S2/sai_4600c_100x50g_12x100g_2x10g.xml +++ b/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D100C12S2/sai_4600c_100x50g_12x100g_2x10g.xml @@ -1,5 +1,5 @@ - @@ -27,6 +26,9 @@ 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D112C8/sai_4600c_112x50g_8x100g.xml b/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D112C8/sai_4600c_112x50g_8x100g.xml index b5aece3e266e..8bbd321e389f 100644 --- a/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D112C8/sai_4600c_112x50g_8x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D112C8/sai_4600c_112x50g_8x100g.xml @@ -1,6 +1,6 @@ 1 - + 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D48C40/sai_4600c_48x50g_40x100g.xml b/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D48C40/sai_4600c_48x50g_40x100g.xml index 51d741cd5873..3666f268958d 100644 --- a/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D48C40/sai_4600c_48x50g_40x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn4600c-r0/Mellanox-SN4600C-D48C40/sai_4600c_48x50g_40x100g.xml @@ -1,6 +1,6 @@ 64 + + 1 + diff --git a/device/mellanox/x86_64-mlnx_msn4700-r0/ACS-MSN4700/sai_4700.xml b/device/mellanox/x86_64-mlnx_msn4700-r0/ACS-MSN4700/sai_4700.xml index 83fc07b0c28b..f136bfd15917 100644 --- a/device/mellanox/x86_64-mlnx_msn4700-r0/ACS-MSN4700/sai_4700.xml +++ b/device/mellanox/x86_64-mlnx_msn4700-r0/ACS-MSN4700/sai_4700.xml @@ -1,6 +1,6 @@ 32 + + 1 + 1 8 17 + + 3 + + 1536 @@ -215,11 +222,7 @@ 105 8 0 - - 3 - - 1536 @@ -260,4 +263,3 @@ - diff --git a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-A96C8V8/sai_4700_8x200g_8x100g_96x25g.xml b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-A96C8V8/sai_4700_8x200g_8x100g_96x25g.xml index a0f0d64be416..efe7350fef9a 100644 --- a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-A96C8V8/sai_4700_8x200g_8x100g_96x25g.xml +++ b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-A96C8V8/sai_4700_8x200g_8x100g_96x25g.xml @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -27,13 +26,20 @@ 32 + + 1 + 1 4 17 + + 3 + + 100 4 @@ -241,11 +247,7 @@ 105 4 0 - - 3 - - 100 4 diff --git a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-C128/sai_4700_128x100g.xml b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-C128/sai_4700_128x100g.xml index 2575b49f3fa0..479b1641ffda 100644 --- a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-C128/sai_4700_128x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-C128/sai_4700_128x100g.xml @@ -1,5 +1,5 @@ - @@ -27,13 +26,20 @@ 32 + + 1 + 1 8 17 + + 3 + + 1536 4 @@ -241,11 +247,7 @@ 105 8 0 - - 3 - - 1536 4 diff --git a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-O8C48/sai_4700_8x400g_48x100g.xml b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-O8C48/sai_4700_8x400g_48x100g.xml index 3791aee76a76..f4ce7f1478e9 100644 --- a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-O8C48/sai_4700_8x400g_48x100g.xml +++ b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-O8C48/sai_4700_8x400g_48x100g.xml @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -27,13 +26,20 @@ 32 + + 1 + 1 8 17 + + 0 + + 32768 1 @@ -241,11 +247,7 @@ 105 8 0 - - 1 - - 1536 2 diff --git a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-V48C32/sai_4700_32x100g_48x200g.xml b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-V48C32/sai_4700_32x100g_48x200g.xml index 1a9b852f1ffd..ebb80e63c8f9 100644 --- a/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-V48C32/sai_4700_32x100g_48x200g.xml +++ b/device/mellanox/x86_64-mlnx_msn4700-r0/Mellanox-SN4700-V48C32/sai_4700_32x100g_48x200g.xml @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - @@ -27,13 +26,20 @@ 32 + + 1 + 1 8 17 + + 1 + + 4096 2 @@ -241,11 +247,7 @@ 105 8 0 - - 1 - - 4096 2 diff --git a/device/mellanox/x86_64-nvidia_sn2201-r0/ACS-SN2201/sai_2201.xml b/device/mellanox/x86_64-nvidia_sn2201-r0/ACS-SN2201/sai_2201.xml index 8c57d2f20b6e..1fe351c95abf 100644 --- a/device/mellanox/x86_64-nvidia_sn2201-r0/ACS-SN2201/sai_2201.xml +++ b/device/mellanox/x86_64-nvidia_sn2201-r0/ACS-SN2201/sai_2201.xml @@ -1,6 +1,6 @@ - @@ -28,14 +27,19 @@ 52 + + 1 + 61 1 0 + 0 + 131072 @@ -399,4 +403,3 @@ - diff --git a/device/mellanox/x86_64-nvidia_sn4800-r0/ACS-SN4800/sai_4800.xml b/device/mellanox/x86_64-nvidia_sn4800-r0/ACS-SN4800/sai_4800.xml index 3ac8606ac2f0..ad3e29c1a2ff 100644 --- a/device/mellanox/x86_64-nvidia_sn4800-r0/ACS-SN4800/sai_4800.xml +++ b/device/mellanox/x86_64-nvidia_sn4800-r0/ACS-SN4800/sai_4800.xml @@ -1,6 +1,6 @@ 0 + + 1 + - diff --git a/device/mellanox/x86_64-nvidia_sn5600-r0/ACS-SN5600/sai_5600.xml b/device/mellanox/x86_64-nvidia_sn5600-r0/ACS-SN5600/sai_5600.xml index bbfe12c0e8bb..8eed10b5d3b8 100644 --- a/device/mellanox/x86_64-nvidia_sn5600-r0/ACS-SN5600/sai_5600.xml +++ b/device/mellanox/x86_64-nvidia_sn5600-r0/ACS-SN5600/sai_5600.xml @@ -494,4 +494,3 @@ - diff --git a/device/mellanox/x86_64-nvidia_sn5600_simx-r0/ACS-SN5600/sai_5600.xml b/device/mellanox/x86_64-nvidia_sn5600_simx-r0/ACS-SN5600/sai_5600.xml index e4548ffe2506..ed83db0ac465 100644 --- a/device/mellanox/x86_64-nvidia_sn5600_simx-r0/ACS-SN5600/sai_5600.xml +++ b/device/mellanox/x86_64-nvidia_sn5600_simx-r0/ACS-SN5600/sai_5600.xml @@ -1,6 +1,6 @@ 3 - - 1536 @@ -450,11 +446,7 @@ 233 8 14 - - 3 - - 1536 @@ -502,4 +494,3 @@ - From c85c12bc75accecff1a4827de4063af4e2fba8a1 Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:32:43 +0800 Subject: [PATCH 08/10] [submodule] Update submodule sonic-swss-common to the latest HEAD automatically (#17068) #### Why I did it src/sonic-swss-common ``` * a57cf9e - (HEAD -> master, origin/master, origin/HEAD) Add batch support in ZmqProducerStateTable. (#803) (10 hours ago) [mint570] ``` #### How I did it #### How to verify it #### Description for the changelog --- src/sonic-swss-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-swss-common b/src/sonic-swss-common index 1c185029532e..a57cf9ef1d27 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit 1c185029532e350c32a79ab2f7d7f007ccf58ef8 +Subproject commit a57cf9ef1d273d52efa5f928442c15c32bcdfc0e From 274d320443bba3b0294e34f26d811118b9d4f602 Mon Sep 17 00:00:00 2001 From: Yaqiang Zhu Date: Thu, 2 Nov 2023 23:09:01 +0800 Subject: [PATCH 09/10] [dhcp_server] Add dhcprelayd for dhcp_server feature (#16947) Add support in dhcp_relay container for dhcp_server_ipv4 feature. HLD: sonic-net/SONiC#1282 --- dockers/docker-dhcp-relay/Dockerfile.j2 | 20 ++ .../cli-plugin-tests/mock_config.py | 40 ++++ .../test_config_dhcp_relay.py | 30 +++ .../cli-plugin-tests/test_show_dhcp_relay.py | 54 ++++- .../cli/config/plugins/dhcp_relay.py | 17 ++ .../cli/show/plugins/show_dhcp_relay.py | 34 ++- .../docker-dhcp-relay/dhcp-relay.programs.j2 | 6 +- .../docker-dhcp-relay.supervisord.conf.j2 | 19 +- .../port-name-alias-map.txt.j2 | 3 + dockers/docker-dhcp-server/supervisord.conf | 2 +- rules/docker-dhcp-relay.mk | 3 + .../dhcp-relay-enable-dhcp-server-sample.json | 7 + .../tests/dhcp-relay-sample.json | 5 + ...-relay-enable-dhcp-server.supervisord.conf | 1 + ...r-dhcp-relay-no-ip-helper.supervisord.conf | 1 - .../py2/docker-dhcp-relay.supervisord.conf | 1 - ...-relay-enable-dhcp-server.supervisord.conf | 64 +++++ ...r-dhcp-relay-no-ip-helper.supervisord.conf | 1 - .../py3/docker-dhcp-relay.supervisord.conf | 1 - src/sonic-config-engine/tests/test_j2files.py | 27 ++- .../dhcp_server/common/__init__.py | 0 .../dhcp_server/common/dhcp_db_monitor.py | 131 +++++++++++ .../{dhcp_server_utils.py => common/utils.py} | 10 + .../dhcp_server/dhcprelayd/dhcprelayd.py | 191 +++++++++++++++ .../{ => dhcpservd}/dhcp_cfggen.py | 3 +- .../dhcp_server/{ => dhcpservd}/dhcp_lease.py | 7 +- .../dhcp_server/{ => dhcpservd}/dhcpservd.py | 26 ++- src/sonic-dhcp-server/setup.py | 22 +- src/sonic-dhcp-server/tests/common_utils.py | 75 ++++++ src/sonic-dhcp-server/tests/conftest.py | 21 +- .../tests/test_data/kea-lease.csv | 3 +- .../tests/test_data/mock_config_db.json | 15 ++ .../tests/test_dhcp_cfggen.py | 5 +- .../tests/test_dhcp_db_monitor.py | 219 ++++++++++++++++++ .../tests/test_dhcp_lease.py | 35 ++- .../tests/test_dhcprelayd.py | 129 +++++++++++ src/sonic-dhcp-server/tests/test_dhcpservd.py | 61 +++-- ...est_dhcp_server_utils.py => test_utils.py} | 14 +- 38 files changed, 1219 insertions(+), 84 deletions(-) create mode 100644 src/sonic-config-engine/tests/dhcp-relay-enable-dhcp-server-sample.json create mode 120000 src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-enable-dhcp-server.supervisord.conf create mode 100644 src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf create mode 100644 src/sonic-dhcp-server/dhcp_server/common/__init__.py create mode 100644 src/sonic-dhcp-server/dhcp_server/common/dhcp_db_monitor.py rename src/sonic-dhcp-server/dhcp_server/{dhcp_server_utils.py => common/utils.py} (94%) create mode 100644 src/sonic-dhcp-server/dhcp_server/dhcprelayd/dhcprelayd.py rename src/sonic-dhcp-server/dhcp_server/{ => dhcpservd}/dhcp_cfggen.py (99%) rename src/sonic-dhcp-server/dhcp_server/{ => dhcpservd}/dhcp_lease.py (95%) rename src/sonic-dhcp-server/dhcp_server/{ => dhcpservd}/dhcpservd.py (64%) create mode 100644 src/sonic-dhcp-server/tests/test_dhcp_db_monitor.py create mode 100644 src/sonic-dhcp-server/tests/test_dhcprelayd.py rename src/sonic-dhcp-server/tests/{test_dhcp_server_utils.py => test_utils.py} (86%) diff --git a/dockers/docker-dhcp-relay/Dockerfile.j2 b/dockers/docker-dhcp-relay/Dockerfile.j2 index 7a8b11222985..ddcc23819bf5 100644 --- a/dockers/docker-dhcp-relay/Dockerfile.j2 +++ b/dockers/docker-dhcp-relay/Dockerfile.j2 @@ -13,6 +13,14 @@ ENV IMAGE_VERSION=$image_version # Update apt's cache of available packages RUN apt-get update +RUN apt-get install -y libjsoncpp-dev {%- if INCLUDE_DHCP_SERVER == "y" %}\ + python3-dev \ + build-essential{%- endif %} + +{% if INCLUDE_DHCP_SERVER == "y" -%} +RUN pip3 install psutil +{%- endif %} + RUN apt-get install -y libjsoncpp-dev {% if docker_dhcp_relay_debs.strip() -%} @@ -23,7 +31,19 @@ RUN apt-get install -y libjsoncpp-dev {{ install_debian_packages(docker_dhcp_relay_debs.split(' ')) }} {%- endif %} +{% if docker_dhcp_relay_whls.strip() %} +# Copy locally-built Python wheel dependencies +{{ copy_files("python-wheels/", docker_dhcp_relay_whls.split(' '), "/python-wheels/") }} + +# Install locally-built Python wheel dependencies +{{ install_python_wheels(docker_dhcp_relay_whls.split(' ')) }} +{% endif %} + # Clean up +{% if INCLUDE_DHCP_SERVER == "y" -%} +RUN apt-get remove -y build-essential \ + python3-dev +{%- endif %} RUN apt-get clean -y && \ apt-get autoclean -y && \ apt-get autoremove -y && \ diff --git a/dockers/docker-dhcp-relay/cli-plugin-tests/mock_config.py b/dockers/docker-dhcp-relay/cli-plugin-tests/mock_config.py index 1549e1937e09..28370fd99f52 100644 --- a/dockers/docker-dhcp-relay/cli-plugin-tests/mock_config.py +++ b/dockers/docker-dhcp-relay/cli-plugin-tests/mock_config.py @@ -45,6 +45,46 @@ } } } + ], + [ + "ipv4_with_disabled_dhcp_server_with_header", + { + "config_db": { + "VLAN": { + "Vlan1000": { + "dhcp_servers": [ + "192.0.0.1", + "192.0.0.2" + ] + } + }, + "FEATURE": { + "dhcp_server": { + "state": "disabled" + } + } + } + } + ], + [ + "ipv4_with_enabled_dhcp_server_with_header", + { + "config_db": { + "VLAN": { + "Vlan1000": { + "dhcp_servers": [ + "192.0.0.1", + "192.0.0.2" + ] + } + }, + "FEATURE": { + "dhcp_server": { + "state": "enabled" + } + } + } + } ] ] diff --git a/dockers/docker-dhcp-relay/cli-plugin-tests/test_config_dhcp_relay.py b/dockers/docker-dhcp-relay/cli-plugin-tests/test_config_dhcp_relay.py index a42d5cce7a8a..295f38ab2a0d 100644 --- a/dockers/docker-dhcp-relay/cli-plugin-tests/test_config_dhcp_relay.py +++ b/dockers/docker-dhcp-relay/cli-plugin-tests/test_config_dhcp_relay.py @@ -224,6 +224,36 @@ def test_config_add_del_dhcp_relay(self, mock_cfgdb, ip_version): db.cfgdb.set_entry.assert_called_once_with(config_db_table, "Vlan1000", expected_dhcp_relay_del_config_db_output[ip_version]) + def test_config_add_del_dhcp_relay_with_enable_dhcp_server(self, mock_cfgdb): + runner = CliRunner() + db = Db() + db.cfgdb = mock_cfgdb + ip_version = "ipv4" + test_ip = IP_VER_TEST_PARAM_MAP[ip_version]["ips"][0] + + with mock.patch("utilities_common.cli.run_command"), \ + mock.patch.object(dhcp_relay, "is_dhcp_server_enabled", return_value=True): + # add new dhcp relay + result = runner.invoke(dhcp_relay.dhcp_relay.commands[ip_version] + .commands[IP_VER_TEST_PARAM_MAP[ip_version]["command"]] + .commands["add"], ["1000", test_ip], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert "Cannot change ipv4 dhcp_relay configuration when dhcp_server feature is enabled" in result.output + + db.cfgdb.set_entry.reset_mock() + # del dhcp relay + with mock.patch("utilities_common.cli.run_command"), \ + mock.patch.object(dhcp_relay, "is_dhcp_server_enabled", return_value=True): + result = runner.invoke(dhcp_relay.dhcp_relay.commands[ip_version] + .commands[IP_VER_TEST_PARAM_MAP[ip_version]["command"]] + .commands["del"], ["1000", test_ip], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert "Cannot change ipv4 dhcp_relay configuration when dhcp_server feature is enabled" in result.output + def test_config_add_del_multiple_dhcp_relay(self, mock_cfgdb, ip_version): runner = CliRunner() db = Db() diff --git a/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp_relay.py b/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp_relay.py index de679972665f..387e052c143a 100644 --- a/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp_relay.py +++ b/dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp_relay.py @@ -1,5 +1,6 @@ import pytest import sys +import click import os sys.path.append('../cli/show/plugins/') import show_dhcp_relay as show @@ -35,6 +36,14 @@ +-------------+----------------------+ """ +expected_ipv4_table_with_enabled_dhcp_server_with_header = """\ ++-------------+----------------------+ +| Interface | DHCP Relay Address | ++=============+======================+ +| Vlan1000 | N/A | ++-------------+----------------------+ +""" + expected_ipv6_table_without_header = """\ -------- ------------ Vlan1000 fc02:2000::1 @@ -86,12 +95,18 @@ def test_plugin_registration(): assert 'DHCP Helper Address' in dict(vlan.VlanBrief.COLUMNS) -def test_dhcp_relay_column_output(): +@pytest.mark.parametrize("feature_table", [{}, {"dhcp_server": {"state": "disabled"}}, + {"dhcp_server": {"state": "enabled"}}, {"dhcp_server": {}}]) +def test_dhcp_relay_column_output(feature_table): ctx = ( ({'Vlan1001': {'dhcp_servers': ['192.0.0.1', '192.168.0.2']}}, {}, {}), - (), + (MockDb({"FEATURE": feature_table})), ) - assert show.get_dhcp_helper_address(ctx, 'Vlan1001') == '192.0.0.1\n192.168.0.2' + if "dhcp_server" in feature_table and "state" in feature_table["dhcp_server"] and \ + feature_table["dhcp_server"]["state"] == "enabled": + assert show.get_dhcp_helper_address(ctx, 'Vlan1001') == 'N/A' + else: + assert show.get_dhcp_helper_address(ctx, 'Vlan1001') == '192.0.0.1\n192.168.0.2' @parameterized.expand(COMMON_TEST_DATA) @@ -103,7 +118,7 @@ def test_show_dhcp_relay(test_name, test_data, fs): config_db = MockConfigDb() ip_version = "ipv4" if "ipv4" in test_name else "ipv6" table = config_db.get_table(IP_VER_TEST_PARAM_MAP[ip_version]["table"]) - if test_name == "ipv4_with_header": + if test_name in ["ipv4_with_header", "ipv4_with_disabled_dhcp_server_with_header"]: result = show.get_dhcp_relay_data_with_header(table, IP_VER_TEST_PARAM_MAP[ip_version]["entry"]) expected_output = expected_ipv4_table_with_header elif test_name == "ipv6_with_header": @@ -112,6 +127,9 @@ def test_show_dhcp_relay(test_name, test_data, fs): elif test_name == "ipv6_without_header": result = show.get_data(table, "Vlan1000") expected_output = expected_ipv6_table_without_header + elif test_name == "ipv4_with_enabled_dhcp_server_with_header": + result = show.get_dhcp_relay_data_with_header(table, IP_VER_TEST_PARAM_MAP[ip_version]["entry"], True) + expected_output = expected_ipv4_table_with_enabled_dhcp_server_with_header assert result == expected_output @@ -153,3 +171,31 @@ def test_show_multi_dhcp_relay(test_name, test_data, fs): else: expected_output = expected_ipv6_table_multi_with_header assert result == expected_output + + +def test_show_dhcp_relay_ipv4_counter_with_enabled_dhcp_server(): + with mock.patch.object(show, "is_dhcp_server_enabled", return_value=True), \ + mock.patch.object(swsscommon.ConfigDBConnector, "connect", return_value=None), \ + mock.patch.object(swsscommon.ConfigDBConnector, "get_table", return_value=None), \ + mock.patch.object(click, "echo", return_value=None) as mock_echo: + show.ipv4_counters("Etherner1") + expected_param = "Unsupport to check dhcp_relay ipv4 counter when dhcp_server feature is enabled" + mock_echo.assert_called_once_with(expected_param) + + +@pytest.mark.parametrize("enable_dhcp_server", [True, False]) +def test_is_dhcp_server_enabled(enable_dhcp_server): + result = show.is_dhcp_server_enabled({"dhcp_server": {"state": "enabled" if enable_dhcp_server else "disabled"}}) + assert result == enable_dhcp_server + + +class MockDb(object): + class MockCfgDb(object): + def __init__(self, mock_cfgdb): + self.mock_cfgdb = mock_cfgdb + + def get_table(self, table_name): + return self.mock_cfgdb.get(table_name, {}) + + def __init__(self, mock_cfgdb): + self.cfgdb = self.MockCfgDb(mock_cfgdb) diff --git a/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py b/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py index 1423a8580ae9..b4cecf13b71f 100644 --- a/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py +++ b/dockers/docker-dhcp-relay/cli/config/plugins/dhcp_relay.py @@ -116,6 +116,11 @@ def del_dhcp_relay(vid, dhcp_relay_ips, db, ip_version): ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) +def is_dhcp_server_enabled(db): + dhcp_server_feature_entry = db.cfgdb.get_entry("FEATURE", "dhcp_server") + return "state" in dhcp_server_feature_entry and dhcp_server_feature_entry["state"] == "enabled" + + @click.group(cls=clicommon.AbbreviationGroup, name="dhcp_relay") def dhcp_relay(): """config DHCP_Relay information""" @@ -163,6 +168,9 @@ def dhcp_relay_ipv4_helper(): @click.argument("dhcp_relay_helpers", nargs=-1, required=True) @clicommon.pass_db def add_dhcp_relay_ipv4_helper(db, vid, dhcp_relay_helpers): + if is_dhcp_server_enabled(db): + click.echo("Cannot change ipv4 dhcp_relay configuration when dhcp_server feature is enabled") + return add_dhcp_relay(vid, dhcp_relay_helpers, db, IPV4) @@ -171,6 +179,9 @@ def add_dhcp_relay_ipv4_helper(db, vid, dhcp_relay_helpers): @click.argument("dhcp_relay_helpers", nargs=-1, required=True) @clicommon.pass_db def del_dhcp_relay_ipv4_helper(db, vid, dhcp_relay_helpers): + if is_dhcp_server_enabled(db): + click.echo("Cannot change ipv4 dhcp_relay configuration when dhcp_server feature is enabled") + return del_dhcp_relay(vid, dhcp_relay_helpers, db, IPV4) @@ -207,6 +218,9 @@ def add_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ips): click.echo("{} is already a DHCP relay destination for {}".format(ip_addr, vlan_name)) continue if clicommon.ipaddress_type(ip_addr) == 4: + if is_dhcp_server_enabled(db): + click.echo("Cannot change dhcp_relay configuration when dhcp_server feature is enabled") + return dhcp_servers.append(ip_addr) else: dhcpv6_servers.append(ip_addr) @@ -253,6 +267,9 @@ def del_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ips): if (ip_addr not in dhcp_servers) and (ip_addr not in dhcpv6_servers): ctx.fail("{} is not a DHCP relay destination for {}".format(ip_addr, vlan_name)) if clicommon.ipaddress_type(ip_addr) == 4: + if is_dhcp_server_enabled(db): + click.echo("Cannot change dhcp_relay configuration when dhcp_server feature is enabled") + return dhcp_servers.remove(ip_addr) else: dhcpv6_servers.remove(ip_addr) diff --git a/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py b/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py index 578f687f9c22..7f99102f9917 100644 --- a/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py +++ b/dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py @@ -32,13 +32,15 @@ def get_dhcp_helper_address(ctx, vlan): - cfg, _ = ctx + cfg, db = ctx vlan_dhcp_helper_data, _, _ = cfg vlan_config = vlan_dhcp_helper_data.get(vlan) if not vlan_config: return "" - dhcp_helpers = vlan_config.get('dhcp_servers', []) + feature_data = db.cfgdb.get_table("FEATURE") + dhcp_server_enabled = is_dhcp_server_enabled(feature_data) + dhcp_helpers = ["N/A"] if dhcp_server_enabled else vlan_config.get('dhcp_servers', []) return '\n'.join(natsorted(dhcp_helpers)) @@ -96,6 +98,11 @@ def dhcp4relay_counters(): def ipv4_counters(interface): + config_db.connect() + feature_tbl = config_db.get_table("FEATURE") + if is_dhcp_server_enabled(feature_tbl): + click.echo("Unsupport to check dhcp_relay ipv4 counter when dhcp_server feature is enabled") + return counter = DHCPv4_Counter() counter_intf = counter.get_interface() @@ -193,7 +200,7 @@ def dhcp_relay_helper(): pass -def get_dhcp_relay_data_with_header(table_data, entry_name): +def get_dhcp_relay_data_with_header(table_data, entry_name, dhcp_server_enabled=False): vlan_relay = {} vlans = table_data.keys() for vlan in vlans: @@ -203,8 +210,11 @@ def get_dhcp_relay_data_with_header(table_data, entry_name): continue vlan_relay[vlan] = [] - for address in dhcp_relay_data: - vlan_relay[vlan].append(address) + if dhcp_server_enabled: + vlan_relay[vlan].append("N/A") + else: + for address in dhcp_relay_data: + vlan_relay[vlan].append(address) dhcp_relay_vlan_keys = vlan_relay.keys() relay_address_list = ["\n".join(vlan_relay[key]) for key in dhcp_relay_vlan_keys] @@ -212,6 +222,13 @@ def get_dhcp_relay_data_with_header(table_data, entry_name): return tabulate(data, tablefmt='grid', stralign='right', headers='keys') + '\n' +def is_dhcp_server_enabled(feature_tbl): + if feature_tbl is not None and "dhcp_server" in feature_tbl and "state" in feature_tbl["dhcp_server"] and \ + feature_tbl["dhcp_server"]["state"] == "enabled": + return True + return False + + def get_dhcp_relay(table_name, entry_name, with_header): if config_db is None: return @@ -221,8 +238,13 @@ def get_dhcp_relay(table_name, entry_name, with_header): if table_data is None: return + dhcp_server_enabled = False + if table_name == VLAN: + feature_tbl = config_db.get_table("FEATURE") + dhcp_server_enabled = is_dhcp_server_enabled(feature_tbl) + if with_header: - output = get_dhcp_relay_data_with_header(table_data, entry_name) + output = get_dhcp_relay_data_with_header(table_data, entry_name, dhcp_server_enabled) print(output) else: vlans = config_db.get_keys(table_name) diff --git a/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 b/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 index d539d895a5bb..b1295a803be8 100644 --- a/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 +++ b/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 @@ -2,9 +2,13 @@ programs= {%- set relay_for_ipv6 = { 'flag': False } %} {%- set add_preceding_comma = { 'flag': False } %} +{% if dhcp_server_ipv4_enabled %} +{% set _dummy = add_preceding_comma.update({'flag': True}) %} +dhcprelayd +{%- endif %} {% for vlan_name in VLAN_INTERFACE %} {# Append DHCPv4 agents #} -{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %} +{% if not dhcp_server_ipv4_enabled and VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %} {% if add_preceding_comma.flag %},{% endif %} {% set _dummy = add_preceding_comma.update({'flag': True}) %} isc-dhcpv4-relay-{{ vlan_name }} diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 index ddd93bb28644..6868fa566d9b 100644 --- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -39,6 +39,10 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=rsyslogd:running +{% set dhcp_server_ipv4_enabled = False %} +{% if FEATURE and 'dhcp_server' in FEATURE and 'state' in FEATURE['dhcp_server'] and FEATURE['dhcp_server']['state'] == 'enabled' %} +{% set dhcp_server_ipv4_enabled = True %} +{% endif %} {# If our configuration has VLANs... #} {% if VLAN_INTERFACE %} {# Count how many VLANs require a DHCP relay agent... #} @@ -56,15 +60,28 @@ dependent_startup_wait_for=rsyslogd:running {% if ipv4_num_relays.count > 0 or ipv6_num_relays.count > 0 %} {% include 'dhcp-relay.programs.j2' %} - {# Create a program entry for each DHCP relay agent instance #} {% set relay_for_ipv4 = { 'flag': False } %} {% set relay_for_ipv6 = { 'flag': False } %} +{% if not dhcp_server_ipv4_enabled %} {% for vlan_name in VLAN_INTERFACE %} {% include 'dhcpv4-relay.agents.j2' %} {% endfor %} +{% endif %} {% include 'dhcpv6-relay.agents.j2' %} +{% if not dhcp_server_ipv4_enabled %} {% include 'dhcp-relay.monitors.j2' %} +{% else %} +[program:dhcprelayd] +command=/usr/local/bin/dhcprelayd +priority=3 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=start:exited {% endif %} {% endif %} +{% endif %} \ No newline at end of file diff --git a/dockers/docker-dhcp-server/port-name-alias-map.txt.j2 b/dockers/docker-dhcp-server/port-name-alias-map.txt.j2 index b2290a9ffbf2..efafe4d5bcb6 100644 --- a/dockers/docker-dhcp-server/port-name-alias-map.txt.j2 +++ b/dockers/docker-dhcp-server/port-name-alias-map.txt.j2 @@ -3,3 +3,6 @@ {% for port, config in PORT.items() %} {{- port }} {% if "alias" in config %}{{ config["alias"] }}{% else %}{{ port }}{% endif %} {{- "\n" -}} {% endfor -%} +{% for pc, config in PORTCHANNEL.items() %} + {{- pc }} {{ pc }} {{- "\n" -}} +{% endfor -%} diff --git a/dockers/docker-dhcp-server/supervisord.conf b/dockers/docker-dhcp-server/supervisord.conf index ea958b9e7cfd..73f454d7c62d 100644 --- a/dockers/docker-dhcp-server/supervisord.conf +++ b/dockers/docker-dhcp-server/supervisord.conf @@ -60,4 +60,4 @@ autorestart=false stdout_logfile=syslog stderr_logfile=syslog dependent_startup=true -dependent_startup_wait_for=start:exited +dependent_startup_wait_for=dhcpservd:running diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk index 701dcc7024e0..6e2e5d5434b9 100644 --- a/rules/docker-dhcp-relay.mk +++ b/rules/docker-dhcp-relay.mk @@ -17,6 +17,9 @@ $(DOCKER_DHCP_RELAY)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_BULLSEYE) $(DOCKER_DHCP_RELAY)_INSTALL_PYTHON_WHEELS = $(SONIC_UTILITIES_PY3) $(DOCKER_DHCP_RELAY)_INSTALL_DEBS = $(PYTHON3_SWSSCOMMON) +ifeq ($(INCLUDE_DHCP_SERVER), y) +$(DOCKER_DHCP_RELAY)_PYTHON_WHEELS += $(SONIC_DHCP_SERVER_PY3) +endif $(DOCKER_DHCP_RELAY)_VERSION = 1.0.0 $(DOCKER_DHCP_RELAY)_PACKAGE_NAME = dhcp-relay diff --git a/src/sonic-config-engine/tests/dhcp-relay-enable-dhcp-server-sample.json b/src/sonic-config-engine/tests/dhcp-relay-enable-dhcp-server-sample.json new file mode 100644 index 000000000000..c74b0dec3627 --- /dev/null +++ b/src/sonic-config-engine/tests/dhcp-relay-enable-dhcp-server-sample.json @@ -0,0 +1,7 @@ +{ + "FEATURE": { + "dhcp_server": { + "state": "enabled" + } + } +} diff --git a/src/sonic-config-engine/tests/dhcp-relay-sample.json b/src/sonic-config-engine/tests/dhcp-relay-sample.json index dfd29ed80f43..927deb539704 100644 --- a/src/sonic-config-engine/tests/dhcp-relay-sample.json +++ b/src/sonic-config-engine/tests/dhcp-relay-sample.json @@ -1,5 +1,10 @@ { "VLAN_INTERFACE": { "Vlan1000|fc02:2000::2/24": {} + }, + "FEATURE": { + "dhcp_server": { + "state": "disabled" + } } } diff --git a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-enable-dhcp-server.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-enable-dhcp-server.supervisord.conf new file mode 120000 index 000000000000..f814d764a9f2 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-enable-dhcp-server.supervisord.conf @@ -0,0 +1 @@ +../py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-no-ip-helper.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-no-ip-helper.supervisord.conf index c36dbe22533b..a12bbef319bd 100644 --- a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-no-ip-helper.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-no-ip-helper.supervisord.conf @@ -42,7 +42,6 @@ dependent_startup_wait_for=rsyslogd:running [group:dhcp-relay] programs=isc-dhcpv4-relay-Vlan1000,dhcp6relay - [program:isc-dhcpv4-relay-Vlan1000] command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id Vlan1000 -iu Vlan2000 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -iu PortChannel01 192.0.0.1 192.0.0.2 priority=3 diff --git a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay.supervisord.conf index 9d4a9d22de47..6ea09feb7c30 100644 --- a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay.supervisord.conf @@ -42,7 +42,6 @@ dependent_startup_wait_for=rsyslogd:running [group:dhcp-relay] programs=isc-dhcpv4-relay-Vlan1000,isc-dhcpv4-relay-Vlan2000,dhcp6relay - [program:isc-dhcpv4-relay-Vlan1000] command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id Vlan1000 -iu Vlan2000 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -iu PortChannel01 192.0.0.1 192.0.0.2 priority=3 diff --git a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf new file mode 100644 index 000000000000..350e302ce9e1 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf @@ -0,0 +1,64 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[eventlistener:dependent-startup] +command=python3 -m supervisord_dependent_startup +autostart=true +autorestart=unexpected +startretries=0 +exitcodes=0,3 +events=PROCESS_STATE +buffer_size=1024 + +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener --container-name dhcp_relay +events=PROCESS_STATE_EXITED,PROCESS_STATE_RUNNING +autostart=true +autorestart=unexpected +buffer_size=1024 + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n -iNONE +priority=1 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true + +[program:start] +command=/usr/bin/start.sh +priority=2 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[group:dhcp-relay] +programs=dhcprelayd,dhcp6relay + +[program:dhcp6relay] +command=/usr/sbin/dhcp6relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=start:exited + +[program:dhcprelayd] +command=/usr/local/bin/dhcprelayd +priority=3 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=start:exited + diff --git a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-no-ip-helper.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-no-ip-helper.supervisord.conf index 35ad0c48b82f..7d43878f267a 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-no-ip-helper.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-no-ip-helper.supervisord.conf @@ -42,7 +42,6 @@ dependent_startup_wait_for=rsyslogd:running [group:dhcp-relay] programs=isc-dhcpv4-relay-Vlan1000,dhcp6relay - [program:isc-dhcpv4-relay-Vlan1000] command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id Vlan1000 -iu Vlan2000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 192.0.0.1 192.0.0.2 priority=3 diff --git a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay.supervisord.conf index 7ea29dfcd635..5cdee13b3c4b 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay.supervisord.conf @@ -42,7 +42,6 @@ dependent_startup_wait_for=rsyslogd:running [group:dhcp-relay] programs=isc-dhcpv4-relay-Vlan1000,isc-dhcpv4-relay-Vlan2000,dhcp6relay - [program:isc-dhcpv4-relay-Vlan1000] command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id Vlan1000 -iu Vlan2000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 192.0.0.1 192.0.0.2 priority=3 diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 50e5df4a4660..97ad63441f9e 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -154,22 +154,43 @@ def test_ports_json(self): def test_dhcp_relay(self): # Test generation of wait_for_intf.sh dhc_sample_data = os.path.join(self.test_dir, "dhcp-relay-sample.json") + enable_dhcp_server_sample_data = os.path.join(self.test_dir, "dhcp-relay-enable-dhcp-server-sample.json") template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', 'wait_for_intf.sh.j2') argument = ['-m', self.t0_minigraph, '-j', dhc_sample_data, '-p', self.t0_port_config, '-t', template_path] self.run_script(argument, output_file=self.output_file) self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, 'wait_for_intf.sh'), self.output_file)) - # Test generation of docker-dhcp-relay.supervisord.conf + # Test generation of docker-dhcp-relay.supervisord.conf witout dhcp_server feature entry template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', 'docker-dhcp-relay.supervisord.conf.j2') argument = ['-m', self.t0_minigraph, '-p', self.t0_port_config, '-t', template_path] self.run_script(argument, output_file=self.output_file) self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, 'docker-dhcp-relay.supervisord.conf'), self.output_file)) + # Test generation of docker-dhcp-relay.supervisord.conf with disabled dhcp_server feature + template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', + 'docker-dhcp-relay.supervisord.conf.j2') + argument = ['-m', self.t0_minigraph, '-j', dhc_sample_data, '-p', self.t0_port_config, '-t', template_path] + self.run_script(argument, output_file=self.output_file) + self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, + 'docker-dhcp-relay.supervisord.conf'), self.output_file)) + + # Test generation of docker-dhcp-relay.supervisord.conf with enabled dhcp_server feature + template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', + 'docker-dhcp-relay.supervisord.conf.j2') + argument = ['-m', self.t0_minigraph, '-j', enable_dhcp_server_sample_data, '-p', self.t0_port_config, '-t', + template_path] + self.run_script(argument, output_file=self.output_file) + self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, + 'docker-dhcp-relay-enable-dhcp-server.supervisord.conf'), + self.output_file)) + # Test generation of docker-dhcp-relay.supervisord.conf when a vlan is missing ip/ipv6 helpers - template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', 'docker-dhcp-relay.supervisord.conf.j2') + template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', + 'docker-dhcp-relay.supervisord.conf.j2') argument = ['-m', self.no_ip_helper_minigraph, '-p', self.t0_port_config, '-t', template_path] self.run_script(argument, output_file=self.output_file) - self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, 'docker-dhcp-relay-no-ip-helper.supervisord.conf'), self.output_file)) + self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, + 'docker-dhcp-relay-no-ip-helper.supervisord.conf'), self.output_file)) def test_radv(self): # Test generation of radvd.conf with multiple ipv6 prefixes diff --git a/src/sonic-dhcp-server/dhcp_server/common/__init__.py b/src/sonic-dhcp-server/dhcp_server/common/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/sonic-dhcp-server/dhcp_server/common/dhcp_db_monitor.py b/src/sonic-dhcp-server/dhcp_server/common/dhcp_db_monitor.py new file mode 100644 index 000000000000..bbee63e1ec90 --- /dev/null +++ b/src/sonic-dhcp-server/dhcp_server/common/dhcp_db_monitor.py @@ -0,0 +1,131 @@ +import ipaddress +import syslog +from abc import abstractmethod +from swsscommon import swsscommon + +DHCP_SERVER_IPV4 = "DHCP_SERVER_IPV4" +DHCP_SERVER_IPV4_PORT = "DHCP_SERVER_IPV4_PORT" +DHCP_SERVER_IPV4_RANGE = "DHCP_SERVER_IPV4_RANGE" +VLAN = "VLAN" +VLAN_MEMBER = "VLAN_MEMBER" +VLAN_INTERFACE = "VLAN_INTERFACE" +DEFAULT_SELECT_TIMEOUT = 5000 # millisecond + + +class DhcpDbMonitor(object): + def __init__(self, db_connector, select_timeout=DEFAULT_SELECT_TIMEOUT): + self.db_connector = db_connector + self.sel = swsscommon.Select() + self.select_timeout = select_timeout + + @abstractmethod + def subscribe_table(self): + """ + Subcribe db table to monitor + """ + raise NotImplementedError + + @abstractmethod + def _do_check(self): + """ + Check whether interested table content changed + """ + raise NotImplementedError + + def check_db_update(self, check_param): + """ + Fetch db and check update + """ + state, _ = self.sel.select(self.select_timeout) + if state == swsscommon.Select.TIMEOUT or state != swsscommon.Select.OBJECT: + return False + return self._do_check(check_param) + + +class DhcpRelaydDbMonitor(DhcpDbMonitor): + subscribe_dhcp_server_table = None + subscribe_vlan_table = None + subscribe_vlan_intf_table = None + + def subscribe_table(self): + self.subscribe_dhcp_server_table = swsscommon.SubscriberStateTable(self.db_connector.config_db, + DHCP_SERVER_IPV4) + self.subscribe_vlan_table = swsscommon.SubscriberStateTable(self.db_connector.config_db, VLAN) + self.subscribe_vlan_intf_table = swsscommon.SubscriberStateTable(self.db_connector.config_db, VLAN_INTERFACE) + # Subscribe dhcp_server_ipv4 and vlan/vlan_interface table. No need to subscribe vlan_member table + self.sel.addSelectable(self.subscribe_dhcp_server_table) + self.sel.addSelectable(self.subscribe_vlan_table) + self.sel.addSelectable(self.subscribe_vlan_intf_table) + + def _do_check(self, check_param): + if "enabled_dhcp_interfaces" not in check_param: + syslog.syslog(syslog.LOG_ERR, "Cannot get enabled_dhcp_interfaces") + return (True, True, True) + enabled_dhcp_interfaces = check_param["enabled_dhcp_interfaces"] + return (self._check_dhcp_server_update(enabled_dhcp_interfaces), + self._check_vlan_update(enabled_dhcp_interfaces), + self._check_vlan_intf_update(enabled_dhcp_interfaces)) + + def _check_dhcp_server_update(self, enabled_dhcp_interfaces): + """ + Check dhcp_server_ipv4 table + Args: + enabled_dhcp_interfaces: DHCP interface that enabled dhcp_server + Returns: + Whether need to refresh + """ + need_refresh = False + while self.subscribe_dhcp_server_table.hasData(): + key, op, entry = self.subscribe_dhcp_server_table.pop() + if op == "SET": + for field, value in entry: + if field != "state": + continue + # Only if new state is not consistent with old state, we need to refresh + if key in enabled_dhcp_interfaces and value == "disabled": + need_refresh = True + elif key not in enabled_dhcp_interfaces and value == "enabled": + need_refresh = True + # For del operation, we can skip disabled change + if op == "DEL": + if key in enabled_dhcp_interfaces: + need_refresh = True + return need_refresh + + def _check_vlan_update(self, enabled_dhcp_interfaces): + """ + Check vlan table + Args: + enabled_dhcp_interfaces: DHCP interface that enabled dhcp_server + Returns: + Whether need to refresh + """ + need_refresh = False + while self.subscribe_vlan_table.hasData(): + key, op, _ = self.subscribe_vlan_table.pop() + # For vlan doesn't have related dhcp entry, not need to refresh dhcrelay process + if key not in enabled_dhcp_interfaces: + continue + need_refresh = True + return need_refresh + + def _check_vlan_intf_update(self, enabled_dhcp_interfaces): + """ + Check vlan_interface table + Args: + enabled_dhcp_interfaces: DHCP interface that enabled dhcp_server + Returns: + Whether need to refresh + """ + need_refresh = False + while self.subscribe_vlan_intf_table.hasData(): + key, _, _ = self.subscribe_vlan_intf_table.pop() + splits = key.split("|") + vlan_name = splits[0] + ip_address = splits[1].split("/")[0] if len(splits) > 1 else None + if vlan_name not in enabled_dhcp_interfaces: + continue + if ip_address is None or ipaddress.ip_address(ip_address).version != 4: + continue + need_refresh = True + return need_refresh diff --git a/src/sonic-dhcp-server/dhcp_server/dhcp_server_utils.py b/src/sonic-dhcp-server/dhcp_server/common/utils.py similarity index 94% rename from src/sonic-dhcp-server/dhcp_server/dhcp_server_utils.py rename to src/sonic-dhcp-server/dhcp_server/common/utils.py index b045752bc658..a07913d6c766 100644 --- a/src/sonic-dhcp-server/dhcp_server/dhcp_server_utils.py +++ b/src/sonic-dhcp-server/dhcp_server/common/utils.py @@ -56,6 +56,16 @@ def get_entry(table, entry_name): return dict(entry) +def terminate_proc(proc): + """ + Terminate process, to make sure it exit successfully + Args: + proc: Process object in psutil + """ + proc.terminate() + proc.wait() + + def merge_intervals(intervals): """ Merge ip range intervals. diff --git a/src/sonic-dhcp-server/dhcp_server/dhcprelayd/dhcprelayd.py b/src/sonic-dhcp-server/dhcp_server/dhcprelayd/dhcprelayd.py new file mode 100644 index 000000000000..cf5a6de5e0b6 --- /dev/null +++ b/src/sonic-dhcp-server/dhcp_server/dhcprelayd/dhcprelayd.py @@ -0,0 +1,191 @@ +# TODO Add support for running different dhcrelay processes for each dhcp interface +# Currently if we run multiple dhcrelay processes, except for the last running process, +# others will not relay dhcp_release packet. +import psutil +import subprocess +import sys +import syslog +import time +from swsscommon import swsscommon +from dhcp_server.common.utils import DhcpDbConnector, terminate_proc +from dhcp_server.common.dhcp_db_monitor import DhcpRelaydDbMonitor + +REDIS_SOCK_PATH = "/var/run/redis/redis.sock" +DHCP_SERVER_IPV4_SERVER_IP = "DHCP_SERVER_IPV4_SERVER_IP" +DHCP_SERVER_IPV4 = "DHCP_SERVER_IPV4" +VLAN = "VLAN" +VLAN_INTERFACE = "VLAN_INTERFACE" +DEFAULT_SELECT_TIMEOUT = 5000 # millisecond +DHCP_SERVER_INTERFACE = "eth0" +DEFAULT_REFRESH_INTERVAL = 2 + +KILLED_OLD = 1 +NOT_KILLED = 2 +NOT_FOUND_PROC = 3 + + +class DhcpRelayd(object): + sel = None + enabled_dhcp_interfaces = set() + + def __init__(self, db_connector, select_timeout=DEFAULT_SELECT_TIMEOUT): + """ + Args: + db_connector: db connector obj + select_timeout: timeout setting for subscribe db change + """ + self.db_connector = db_connector + self.last_refresh_time = None + self.dhcp_relayd_monitor = DhcpRelaydDbMonitor(db_connector, select_timeout) + + def start(self): + """ + Start function + """ + self.refresh_dhcrelay() + self.dhcp_relayd_monitor.subscribe_table() + + def refresh_dhcrelay(self, force_kill=False): + """ + To refresh dhcrelay/dhcpmon process (start or restart) + """ + syslog.syslog(syslog.LOG_INFO, "Start to refresh dhcrelay related processes") + dhcp_server_ip = self._get_dhcp_server_ip() + dhcp_server_ipv4_table = self.db_connector.get_config_db_table(DHCP_SERVER_IPV4) + vlan_table = self.db_connector.get_config_db_table(VLAN) + + dhcp_interfaces = set() + self.enabled_dhcp_interfaces = set() + for dhcp_interface, config in dhcp_server_ipv4_table.items(): + # Reason for add to enabled_dhcp_interfaces firstly is for below scenario: + # Firstly vlan 1000 is not in vlan table but enabled in dhcp_server table, then add vlan1000 to vlan table + # we need to refresh + if config["state"] == "enabled": + dhcp_interfaces.add(dhcp_interface) + self.enabled_dhcp_interfaces.add(dhcp_interface) + if dhcp_interface not in vlan_table: + dhcp_interfaces.discard(dhcp_interface) + continue + self._start_dhcrelay_process(dhcp_interfaces, dhcp_server_ip, force_kill) + self._start_dhcpmon_process(dhcp_interfaces, force_kill) + + def wait(self): + """ + Wait function, check db change here + """ + while True: + res = (self.dhcp_relayd_monitor.check_db_update({"enabled_dhcp_interfaces": self.enabled_dhcp_interfaces})) + # Select timeout or no successful + if isinstance(res, bool): + continue + (dhcp_server_res, vlan_res, vlan_intf_res) = res + # vlan ip change require kill old dhcp_relay related processes + if vlan_intf_res: + self.refresh_dhcrelay(True) + elif dhcp_server_res or vlan_res: + self.refresh_dhcrelay(False) + + def _start_dhcrelay_process(self, new_dhcp_interfaces, dhcp_server_ip, force_kill): + # To check whether need to kill dhcrelay process + kill_res = self._kill_exist_relay_releated_process(new_dhcp_interfaces, "dhcrelay", force_kill) + if kill_res == NOT_KILLED: + # Means old running status consistent with the new situation, no need to run new + return + + # No need to start new dhcrelay process + if len(new_dhcp_interfaces) == 0: + return + + cmds = ["/usr/sbin/dhcrelay", "-d", "-m", "discard", "-a", "%h:%p", "%P", "--name-alias-map-file", + "/tmp/port-name-alias-map.txt"] + for dhcp_interface in new_dhcp_interfaces: + cmds += ["-id", dhcp_interface] + cmds += ["-iu", "docker0", dhcp_server_ip] + popen_res = subprocess.Popen(cmds) + # To make sure process start successfully not in zombie status + proc = psutil.Process(popen_res.pid) + time.sleep(1) + if proc.status() == psutil.STATUS_ZOMBIE: + syslog.syslog(syslog.LOG_ERR, "Failed to start dhcrelay process with: {}".format(cmds)) + terminate_proc(proc) + sys.exit(1) + + syslog.syslog(syslog.LOG_INFO, "dhcrelay process started successfully, cmds: {}".format(cmds)) + + def _start_dhcpmon_process(self, new_dhcp_interfaces, force_kill): + # To check whether need to kill dhcrelay process + kill_res = self._kill_exist_relay_releated_process(new_dhcp_interfaces, "dhcpmon", force_kill) + if kill_res == NOT_KILLED: + # Means old running status consistent with the new situation, no need to run new + return + + # No need to start new dhcrelay process + if len(new_dhcp_interfaces) == 0: + return + + pids_cmds = {} + for dhcp_interface in new_dhcp_interfaces: + cmds = ["/usr/sbin/dhcpmon", "-id", dhcp_interface, "-iu", "docker0", "-im", "eth0"] + popen_res = subprocess.Popen(cmds) + pids_cmds[popen_res.pid] = cmds + time.sleep(1) + # To make sure process start successfully not in zombie status + for pid, cmds in pids_cmds.items(): + proc = psutil.Process(pid) + if proc.status() == psutil.STATUS_ZOMBIE: + syslog.syslog(syslog.LOG_ERR, "Faild to start dhcpmon process: {}".format(cmds)) + terminate_proc(proc) + else: + syslog.syslog(syslog.LOG_INFO, "dhcpmon process started successfully, cmds: {}".format(cmds)) + + def _kill_exist_relay_releated_process(self, new_dhcp_interfaces, process_name, force_kill): + old_dhcp_interfaces = set() + # Because in system there maybe more than 1 dhcpmon processes are running, so we need list to store + target_procs = [] + + # Get old dhcrelay process and get old dhcp interfaces + for proc in psutil.process_iter(): + if proc.name() == process_name: + cmds = proc.cmdline() + index = 0 + target_procs.append(proc) + while index < len(cmds): + if cmds[index] == "-id": + old_dhcp_interfaces.add(cmds[index + 1]) + index += 2 + else: + index += 1 + if len(target_procs) == 0: + return NOT_FOUND_PROC + + # No need to kill + if not force_kill and (process_name == "dhcrelay" and old_dhcp_interfaces == new_dhcp_interfaces or + process_name == "dhcpmon" and old_dhcp_interfaces == (new_dhcp_interfaces)): + return NOT_KILLED + for proc in target_procs: + terminate_proc(proc) + syslog.syslog(syslog.LOG_INFO, "Kill process: {}".format(process_name)) + return KILLED_OLD + + def _get_dhcp_server_ip(self): + dhcp_server_ip_table = swsscommon.Table(self.db_connector.state_db, DHCP_SERVER_IPV4_SERVER_IP) + for _ in range(10): + state, ip = dhcp_server_ip_table.hget(DHCP_SERVER_INTERFACE, "ip") + if state: + return ip + else: + syslog.syslog(syslog.LOG_INFO, "Cannot get dhcp server ip") + time.sleep(10) + syslog.syslog(syslog.LOG_ERR, "Cannot get dhcp_server ip from state_db") + sys.exit(1) + + +def main(): + dhcp_db_connector = DhcpDbConnector(redis_sock=REDIS_SOCK_PATH) + dhcprelayd = DhcpRelayd(dhcp_db_connector) + dhcprelayd.start() + dhcprelayd.wait() + + +if __name__ == "__main__": + main() diff --git a/src/sonic-dhcp-server/dhcp_server/dhcp_cfggen.py b/src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcp_cfggen.py similarity index 99% rename from src/sonic-dhcp-server/dhcp_server/dhcp_cfggen.py rename to src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcp_cfggen.py index 4fca71a3834d..0708f93c86a7 100755 --- a/src/sonic-dhcp-server/dhcp_server/dhcp_cfggen.py +++ b/src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcp_cfggen.py @@ -1,12 +1,11 @@ #!/usr/bin/env python import ipaddress -import json import os import syslog from jinja2 import Environment, FileSystemLoader -from .dhcp_server_utils import merge_intervals +from dhcp_server.common.utils import merge_intervals PORT_MAP_PATH = "/tmp/port-name-alias-map.txt" UNICODE_TYPE = str diff --git a/src/sonic-dhcp-server/dhcp_server/dhcp_lease.py b/src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcp_lease.py similarity index 95% rename from src/sonic-dhcp-server/dhcp_server/dhcp_lease.py rename to src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcp_lease.py index 693a93d2c090..10ff46da85c8 100644 --- a/src/sonic-dhcp-server/dhcp_server/dhcp_lease.py +++ b/src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcp_lease.py @@ -1,5 +1,3 @@ -import ipaddress -import json import signal import syslog import threading @@ -66,12 +64,13 @@ def update_lease(self): old_lease_table = self.db_connector.get_state_db_table(DHCP_SERVER_IPV4_LEASE) old_lease_key = set(old_lease_table.keys()) - # 1.1 If start time equal to end time, means lease has been released + # 1.1 If start time equal to end time or lease expired, means lease has been released # 1.1.1 If current lease table has this old lease, delete it # 1.1.2 Else skip # 1.2 Else, means lease valid, save it. for key, value in new_lease.items(): - if value["lease_start"] == value["lease_end"]: + unix_time = datetime.now().timestamp() + if value["lease_start"] == value["lease_end"] or unix_time >= int(value["lease_end"]): if key in old_lease_key: self.db_connector.state_db.delete("{}|{}".format(DHCP_SERVER_IPV4_LEASE, key)) continue diff --git a/src/sonic-dhcp-server/dhcp_server/dhcpservd.py b/src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcpservd.py similarity index 64% rename from src/sonic-dhcp-server/dhcp_server/dhcpservd.py rename to src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcpservd.py index a82db326c919..17266b66a86a 100644 --- a/src/sonic-dhcp-server/dhcp_server/dhcpservd.py +++ b/src/sonic-dhcp-server/dhcp_server/dhcpservd/dhcpservd.py @@ -2,14 +2,19 @@ import psutil import signal import time +import sys +import syslog from .dhcp_cfggen import DhcpServCfgGenerator from .dhcp_lease import LeaseManager -from .dhcp_server_utils import DhcpDbConnector +from dhcp_server.common.utils import DhcpDbConnector KEA_DHCP4_CONFIG = "/etc/kea/kea-dhcp4.conf" KEA_DHCP4_PROC_NAME = "kea-dhcp4" KEA_LEASE_FILE_PATH = "/tmp/kea-lease.csv" REDIS_SOCK_PATH = "/var/run/redis/redis.sock" +DHCP_SERVER_IPV4_SERVER_IP = "DHCP_SERVER_IPV4_SERVER_IP" +DHCP_SERVER_INTERFACE = "eth0" +AF_INET = 2 class DhcpServd(object): @@ -37,8 +42,27 @@ def dump_dhcp4_config(self): # After refresh kea-config, we need to SIGHUP kea-dhcp4 process to read new config self._notify_kea_dhcp4_proc() + def _update_dhcp_server_ip(self): + """ + Add ip address of "eth0" inside dhcp_server container as dhcp_server_ip into state_db + """ + dhcp_server_ip = None + for _ in range(10): + dhcp_interface = psutil.net_if_addrs().get(DHCP_SERVER_INTERFACE, []) + for address in dhcp_interface: + if address.family == AF_INET: + dhcp_server_ip = address.address + self.db_connector.state_db.hset("{}|{}".format(DHCP_SERVER_IPV4_SERVER_IP, DHCP_SERVER_INTERFACE), + "ip", dhcp_server_ip) + return + else: + time.sleep(5) + syslog.syslog(syslog.LOG_INFO, "Cannot get ip address of {}".format(DHCP_SERVER_INTERFACE)) + sys.exit(1) + def start(self): self.dump_dhcp4_config() + self._update_dhcp_server_ip() lease_manager = LeaseManager(self.db_connector, KEA_LEASE_FILE_PATH) lease_manager.start() diff --git a/src/sonic-dhcp-server/setup.py b/src/sonic-dhcp-server/setup.py index c81a915cefbc..1dc57a70ff45 100644 --- a/src/sonic-dhcp-server/setup.py +++ b/src/sonic-dhcp-server/setup.py @@ -1,18 +1,12 @@ -from setuptools import setup +from setuptools import setup, find_packages dependencies = [ - "psutil", - "coverage" + "psutil" ] test_deps = [ - "pytest" -] - -py_modules = [ - "dhcp_server_utils", - "dhcp_cfggen", - "dhcp_lease" + "pytest", + "freezegun" ] setup( @@ -29,14 +23,16 @@ "wheel", ], packages=[ - "dhcp_server" + "dhcp_server.common", + "dhcp_server.dhcpservd", + "dhcp_server.dhcprelayd" ], entry_points={ "console_scripts": [ - "dhcpservd = dhcp_server.dhcpservd:main" + "dhcprelayd = dhcp_server.dhcprelayd.dhcprelayd:main", + "dhcpservd = dhcp_server.dhcpservd.dhcpservd:main" ] }, - py_modules=py_modules, classifiers=[ "Intended Audience :: Developers", "Operating System :: Linux", diff --git a/src/sonic-dhcp-server/tests/common_utils.py b/src/sonic-dhcp-server/tests/common_utils.py index a9ebadd3a4e5..35e09f7fec51 100644 --- a/src/sonic-dhcp-server/tests/common_utils.py +++ b/src/sonic-dhcp-server/tests/common_utils.py @@ -1,6 +1,9 @@ +import heapq import json +import psutil MOCK_CONFIG_DB_PATH = "tests/test_data/mock_config_db.json" +MOCK_STATE_DB_PATH = "tests/test_data/mock_state_db.json" class MockConfigDb(object): @@ -10,3 +13,75 @@ def __init__(self, config_db_path=MOCK_CONFIG_DB_PATH): def get_config_db_table(self, table_name): return self.config_db.get(table_name, {}) + + +class MockSelect(object): + def __init__(self): + pass + + def select(self, timeout): + return None, None + + +class MockSubscribeTable(object): + def __init__(self, tables): + self.stack = [] + for item in tables: + heapq.heappush(self.stack, item) + # if table_name == "DHCP_SERVER_IPV4": + # heapq.heappush(self.stack, ("Vlan1000", "SET", (("state", "enabled"),))) + # heapq.heappush(self.stack, ("Vlan1000", "SET", (("customized_options", "option1"), ("state", "enabled"),))) + # heapq.heappush(self.stack, ("Vlan2000", "SET", (("state", "enabled"),))) + # heapq.heappush(self.stack, ("Vlan1000", "DEL", ())) + # heapq.heappush(self.stack, ("Vlan2000", "DEL", ())) + # if table_name == "VLAN": + # heapq.heappush(self.stack, ("Vlan1000", "SET", (("vlanid", "1000"),))) + # heapq.heappush(self.stack, ("Vlan1001", "SET", (("vlanid", "1001"),))) + # heapq.heappush(self.stack, ("Vlan1001", "DEL", (("vlanid", "1001"),))) + # heapq.heappush(self.stack, ("Vlan1002", "SET", (("vlanid", "1002"),))) + # heapq.heappush(self.stack, ("Vlan2000", "SET", (("vlanid", "2000"),))) + + def pop(self): + res = heapq.heappop(self.stack) + return res + + def hasData(self): + return len(self.stack) != 0 + + +def mock_get_config_db_table(table_name): + mock_config_db = MockConfigDb() + return mock_config_db.get_config_db_table(table_name) + + +class MockProc(object): + def __init__(self, name, pid=None, status=psutil.STATUS_RUNNING): + self.proc_name = name + self.pid = pid + + def name(self): + return self.proc_name + + def send_signal(self, sig_num): + pass + + def cmdline(self): + if self.proc_name == "dhcrelay": + return ["/usr/sbin/dhcrelay", "-d", "-m", "discard", "-a", "%h:%p", "%P", "--name-alias-map-file", + "/tmp/port-name-alias-map.txt", "-id", "Vlan1000", "-iu", "docker0", "240.127.1.2"] + if self.proc_name == "dhcpmon": + return ["/usr/sbin/dhcpmon", "-id", "Vlan1000", "-iu", "docker0", "-im", "eth0"] + + def terminate(self): + pass + + def wait(self): + pass + + def status(self): + return self.status + + +class MockPopen(object): + def __init__(self, pid): + self.pid = pid diff --git a/src/sonic-dhcp-server/tests/conftest.py b/src/sonic-dhcp-server/tests/conftest.py index 295cc543b43c..046c1f164c16 100644 --- a/src/sonic-dhcp-server/tests/conftest.py +++ b/src/sonic-dhcp-server/tests/conftest.py @@ -1,30 +1,38 @@ import pytest -import dhcp_server.dhcp_server_utils as dhcp_server_utils +import dhcp_server.common.utils as utils +import os +import sys from unittest.mock import patch, PropertyMock -from dhcp_server.dhcp_cfggen import DhcpServCfgGenerator +from dhcp_server.dhcpservd.dhcp_cfggen import DhcpServCfgGenerator +test_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(test_path) +sys.path.insert(0, test_path) +sys.path.insert(0, modules_path) @pytest.fixture(scope="function") def mock_swsscommon_dbconnector_init(): - with patch.object(dhcp_server_utils.swsscommon.DBConnector, "__init__", return_value=None) as mock_dbconnector_init: + with patch.object(utils.swsscommon.DBConnector, "__init__", return_value=None) as mock_dbconnector_init: yield mock_dbconnector_init @pytest.fixture(scope="function") def mock_swsscommon_table_init(): - with patch.object(dhcp_server_utils.swsscommon.Table, "__init__", return_value=None) as mock_table_init: + with patch.object(utils.swsscommon.Table, "__init__", return_value=None) as mock_table_init: yield mock_table_init @pytest.fixture(scope="function") def mock_get_render_template(): - with patch("dhcp_server.dhcp_cfggen.DhcpServCfgGenerator._get_render_template", return_value=None) as mock_template: + with patch("dhcp_server.dhcpservd.dhcp_cfggen.DhcpServCfgGenerator._get_render_template", + return_value=None) as mock_template: yield mock_template @pytest.fixture def mock_parse_port_map_alias(scope="function"): - with patch("dhcp_server.dhcp_cfggen.DhcpServCfgGenerator._parse_port_map_alias", return_value=None) as mock_map, \ + with patch("dhcp_server.dhcpservd.dhcp_cfggen.DhcpServCfgGenerator._parse_port_map_alias", + return_value=None) as mock_map, \ patch.object(DhcpServCfgGenerator, "port_alias_map", return_value={"Ethernet24": "etp7", "Ethernet28": "etp8"}, new_callable=PropertyMock), \ patch.object(DhcpServCfgGenerator, "lease_update_script_path", return_value="/etc/kea/lease_update.sh", @@ -32,4 +40,3 @@ def mock_parse_port_map_alias(scope="function"): patch.object(DhcpServCfgGenerator, "lease_path", return_value="/tmp/kea-lease.csv", new_callable=PropertyMock): yield mock_map - diff --git a/src/sonic-dhcp-server/tests/test_data/kea-lease.csv b/src/sonic-dhcp-server/tests/test_data/kea-lease.csv index 85976d8cb5f9..645b07b2276e 100644 --- a/src/sonic-dhcp-server/tests/test_data/kea-lease.csv +++ b/src/sonic-dhcp-server/tests/test_data/kea-lease.csv @@ -6,4 +6,5 @@ address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostn 192.168.0.131,10:70:fd:b6:13:17,,3600,1694000915,1,0,0,7626dced293e,0,,1 192.168.0.2,10:70:fd:b6:13:00,,0,1693997305,1,0,0,7626dced293e,0,,0 193.168.2.2,10:70:fd:b6:13:15,,3600,1693999305,1,0,0,7626dced293e,0,,0 -193.168.2.3,10:70:fd:b6:13:20,,3600,1693999305,1,0,0,7626dced293e,0,,0 \ No newline at end of file +193.168.2.3,10:70:fd:b6:13:20,,3600,1693999305,1,0,0,7626dced293e,0,,0 +193.168.0.132,10:70:fd:b6:13:18,,3600,1697610805,1,0,0,7626dced293e,0,,0 \ No newline at end of file diff --git a/src/sonic-dhcp-server/tests/test_data/mock_config_db.json b/src/sonic-dhcp-server/tests/test_data/mock_config_db.json index 0e6f4387f47c..52e30d403b94 100644 --- a/src/sonic-dhcp-server/tests/test_data/mock_config_db.json +++ b/src/sonic-dhcp-server/tests/test_data/mock_config_db.json @@ -4,6 +4,10 @@ "hostname": "sonic-host" } }, + "VLAN": { + "Vlan1000": {}, + "Vlan2000": {} + }, "VLAN_INTERFACE": { "Vlan1000|192.168.0.1/21": { "NULL": "NULL" @@ -77,6 +81,17 @@ "mode": "PORT", "netmask": "255.255.255.0", "state": "enabled" + }, + "Vlan5000": { + "customized_options": [ + "option60", + "option223" + ], + "gateway": "192.168.4.1", + "lease_time": "900", + "mode": "PORT", + "netmask": "255.255.255.0", + "state": "disabled" } }, "DHCP_SERVER_IPV4_CUSTOMIZED_OPTIONS": { diff --git a/src/sonic-dhcp-server/tests/test_dhcp_cfggen.py b/src/sonic-dhcp-server/tests/test_dhcp_cfggen.py index 25b46f85442b..410b809489db 100644 --- a/src/sonic-dhcp-server/tests/test_dhcp_cfggen.py +++ b/src/sonic-dhcp-server/tests/test_dhcp_cfggen.py @@ -3,9 +3,8 @@ import json import pytest from common_utils import MockConfigDb -from dhcp_server.dhcp_server_utils import DhcpDbConnector -from dhcp_server.dhcp_cfggen import DhcpServCfgGenerator -from unittest.mock import patch, MagicMock +from dhcp_server.common.utils import DhcpDbConnector +from dhcp_server.dhcpservd.dhcp_cfggen import DhcpServCfgGenerator expected_dhcp_config = { "Dhcp4": { diff --git a/src/sonic-dhcp-server/tests/test_dhcp_db_monitor.py b/src/sonic-dhcp-server/tests/test_dhcp_db_monitor.py new file mode 100644 index 000000000000..2f2eed66a3db --- /dev/null +++ b/src/sonic-dhcp-server/tests/test_dhcp_db_monitor.py @@ -0,0 +1,219 @@ +import pytest +from common_utils import MockSubscribeTable +from dhcp_server.common.dhcp_db_monitor import DhcpDbMonitor, DhcpRelaydDbMonitor +from dhcp_server.common.utils import DhcpDbConnector +from swsscommon import swsscommon +from unittest.mock import patch, call, ANY, PropertyMock + +tested_subscribe_dhcp_server_table = [ + { + "table": [ + ("Vlan1000", "SET", (("customized_options", "option1"), ("state", "enabled"),)) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan2000", "SET", (("state", "enabled"),)) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan1000", "DEL", ()) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan2000", "DEL", ()) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan2000", "DEL", ()), + ("Vlan1000", "DEL", ()) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan3000", "SET", (("state", "enabled"),)) + ], + "exp_res": True + } +] +tested_subscribe_vlan_table = [ + { + "table": [ + ("Vlan1000", "SET", (("vlanid", "1000"),)) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan1001", "SET", (("vlanid", "1001"),)) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan1000", "SET", (("vlanid", "1000"),)), + ("Vlan1002", "SET", (("vlanid", "1002"),)) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan1001", "DEL", ()) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan1000", "DEL", ()) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan1000", "SET", (("vlanid", "1000"),)), + ("Vlan1001", "DEL", ()) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan1003", "SET", (("vlanid", "1003"),)) + ], + "exp_res": False + } +] +tested_subscribe_vlan_intf_table = [ + { + "table": [ + ("Vlan1000", "SET", ()) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan1000|192.168.0.1/24", "SET", ()) + ], + "exp_res": True + }, + { + "table": [ + ("Vlan1000|fc02::8/64", "SET", ()) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan2000|192.168.0.1/24", "SET", ()) + ], + "exp_res": False + }, + { + "table": [ + ("Vlan1001|192.168.0.1/24", "SET", ()) + ], + "exp_res": False + } +] + + +@pytest.mark.parametrize("select_result", [swsscommon.Select.TIMEOUT, swsscommon.Select.OBJECT]) +def test_dhcp_db_monitor(mock_swsscommon_dbconnector_init, select_result): + db_connector = DhcpDbConnector() + dhcp_db_monitor = DhcpDbMonitor(db_connector) + try: + dhcp_db_monitor.subscribe_table() + except NotImplementedError: + pass + try: + dhcp_db_monitor._do_check() + except NotImplementedError: + pass + with patch.object(DhcpDbMonitor, "_do_check", return_value=None) as mock_do_check, \ + patch.object(swsscommon.Select, "select", return_value=(select_result, None)): + dhcp_db_monitor.check_db_update("mock_param") + if select_result == swsscommon.Select.TIMEOUT: + mock_do_check.assert_not_called() + elif select_result == swsscommon.Select.OBJECT: + mock_do_check.assert_called_once_with("mock_param") + + +def test_dhcp_relayd_monitor_subscribe_table(mock_swsscommon_dbconnector_init): + with patch.object(swsscommon, "SubscriberStateTable", side_effect=mock_subscriber_state_table) as mock_subscribe, \ + patch.object(swsscommon.Select, "addSelectable", return_value=None) as mock_add_select: + db_connector = DhcpDbConnector() + dhcp_relayd_db_monitor = DhcpRelaydDbMonitor(db_connector) + dhcp_relayd_db_monitor.subscribe_table() + mock_subscribe.assert_has_calls([ + call(ANY, "DHCP_SERVER_IPV4"), + call(ANY, "VLAN"), + call(ANY, "VLAN_INTERFACE") + ]) + mock_add_select.assert_has_calls([ + call("DHCP_SERVER_IPV4"), + call("VLAN"), + call("VLAN_INTERFACE") + ]) + + +@pytest.mark.parametrize("check_param", [{}, {"enabled_dhcp_interfaces": "dummy"}]) +def test_dhcp_relayd_monitor_do_check(mock_swsscommon_dbconnector_init, check_param): + with patch.object(DhcpRelaydDbMonitor, "_check_dhcp_server_update") as mock_check_dhcp_server_update, \ + patch.object(DhcpRelaydDbMonitor, "_check_vlan_update") as mock_check_vlan_update, \ + patch.object(DhcpRelaydDbMonitor, "_check_vlan_intf_update") as mock_check_vlan_intf_update: + db_connector = DhcpDbConnector() + dhcp_relayd_db_monitor = DhcpRelaydDbMonitor(db_connector) + dhcp_relayd_db_monitor._do_check(check_param) + if "enabled_dhcp_interfaces" in check_param: + mock_check_dhcp_server_update.assert_called_once_with("dummy") + mock_check_vlan_update.assert_called_once_with("dummy") + mock_check_vlan_intf_update.assert_called_once_with("dummy") + else: + mock_check_dhcp_server_update.assert_not_called() + mock_check_vlan_update.assert_not_called() + mock_check_vlan_intf_update.assert_not_called() + + +@pytest.mark.parametrize("dhcp_server_table_update", tested_subscribe_dhcp_server_table) +def test_dhcp_relayd_monitor_check_dhcp_server_update(mock_swsscommon_dbconnector_init, dhcp_server_table_update): + tested_table = dhcp_server_table_update["table"] + with patch.object(DhcpRelaydDbMonitor, "subscribe_dhcp_server_table", + return_value=MockSubscribeTable(tested_table), + new_callable=PropertyMock): + db_connector = DhcpDbConnector() + dhcp_relayd_db_monitor = DhcpRelaydDbMonitor(db_connector) + check_res = dhcp_relayd_db_monitor._check_dhcp_server_update(set(["Vlan1000"])) + assert check_res == dhcp_server_table_update["exp_res"] + + +@pytest.mark.parametrize("vlan_table_update", tested_subscribe_vlan_table) +def test_dhcp_relayd_monitor_check_vlan_update(mock_swsscommon_dbconnector_init, vlan_table_update): + tested_table = vlan_table_update["table"] + with patch.object(DhcpRelaydDbMonitor, "subscribe_vlan_table", return_value=MockSubscribeTable(tested_table), + new_callable=PropertyMock): + db_connector = DhcpDbConnector() + dhcp_relayd_db_monitor = DhcpRelaydDbMonitor(db_connector) + check_res = dhcp_relayd_db_monitor._check_vlan_update(set(["Vlan1000"])) + assert check_res == vlan_table_update["exp_res"] + + +@pytest.mark.parametrize("vlan_intf_table_update", tested_subscribe_vlan_intf_table) +def test_dhcp_relayd_monitor_check_vlan_intf_update(mock_swsscommon_dbconnector_init, vlan_intf_table_update): + tested_table = vlan_intf_table_update["table"] + with patch.object(DhcpRelaydDbMonitor, "subscribe_vlan_intf_table", return_value=MockSubscribeTable(tested_table), + new_callable=PropertyMock): + db_connector = DhcpDbConnector() + dhcp_relayd_db_monitor = DhcpRelaydDbMonitor(db_connector) + check_res = dhcp_relayd_db_monitor._check_vlan_intf_update(set(["Vlan1000"])) + assert check_res == vlan_intf_table_update["exp_res"] + + +def mock_subscriber_state_table(db, table_name): + return table_name diff --git a/src/sonic-dhcp-server/tests/test_dhcp_lease.py b/src/sonic-dhcp-server/tests/test_dhcp_lease.py index 08a93e2c4c2c..4ec748749d6e 100644 --- a/src/sonic-dhcp-server/tests/test_dhcp_lease.py +++ b/src/sonic-dhcp-server/tests/test_dhcp_lease.py @@ -1,5 +1,6 @@ -from dhcp_server.dhcp_server_utils import DhcpDbConnector -from dhcp_server.dhcp_lease import KeaDhcp4LeaseHandler, LeaseHanlder +from dhcp_server.common.utils import DhcpDbConnector +from dhcp_server.dhcpservd.dhcp_lease import KeaDhcp4LeaseHandler, LeaseHanlder +from freezegun import freeze_time from swsscommon import swsscommon from unittest.mock import patch, call, MagicMock @@ -14,6 +15,11 @@ "lease_end": "1694000915", "ip": "192.168.0.131" }, + "Vlan1000|10:70:fd:b6:13:18": { + "lease_start": "1697607205", + "lease_end": "1697610805", + "ip": "193.168.0.132" + }, "Vlan2000|10:70:fd:b6:13:15": { "lease_start": "1693995705", "lease_end": "1693999305", @@ -24,6 +30,7 @@ "10:70:fd:b6:13:00": "Vlan1000", "10:70:fd:b6:13:15": "Vlan2000", "10:70:fd:b6:13:17": "Vlan1000", + "10:70:fd:b6:13:18": "Vlan1000" } @@ -43,8 +50,6 @@ def test_read_kea_lease(mock_swsscommon_dbconnector_init): kea_lease_handler = KeaDhcp4LeaseHandler(db_connector, lease_file="tests/test_data/kea-lease.csv") # Verify whether lease information read is as expected lease = kea_lease_handler._read() - print(lease) - print(expected_lease) assert lease == expected_lease @@ -52,9 +57,10 @@ def test_get_fdb_info(mock_swsscommon_dbconnector_init): mock_fdb_table = { "Vlan2000:10:70:fd:b6:13:15": {"port": "Ethernet31", "type": "dynamic"}, "Vlan1000:10:70:fd:b6:13:00": {"port": "Ethernet32", "type": "dynamic"}, - "Vlan1000:10:70:fd:b6:13:17": {"port": "Ethernet32", "type": "dynamic"} + "Vlan1000:10:70:fd:b6:13:17": {"port": "Ethernet33", "type": "dynamic"}, + "Vlan1000:10:70:fd:b6:13:18": {"port": "Ethernet34", "type": "dynamic"} } - with patch("dhcp_server.dhcp_server_utils.DhcpDbConnector.get_state_db_table", return_value=mock_fdb_table): + with patch("dhcp_server.common.utils.DhcpDbConnector.get_state_db_table", return_value=mock_fdb_table): db_connector = DhcpDbConnector() kea_lease_handler = KeaDhcp4LeaseHandler(db_connector, lease_file="tests/test_data/kea-lease.csv") # Verify whether lease information read is as expected @@ -62,13 +68,21 @@ def test_get_fdb_info(mock_swsscommon_dbconnector_init): assert fdb_info == expected_fdb_info +# Cannot mock built-in/extension type function(datetime.datetime.timestamp), need to free time +@freeze_time("2023-09-08") def test_update_kea_lease(mock_swsscommon_dbconnector_init, mock_swsscommon_table_init): tested_lease = expected_lease + mock_lease_table = { + "Vlan1000|aa:bb:cc:dd:ee:ff": {}, + "Vlan1000|10:70:fd:b6:13:00": {}, + "Vlan1000|10:70:fd:b6:13:17": {}, + "Vlan1000|10:70:fd:b6:13:18": {} + } with patch.object(swsscommon.Table, "getKeys"), \ patch.object(swsscommon.DBConnector, "hset") as mock_hset, \ patch.object(KeaDhcp4LeaseHandler, "_read", MagicMock(return_value=tested_lease)), \ patch.object(DhcpDbConnector, "get_state_db_table", - return_value={"Vlan1000|aa:bb:cc:dd:ee:ff": {}, "Vlan1000|10:70:fd:b6:13:00": {}}), \ + return_value=mock_lease_table), \ patch.object(swsscommon.DBConnector, "delete") as mock_delete, \ patch("time.sleep", return_value=None) as mock_sleep: db_connector = DhcpDbConnector() @@ -77,14 +91,15 @@ def test_update_kea_lease(mock_swsscommon_dbconnector_init, mock_swsscommon_tabl # Verify that old key was deleted mock_delete.assert_has_calls([ call("DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:00"), + call("DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:17"), call("DHCP_SERVER_IPV4_LEASE|Vlan1000|aa:bb:cc:dd:ee:ff") ]) # Verify that lease has been updated, to be noted that lease for "192.168.0.2" didn't been updated because # lease_start equals to lease_end mock_hset.assert_has_calls([ - call('DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:17', 'lease_start', '1693997315'), - call('DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:17', 'lease_end', '1694000915'), - call('DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:17', 'ip', '192.168.0.131') + call("DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:18", "lease_start", "1697607205"), + call("DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:18", "lease_end", "1697610805"), + call("DHCP_SERVER_IPV4_LEASE|Vlan1000|10:70:fd:b6:13:18", "ip", "193.168.0.132") ]) kea_lease_handler.update_lease() mock_sleep.assert_called_once_with(2) diff --git a/src/sonic-dhcp-server/tests/test_dhcprelayd.py b/src/sonic-dhcp-server/tests/test_dhcprelayd.py new file mode 100644 index 000000000000..d7f4f5f85c87 --- /dev/null +++ b/src/sonic-dhcp-server/tests/test_dhcprelayd.py @@ -0,0 +1,129 @@ +import psutil +import pytest +import subprocess +import sys +import time +from common_utils import mock_get_config_db_table, MockProc, MockPopen +from dhcp_server.common.utils import DhcpDbConnector +from dhcp_server.dhcprelayd.dhcprelayd import DhcpRelayd, KILLED_OLD, NOT_KILLED, NOT_FOUND_PROC +from dhcp_server.common.dhcp_db_monitor import DhcpRelaydDbMonitor +from swsscommon import swsscommon +from unittest.mock import patch, call + + +def test_start(mock_swsscommon_dbconnector_init): + with patch.object(DhcpRelayd, "refresh_dhcrelay", return_value=None) as mock_refresh, \ + patch.object(DhcpRelaydDbMonitor, "subscribe_table", return_value=None) as mock_subscribe: + dhcp_db_connector = DhcpDbConnector() + dhcprelayd = DhcpRelayd(dhcp_db_connector) + dhcprelayd.start() + mock_refresh.assert_called_once_with() + mock_subscribe.assert_called_once_with() + + +def test_refresh_dhcrelay(mock_swsscommon_dbconnector_init): + with patch.object(DhcpRelayd, "_get_dhcp_server_ip", return_value="240.127.1.2"), \ + patch.object(DhcpDbConnector, "get_config_db_table", side_effect=mock_get_config_db_table), \ + patch.object(DhcpRelayd, "_start_dhcrelay_process", return_value=None), \ + patch.object(DhcpRelayd, "_start_dhcpmon_process", return_value=None): + dhcp_db_connector = DhcpDbConnector() + dhcprelayd = DhcpRelayd(dhcp_db_connector) + dhcprelayd.refresh_dhcrelay() + + +@pytest.mark.parametrize("new_dhcp_interfaces", [[], ["Vlan1000"], ["Vlan1000", "Vlan2000"]]) +@pytest.mark.parametrize("kill_res", [KILLED_OLD, NOT_KILLED, NOT_FOUND_PROC]) +@pytest.mark.parametrize("proc_status", [psutil.STATUS_ZOMBIE, psutil.STATUS_RUNNING]) +def test_start_dhcrelay_process(mock_swsscommon_dbconnector_init, new_dhcp_interfaces, kill_res, proc_status): + with patch.object(DhcpRelayd, "_kill_exist_relay_releated_process", return_value=kill_res), \ + patch.object(subprocess, "Popen", return_value=MockPopen(999)) as mock_popen, \ + patch.object(time, "sleep"), \ + patch("dhcp_server.dhcprelayd.dhcprelayd.terminate_proc", return_value=None) as mock_terminate, \ + patch.object(psutil.Process, "__init__", return_value=None), \ + patch.object(psutil.Process, "status", return_value=proc_status), \ + patch.object(sys, "exit") as mock_exit: + dhcp_db_connector = DhcpDbConnector() + dhcprelayd = DhcpRelayd(dhcp_db_connector) + dhcprelayd._start_dhcrelay_process(new_dhcp_interfaces, "240.127.1.2", False) + if len(new_dhcp_interfaces) == 0 or kill_res == NOT_KILLED: + mock_popen.assert_not_called() + else: + call_param = ["/usr/sbin/dhcrelay", "-d", "-m", "discard", "-a", "%h:%p", "%P", "--name-alias-map-file", + "/tmp/port-name-alias-map.txt"] + for interface in new_dhcp_interfaces: + call_param += ["-id", interface] + call_param += ["-iu", "docker0", "240.127.1.2"] + mock_popen.assert_called_once_with(call_param) + if len(new_dhcp_interfaces) != 0 and kill_res != NOT_KILLED and proc_status == psutil.STATUS_ZOMBIE: + mock_terminate.assert_called_once() + mock_exit.assert_called_once_with(1) + else: + mock_terminate.assert_not_called() + mock_exit.assert_not_called() + + +@pytest.mark.parametrize("new_dhcp_interfaces_list", [[], ["Vlan1000"], ["Vlan1000", "Vlan2000"]]) +@pytest.mark.parametrize("kill_res", [KILLED_OLD, NOT_KILLED, NOT_FOUND_PROC]) +@pytest.mark.parametrize("proc_status", [psutil.STATUS_ZOMBIE, psutil.STATUS_RUNNING]) +def test_start_dhcpmon_process(mock_swsscommon_dbconnector_init, new_dhcp_interfaces_list, kill_res, proc_status): + new_dhcp_interfaces = set(new_dhcp_interfaces_list) + with patch.object(DhcpRelayd, "_kill_exist_relay_releated_process", return_value=kill_res), \ + patch.object(subprocess, "Popen", return_value=MockPopen(999)) as mock_popen, \ + patch.object(time, "sleep"), \ + patch("dhcp_server.dhcprelayd.dhcprelayd.terminate_proc", return_value=None) as mock_terminate, \ + patch.object(psutil.Process, "__init__", return_value=None), \ + patch.object(psutil.Process, "status", return_value=proc_status): + dhcp_db_connector = DhcpDbConnector() + dhcprelayd = DhcpRelayd(dhcp_db_connector) + dhcprelayd._start_dhcpmon_process(new_dhcp_interfaces, False) + if len(new_dhcp_interfaces) == 0 or kill_res == NOT_KILLED: + mock_popen.assert_not_called() + else: + calls = [] + for interface in new_dhcp_interfaces: + call_param = ["/usr/sbin/dhcpmon", "-id", interface, "-iu", "docker0", "-im", "eth0"] + calls.append(call(call_param)) + mock_popen.assert_has_calls(calls) + if len(new_dhcp_interfaces) != 0 and kill_res != NOT_KILLED and proc_status == psutil.STATUS_ZOMBIE: + mock_terminate.assert_called_once() + else: + mock_terminate.assert_not_called() + + +@pytest.mark.parametrize("new_dhcp_interfaces_list", [[], ["Vlan1000"], ["Vlan1000", "Vlan2000"]]) +@pytest.mark.parametrize("process_name", ["dhcrelay", "dhcpmon"]) +@pytest.mark.parametrize("running_procs", [[], ["dhcrelay"], ["dhcpmon"], ["dhcrelay", "dhcpmon"]]) +@pytest.mark.parametrize("force_kill", [True, False]) +def test_kill_exist_relay_releated_process(mock_swsscommon_dbconnector_init, new_dhcp_interfaces_list, process_name, + running_procs, force_kill): + new_dhcp_interfaces = set(new_dhcp_interfaces_list) + process_iter_ret = [] + for running_proc in running_procs: + process_iter_ret.append(MockProc(running_proc)) + with patch.object(psutil, "process_iter", return_value=process_iter_ret): + dhcp_db_connector = DhcpDbConnector() + dhcprelayd = DhcpRelayd(dhcp_db_connector) + res = dhcprelayd._kill_exist_relay_releated_process(new_dhcp_interfaces, process_name, force_kill) + if force_kill and process_name in running_procs: + assert res == KILLED_OLD + elif new_dhcp_interfaces_list == ["Vlan1000"] and process_name in running_procs: + assert res == NOT_KILLED + elif process_name not in running_procs: + assert res == NOT_FOUND_PROC + elif new_dhcp_interfaces_list != ["Vlan1000"]: + assert res == KILLED_OLD + + +@pytest.mark.parametrize("get_res", [(1, "240.127.1.2"), (0, None)]) +def test_get_dhcp_server_ip(mock_swsscommon_dbconnector_init, mock_swsscommon_table_init, get_res): + with patch.object(swsscommon.Table, "hget", return_value=get_res), \ + patch.object(time, "sleep") as mock_sleep, \ + patch.object(sys, "exit") as mock_exit: + dhcp_db_connector = DhcpDbConnector() + dhcprelayd = DhcpRelayd(dhcp_db_connector) + ret = dhcprelayd._get_dhcp_server_ip() + if get_res[0] == 1: + assert ret == get_res[1] + else: + mock_exit.assert_called_once_with(1) + mock_sleep.assert_has_calls([call(10) for _ in range(10)]) diff --git a/src/sonic-dhcp-server/tests/test_dhcpservd.py b/src/sonic-dhcp-server/tests/test_dhcpservd.py index 08e3253a6b94..558d8cb879ce 100644 --- a/src/sonic-dhcp-server/tests/test_dhcpservd.py +++ b/src/sonic-dhcp-server/tests/test_dhcpservd.py @@ -1,15 +1,22 @@ import pytest import psutil import signal -from dhcp_server.dhcp_server_utils import DhcpDbConnector -from dhcp_server.dhcp_cfggen import DhcpServCfgGenerator -from dhcp_server.dhcpservd import DhcpServd +import sys +import time +from common_utils import MockProc +from dhcp_server.common.utils import DhcpDbConnector +from dhcp_server.dhcpservd.dhcp_cfggen import DhcpServCfgGenerator +from dhcp_server.dhcpservd.dhcpservd import DhcpServd +from swsscommon import swsscommon from unittest.mock import patch, call, MagicMock +AF_INET = 2 +AF_INET6 = 10 + def test_dump_dhcp4_config(mock_swsscommon_dbconnector_init): - with patch("dhcp_server.dhcp_cfggen.DhcpServCfgGenerator.generate", return_value="dummy_config") as mock_generate, \ - patch("dhcp_server.dhcpservd.DhcpServd._notify_kea_dhcp4_proc", MagicMock()) as mock_notify_kea_dhcp4_proc: + with patch("dhcp_server.dhcpservd.dhcp_cfggen.DhcpServCfgGenerator.generate", return_value="dummy_config") as mock_generate, \ + patch("dhcp_server.dhcpservd.dhcpservd.DhcpServd._notify_kea_dhcp4_proc", MagicMock()) as mock_notify_kea_dhcp4_proc: dhcp_db_connector = DhcpDbConnector() dhcp_cfg_generator = DhcpServCfgGenerator(dhcp_db_connector, port_map_path="tests/test_data/port-name-alias-map.txt", @@ -40,21 +47,45 @@ def test_notify_kea_dhcp4_proc(process_list, mock_swsscommon_dbconnector_init, m mock_send_signal.assert_not_called() +@pytest.mark.parametrize("mock_intf", [True, False]) +def test_update_dhcp_server_ip(mock_swsscommon_dbconnector_init, mock_parse_port_map_alias, mock_get_render_template, + mock_intf): + mock_interface = {} if not mock_intf else { + "eth0": [ + MockIntf(AF_INET6, "fd00::2"), + MockIntf(AF_INET, "240.127.1.2") + ] + } + with patch.object(psutil, "net_if_addrs", return_value=mock_interface), \ + patch.object(swsscommon.DBConnector, "hset") as mock_hset, \ + patch.object(time, "sleep") as mock_sleep, \ + patch.object(sys, "exit") as mock_exit: + dhcp_db_connector = DhcpDbConnector() + dhcp_cfg_generator = DhcpServCfgGenerator(dhcp_db_connector) + dhcpservd = DhcpServd(dhcp_cfg_generator, dhcp_db_connector) + dhcpservd._update_dhcp_server_ip() + if mock_intf: + mock_hset.assert_has_calls([ + call("DHCP_SERVER_IPV4_SERVER_IP|eth0", "ip", "240.127.1.2") + ]) + else: + mock_hset.assert_not_called() + mock_exit.assert_called_once_with(1) + mock_sleep.assert_has_calls([call(5) for _ in range(10)]) + + def test_start(mock_swsscommon_dbconnector_init, mock_parse_port_map_alias, mock_get_render_template): - with patch.object(DhcpServd, "dump_dhcp4_config") as mock_dump: + with patch.object(DhcpServd, "dump_dhcp4_config") as mock_dump, \ + patch.object(DhcpServd, "_update_dhcp_server_ip") as mock_update_dhcp_server_ip: dhcp_db_connector = DhcpDbConnector() dhcp_cfg_generator = DhcpServCfgGenerator(dhcp_db_connector) dhcpservd = DhcpServd(dhcp_cfg_generator, dhcp_db_connector) dhcpservd.start() mock_dump.assert_called_once_with() + mock_update_dhcp_server_ip.assert_called_once_with() -class MockProc(object): - def __init__(self, name): - self.proc_name = name - - def name(self): - return self.proc_name - - def send_signal(self, sig_num): - pass +class MockIntf(object): + def __init__(self, family, address): + self.family = family + self.address = address diff --git a/src/sonic-dhcp-server/tests/test_dhcp_server_utils.py b/src/sonic-dhcp-server/tests/test_utils.py similarity index 86% rename from src/sonic-dhcp-server/tests/test_dhcp_server_utils.py rename to src/sonic-dhcp-server/tests/test_utils.py index 7b7857265acb..6acc39115bee 100644 --- a/src/sonic-dhcp-server/tests/test_dhcp_server_utils.py +++ b/src/sonic-dhcp-server/tests/test_utils.py @@ -1,4 +1,4 @@ -import dhcp_server.dhcp_server_utils as dhcp_server_utils +import dhcp_server.common.utils as utils import ipaddress import pytest from swsscommon import swsscommon @@ -29,7 +29,7 @@ def test_construct_without_sock(mock_swsscommon_dbconnector_init): - dhcp_server_utils.DhcpDbConnector() + utils.DhcpDbConnector() mock_swsscommon_dbconnector_init.assert_has_calls([ call(swsscommon.CONFIG_DB, "127.0.0.1", 6379, 0), call(swsscommon.STATE_DB, "127.0.0.1", 6379, 0) @@ -38,7 +38,7 @@ def test_construct_without_sock(mock_swsscommon_dbconnector_init): def test_construct_sock(mock_swsscommon_dbconnector_init): redis_sock = "/var/run/redis/redis.sock" - dhcp_db_connector = dhcp_server_utils.DhcpDbConnector(redis_sock=redis_sock) + dhcp_db_connector = utils.DhcpDbConnector(redis_sock=redis_sock) assert dhcp_db_connector.redis_sock == redis_sock mock_swsscommon_dbconnector_init.assert_has_calls([ @@ -48,15 +48,13 @@ def test_construct_sock(mock_swsscommon_dbconnector_init): def test_get_config_db_table(mock_swsscommon_dbconnector_init, mock_swsscommon_table_init): - dhcp_db_connector = dhcp_server_utils.DhcpDbConnector() + dhcp_db_connector = utils.DhcpDbConnector() with patch.object(swsscommon.Table, "getKeys", return_value=["key1", "key2"]) as mock_get_keys, \ - patch.object(dhcp_server_utils, "get_entry", return_value={"list": "1,2", "value": "3,4"}), \ + patch.object(utils, "get_entry", return_value={"list": "1,2", "value": "3,4"}), \ patch.object(swsscommon.Table, "hget", side_effect=mock_hget): ret = dhcp_db_connector.get_config_db_table("VLAN") mock_swsscommon_table_init.assert_called_once_with(dhcp_db_connector.config_db, "VLAN") - print(ret) mock_get_keys.assert_called_once_with() - print(ret) assert ret == { "key1": {"list": ["1", "2"], "value": "3,4"}, "key2": {"list": ["1", "2"], "value": "3,4"} @@ -67,7 +65,7 @@ def test_get_config_db_table(mock_swsscommon_dbconnector_init, mock_swsscommon_t def test_merge_intervals(test_type): intervals = convert_ip_address_intervals(interval_test_data[test_type]["intervals"]) expected_res = convert_ip_address_intervals(interval_test_data[test_type]["expected_res"]) - assert dhcp_server_utils.merge_intervals(intervals) == expected_res + assert utils.merge_intervals(intervals) == expected_res def mock_hget(_, field): From 341de0a042af9d96de4137eb720c2af405565ea1 Mon Sep 17 00:00:00 2001 From: yaqiangz Date: Fri, 3 Nov 2023 06:08:34 +0000 Subject: [PATCH 10/10] Fix ut failed in because internal repo has dnsmasq --- .../docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 | 2 +- .../py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 index d521be4dcb05..82e81183faa6 100644 --- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -57,7 +57,7 @@ dependent_startup_wait_for=rsyslogd:running {% endif %} {% endfor %} -{% if 'dhcp_server' in DEVICE_METADATA['localhost'] and 'enable' in DEVICE_METADATA['localhost']['dhcp_server'] %} +{% if not dhcp_server_ipv4_enabled and 'dhcp_server' in DEVICE_METADATA['localhost'] and 'enable' in DEVICE_METADATA['localhost']['dhcp_server'] %} [group:dhcp-server] programs=dnsmasq,host-monitor diff --git a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf index 350e302ce9e1..4aaa29d19eae 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-enable-dhcp-server.supervisord.conf @@ -39,6 +39,10 @@ stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=rsyslogd:running + +[group:dhcp-server] +programs= + [group:dhcp-relay] programs=dhcprelayd,dhcp6relay