From 081741b24a7f6903e4ec2e69d924d17313d54f45 Mon Sep 17 00:00:00 2001 From: Anant <127479400+AnantKishorSharma@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:13:17 +0530 Subject: [PATCH 1/2] [dhcp_relay] sonic dhcp relay agent for IPv4 (#22486) Why I did it Currently SONiC uses the 'isc-dhcp-relay' package to allow DHCP relay functionality on IPv4 networks. With this PR we are adding sonic dhcp relay agent for IPv4 as described in this HLD(sonic-net/SONiC#1938) Work item tracking Microsoft ADO (number only): How I did it Edit supervisord template to start sonic DHCPv4 relay instance when configured to do so in Config DB. Align cfg unit test to the new change. How to verify it Configure sonic DHCPv4 agent as described in the feature HLD(sonic-net/SONiC#1938) Test it with real client/server with IPv4 or use the sonic-mgmt suite Signed-off-by: Ashutosh Agrawal Co-authored-by: Shivashankar C R Co-authored-by: Ashutosh Agrawal Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: StormLiangMS <89824293+StormLiangMS@users.noreply.github.com> --- dockers/docker-dhcp-relay/Dockerfile.j2 | 5 +- .../docker-dhcp-relay/dhcp-relay.monitors.j2 | 4 + .../docker-dhcp-relay/dhcp-relay.programs.j2 | 22 + .../dhcpv4-sonic-relay.agents.j2 | 15 + .../docker-dhcp-relay.supervisord.conf.j2 | 14 + rules/dhcp4relay.dep | 11 + rules/dhcp4relay.mk | 12 + rules/docker-dhcp-relay.dep | 2 +- rules/docker-dhcp-relay.mk | 4 +- .../dhcp-sonic-relay-disabled-sample.json | 27 + .../dhcp-sonic-relay-enabled-sample.json | 26 + ...-sonic-agent-no-relay-cfg.supervisord.conf | 74 ++ ...er-dhcp-relay-sonic-agent.supervisord.conf | 110 +++ ...-sonic-agent-no-relay-cfg.supervisord.conf | 74 ++ ...er-dhcp-relay-sonic-agent.supervisord.conf | 110 +++ .../tests/t0-sonic-dhcp4relay-graph.xml | 928 ++++++++++++++++++ src/sonic-config-engine/tests/test_j2files.py | 28 + .../dhcp_utilities/dhcprelayd/dhcprelayd.py | 4 +- .../yang-models/sonic-device_metadata.yang | 6 + 19 files changed, 1470 insertions(+), 6 deletions(-) create mode 100644 dockers/docker-dhcp-relay/dhcpv4-sonic-relay.agents.j2 create mode 100644 rules/dhcp4relay.dep create mode 100644 rules/dhcp4relay.mk create mode 100644 src/sonic-config-engine/tests/dhcp-sonic-relay-disabled-sample.json create mode 100644 src/sonic-config-engine/tests/dhcp-sonic-relay-enabled-sample.json create mode 100644 src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf create mode 100644 src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent.supervisord.conf create mode 100644 src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf create mode 100644 src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent.supervisord.conf create mode 100644 src/sonic-config-engine/tests/t0-sonic-dhcp4relay-graph.xml diff --git a/dockers/docker-dhcp-relay/Dockerfile.j2 b/dockers/docker-dhcp-relay/Dockerfile.j2 index 01213a405cb..c364858becc 100644 --- a/dockers/docker-dhcp-relay/Dockerfile.j2 +++ b/dockers/docker-dhcp-relay/Dockerfile.j2 @@ -14,7 +14,8 @@ RUN apt-get update RUN apt-get install -y libjsoncpp-dev \ python3-dev \ - build-essential + build-essential \ + libpcap-dev RUN pip3 install psutil @@ -40,7 +41,7 @@ RUN apt-get remove -y build-essential \ COPY ["docker_init.sh", "start.sh", "/usr/bin/"] COPY ["docker-dhcp-relay.supervisord.conf.j2", "port-name-alias-map.txt.j2", "wait_for_intf.sh.j2", "/usr/share/sonic/templates/"] -COPY ["dhcp-relay.programs.j2", "dhcpv4-relay.agents.j2", "dhcpv6-relay.agents.j2", "dhcp-relay.monitors.j2", "/usr/share/sonic/templates/"] +COPY ["dhcp-relay.programs.j2", "dhcpv4-relay.agents.j2", "dhcpv4-sonic-relay.agents.j2", "dhcpv6-relay.agents.j2", "dhcp-relay.monitors.j2", "/usr/share/sonic/templates/"] COPY ["critical_processes", "/etc/supervisor"] COPY ["cli", "/cli/"] diff --git a/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2 b/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2 index e63c4fb0c19..56692523f93 100644 --- a/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2 +++ b/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2 @@ -49,6 +49,10 @@ stdout_syslog=true stderr_logfile=NONE stderr_syslog=true dependent_startup=true +{% if 'has_sonic_dhcpv4_relay' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['has_sonic_dhcpv4_relay'] == 'True' %} +dependent_startup_wait_for=dhcp4relay:running +{% else %} dependent_startup_wait_for=isc-dhcpv4-relay-{{ vlan_name }}:running +{% endif %} {% endfor %} diff --git a/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 b/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 index 087a734d6f8..73b12060453 100644 --- a/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 +++ b/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 @@ -1,5 +1,6 @@ [group:dhcp-relay] programs=dhcprelayd +{%- if 'has_sonic_dhcpv4_relay' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['has_sonic_dhcpv4_relay'] == 'True' %} {%- set relay_for_ipv6 = { 'flag': False } %} {%- set add_preceding_comma = { 'flag': True } %} {% for vlan_name in VLAN_INTERFACE %} @@ -12,4 +13,25 @@ programs=dhcprelayd {% if add_preceding_comma.flag %},{% endif %} {% set _dummy = add_preceding_comma.update({'flag': True}) %} dhcp6relay +{%- endif %} +{# Create a program entry for sonic dhcpv4 relay agent #} +{%- set add_preceding_comma = { 'flag': True } %} +{# Append sonic DHCPv4 agent #} +{% if add_preceding_comma.flag %},{% endif %} +{% set _dummy = add_preceding_comma.update({'flag': True}) %} +dhcp4relay +{% else %} +{%- set relay_for_ipv6 = { 'flag': False } %} +{%- set add_preceding_comma = { 'flag': True } %} +{% for vlan_name in VLAN_INTERFACE %} +{% if DHCP_RELAY and vlan_name in DHCP_RELAY and DHCP_RELAY[vlan_name]['dhcpv6_servers']|length > 0 %} +{% set _dummy = relay_for_ipv6.update({'flag': True}) %} +{%- endif %} +{% endfor %} +{# Append DHCPv6 agents #} +{% if relay_for_ipv6.flag %} +{% if add_preceding_comma.flag %},{% endif %} +{% set _dummy = add_preceding_comma.update({'flag': True}) %} +dhcp6relay +{% endif %} {% endif %} diff --git a/dockers/docker-dhcp-relay/dhcpv4-sonic-relay.agents.j2 b/dockers/docker-dhcp-relay/dhcpv4-sonic-relay.agents.j2 new file mode 100644 index 00000000000..1b40615b31f --- /dev/null +++ b/dockers/docker-dhcp-relay/dhcpv4-sonic-relay.agents.j2 @@ -0,0 +1,15 @@ +{# Append DHCPv4 sonic agent #} +[program:dhcp4relay] +command=/usr/sbin/dhcp4relay{% if 'subtype' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['subtype'] == 'DualToR' %} -u Loopback0{% endif %} + +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + + 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 a4a983ea1fb..696b410f64d 100644 --- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -48,6 +48,9 @@ dependent_startup_wait_for=rsyslogd:running {# Count how many VLANs require a DHCP relay agent... #} {% set ipv4_num_relays = { 'count': 0 } %} {% set ipv6_num_relays = { 'count': 0 } %} +{% if 'has_sonic_dhcpv4_relay' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['has_sonic_dhcpv4_relay'] == 'True' %} +{% set _dummy = ipv4_num_relays.update({'count': ipv4_num_relays.count + 1}) %} +{% endif %} {% for vlan_name in VLAN_INTERFACE %} {% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %} {% set _dummy = ipv4_num_relays.update({'count': ipv4_num_relays.count + 1}) %} @@ -63,6 +66,12 @@ dependent_startup_wait_for=rsyslogd:running {# Create a program entry for each DHCP relay agent instance #} {% set relay_for_ipv4 = { 'flag': False } %} {% set relay_for_ipv6 = { 'flag': False } %} +{# Decide the dhcpv4 relay agent based on the feature config #} +{% if 'has_sonic_dhcpv4_relay' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['has_sonic_dhcpv4_relay'] == 'True' %} +{% include 'dhcpv4-sonic-relay.agents.j2' %} +{% include 'dhcpv6-relay.agents.j2' %} +{% include 'dhcp-relay.monitors.j2' %} +{% else %} {% set added_vlan = []%} {% for (vlan_name, prefix) in VLAN_INTERFACE|pfx_filter %} {%- if prefix | ipv4 and vlan_name not in added_vlan %} @@ -75,6 +84,11 @@ dependent_startup_wait_for=rsyslogd:running {% include 'dhcp-relay.monitors.j2' %} {% endif %} {% endif %} +{% else %} +{% if 'has_sonic_dhcpv4_relay' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['has_sonic_dhcpv4_relay'] == 'True' %} +{% include 'dhcpv4-sonic-relay.agents.j2' %} +{% endif %} +{% endif %} [program:dhcprelayd] command=/usr/local/bin/dhcprelayd priority=3 diff --git a/rules/dhcp4relay.dep b/rules/dhcp4relay.dep new file mode 100644 index 00000000000..223ff58e97e --- /dev/null +++ b/rules/dhcp4relay.dep @@ -0,0 +1,11 @@ + +SPATH := $($(SONIC_DHCP4RELAY)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/dhcp4relay.mk rules/dhcp4relay.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files --recurse-submodules)) + +$(SONIC_DHCP4RELAY)_CACHE_MODE := GIT_CONTENT_SHA +$(SONIC_DHCP4RELAY)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(SONIC_DHCP4RELAY)_DEP_FILES := $(DEP_FILES) +$(SONIC_DHCP4RELAY)_SMDEP_FILES := $(SMDEP_FILES) +$(SONIC_DHCP4RELAY)_SMDEP_PATHS := $(SPATH) diff --git a/rules/dhcp4relay.mk b/rules/dhcp4relay.mk new file mode 100644 index 00000000000..d365a3361da --- /dev/null +++ b/rules/dhcp4relay.mk @@ -0,0 +1,12 @@ +# SONiC DHCPV4 RELAY Package + +SONIC_DHCP4RELAY_VERSION = 1.0.0-0 +SONIC_DHCP4RELAY_PKG_NAME = dhcp4relay + +SONIC_DHCP4RELAY = sonic-$(SONIC_DHCP4RELAY_PKG_NAME)_$(SONIC_DHCP4RELAY_VERSION)_$(CONFIGURED_ARCH).deb +$(SONIC_DHCP4RELAY)_DEPENDS = $(LIBSWSSCOMMON) $(LIBSWSSCOMMON_DEV) +$(SONIC_DHCP4RELAY)_SRC_PATH = $(SRC_PATH)/dhcprelay/dhcp4relay +SONIC_DPKG_DEBS += $(SONIC_DHCP4RELAY) + +SONIC_DHCP4RELAY_DBG = sonic-$(SONIC_DHCP4RELAY_PKG_NAME)-dbgsym_$(SONIC_DHCP4RELAY_VERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(SONIC_DHCP4RELAY),$(SONIC_DHCP4RELAY_DBG))) diff --git a/rules/docker-dhcp-relay.dep b/rules/docker-dhcp-relay.dep index 996e346da98..726dbaa095d 100644 --- a/rules/docker-dhcp-relay.dep +++ b/rules/docker-dhcp-relay.dep @@ -1,6 +1,6 @@ DPATH := $($(DOCKER_DHCP_RELAY)_PATH) -DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/docker-dhcp-relay.mk rules/docker-dhcp-relay.dep +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/docker-dhcp-relay.mk rules/docker-dhcp-relay.dep DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) DEP_FILES += $(shell git ls-files $(DPATH)) diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk index 8b3be4c3630..0bbc3603aed 100644 --- a/rules/docker-dhcp-relay.mk +++ b/rules/docker-dhcp-relay.mk @@ -6,10 +6,10 @@ DOCKER_DHCP_RELAY_DBG = $(DOCKER_DHCP_RELAY_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_DHCP_RELAY)_PATH = $(DOCKERS_PATH)/$(DOCKER_DHCP_RELAY_STEM) -$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(SONIC_DHCPMON) $(SONIC_DHCPRELAY) $(LIBSWSSCOMMON) +$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(SONIC_DHCPMON) $(SONIC_DHCP4RELAY) $(SONIC_DHCPRELAY) $(LIBSWSSCOMMON) $(DOCKER_DHCP_RELAY)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) -$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCPRELAY_DBG) $(SONIC_DHCPMON_DBG) +$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCP4RELAY_DBG) $(SONIC_DHCPRELAY_DBG) $(SONIC_DHCPMON_DBG) $(DOCKER_DHCP_RELAY)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_IMAGE_PACKAGES) diff --git a/src/sonic-config-engine/tests/dhcp-sonic-relay-disabled-sample.json b/src/sonic-config-engine/tests/dhcp-sonic-relay-disabled-sample.json new file mode 100644 index 00000000000..d331f884350 --- /dev/null +++ b/src/sonic-config-engine/tests/dhcp-sonic-relay-disabled-sample.json @@ -0,0 +1,27 @@ +{ + "VLAN_INTERFACE": { + "Vlan1000|fc02:2000::2/24": {} + }, + "FEATURE": { + "dhcp_server": { + "state": "disabled" + }, + "dhcp_relay": { + "auto_restart": "disabled", + "check_up_status": "False", + "delayed": "False", + "has_global_scope": "True", + "has_per_asic_scope": "False", + "high_mem_alert": "disabled", + "set_owner": "local", + "state": "enabled", + "support_syslog_rate_limit": "True" + } + + }, + "DEVICE_METADATA": { + "localhost": { + "has_sonic_dhcpv4_relay": "False" + } + } +} diff --git a/src/sonic-config-engine/tests/dhcp-sonic-relay-enabled-sample.json b/src/sonic-config-engine/tests/dhcp-sonic-relay-enabled-sample.json new file mode 100644 index 00000000000..8749df0eb42 --- /dev/null +++ b/src/sonic-config-engine/tests/dhcp-sonic-relay-enabled-sample.json @@ -0,0 +1,26 @@ +{ + "VLAN_INTERFACE": { + "Vlan1000|fc02:2000::2/24": {} + }, + "FEATURE": { + "dhcp_server": { + "state": "disabled" + }, + "dhcp_relay": { + "auto_restart": "disabled", + "check_up_status": "False", + "delayed": "False", + "has_global_scope": "True", + "has_per_asic_scope": "False", + "high_mem_alert": "disabled", + "set_owner": "local", + "state": "enabled", + "support_syslog_rate_limit": "True" + } + }, + "DEVICE_METADATA": { + "localhost": { + "has_sonic_dhcpv4_relay": "True" + } + } +} diff --git a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf new file mode 100644 index 00000000000..2598ee08f06 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf @@ -0,0 +1,74 @@ +[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-rs --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=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true + +[program:start] +command=/usr/bin/start.sh +priority=2 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[group:dhcp-relay] +programs=dhcprelayd,dhcp4relay + +[program:dhcp4relay] +command=/usr/sbin/dhcp4relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + +[group:dhcpmon] +programs= + +[program:dhcprelayd] +command=/usr/local/bin/dhcprelayd +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited diff --git a/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent.supervisord.conf new file mode 100644 index 00000000000..25699495307 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py2/docker-dhcp-relay-sonic-agent.supervisord.conf @@ -0,0 +1,110 @@ +[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-rs --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=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true + +[program:start] +command=/usr/bin/start.sh +priority=2 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[group:dhcp-relay] +programs=dhcprelayd,dhcp6relay,dhcp4relay + +[program:dhcp4relay] +command=/usr/sbin/dhcp4relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + +[program:dhcp6relay] +command=/usr/sbin/dhcp6relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + +[group:dhcpmon] +programs=dhcpmon-Vlan1000,dhcpmon-Vlan2000 + +[program:dhcpmon-Vlan1000] +command=/usr/sbin/dhcpmon -id Vlan1000 -iu Vlan2000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -im eth0 +priority=4 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=dhcp4relay:running + +[program:dhcpmon-Vlan2000] +command=/usr/sbin/dhcpmon -id Vlan2000 -iu Vlan1000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -im eth0 +priority=4 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=dhcp4relay:running + +[program:dhcprelayd] +command=/usr/local/bin/dhcprelayd +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited diff --git a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf new file mode 100644 index 00000000000..2598ee08f06 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent-no-relay-cfg.supervisord.conf @@ -0,0 +1,74 @@ +[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-rs --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=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true + +[program:start] +command=/usr/bin/start.sh +priority=2 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[group:dhcp-relay] +programs=dhcprelayd,dhcp4relay + +[program:dhcp4relay] +command=/usr/sbin/dhcp4relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + +[group:dhcpmon] +programs= + +[program:dhcprelayd] +command=/usr/local/bin/dhcprelayd +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited diff --git a/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent.supervisord.conf b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent.supervisord.conf new file mode 100644 index 00000000000..25699495307 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py3/docker-dhcp-relay-sonic-agent.supervisord.conf @@ -0,0 +1,110 @@ +[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-rs --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=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true + +[program:start] +command=/usr/bin/start.sh +priority=2 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + +[group:dhcp-relay] +programs=dhcprelayd,dhcp6relay,dhcp4relay + +[program:dhcp4relay] +command=/usr/sbin/dhcp4relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + +[program:dhcp6relay] +command=/usr/sbin/dhcp6relay +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited + +[group:dhcpmon] +programs=dhcpmon-Vlan1000,dhcpmon-Vlan2000 + +[program:dhcpmon-Vlan1000] +command=/usr/sbin/dhcpmon -id Vlan1000 -iu Vlan2000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -im eth0 +priority=4 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=dhcp4relay:running + +[program:dhcpmon-Vlan2000] +command=/usr/sbin/dhcpmon -id Vlan2000 -iu Vlan1000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -im eth0 +priority=4 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=dhcp4relay:running + +[program:dhcprelayd] +command=/usr/local/bin/dhcprelayd +priority=3 +autostart=false +autorestart=false +stdout_logfile=NONE +stdout_syslog=true +stderr_logfile=NONE +stderr_syslog=true +dependent_startup=true +dependent_startup_wait_for=start:exited diff --git a/src/sonic-config-engine/tests/t0-sonic-dhcp4relay-graph.xml b/src/sonic-config-engine/tests/t0-sonic-dhcp4relay-graph.xml new file mode 100644 index 00000000000..f04caec742e --- /dev/null +++ b/src/sonic-config-engine/tests/t0-sonic-dhcp4relay-graph.xml @@ -0,0 +1,928 @@ + + + + + + switch-t0 + 10.1.0.32 + BGPMonitor + 10.20.30.40 + 30 + 10 + 3 + + + false + switch-t0 + 10.0.0.56 + ARISTA01T1 + 10.0.0.57 + 1 + 180 + 60 + + + switch-t0 + FC00::71 + ARISTA01T1 + FC00::72 + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.58 + ARISTA02T1 + 10.0.0.59 + 1 + 180 + 60 + + + switch-t0 + FC00::75 + ARISTA02T1 + FC00::76 + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.60 + ARISTA03T1 + 10.0.0.61 + 1 + 180 + 60 + + + switch-t0 + FC00::79 + ARISTA03T1 + FC00::7A + 1 + 180 + 60 + + + false + switch-t0 + 10.0.0.62 + ARISTA04T1 + 10.0.0.63 + 1 + 180 + 60 + + + switch-t0 + FC00::7D + ARISTA04T1 + FC00::7E + 1 + 180 + 60 + + + + + 1 + + BGPMonitor + + + BGPPeer +
10.1.0.32
+ + + +
+
+ +
+ + 65100 + switch-t0 + + +
10.0.0.57
+ + + +
+ +
10.0.0.59
+ + + +
+ +
10.0.0.61
+ + + +
+ +
10.0.0.63
+ + + +
+
+ +
+ + 64600 + ARISTA01T1 + + + + 64600 + ARISTA02T1 + + + + 64600 + ARISTA03T1 + + + + 64600 + ARISTA04T1 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + HostIP1 + Loopback0 + + FC00:1::32/128 + + FC00:1::32/128 + + + LoopbackIP1 + Loopback1 + + 10.10.0.99/32 + + 10.10.0.99/32 + + + LoopbackIP2 + Loopback2 + + 10.21.0.64/32 + + 10.21.0.64/32 + + + LoopbackIP3 + Loopback3 + + 10.21.64.2/32 + + 10.21.64.2/32 + + + + + HostIP + eth0 + + 10.0.0.100/24 + + 10.0.0.100/24 + + + HostIP + eth0 + + 2603:10e2:0:2902::8/64 + + 2603:10e2:0:2902::8/64 + + + + + + + switch-t0 + + + PortChannel01 + fortyGigE0/112 + + + + PortChannel02 + fortyGigE0/116 + + + + PortChannel03 + fortyGigE0/120 + + + + PortChannel04 + fortyGigE0/124 + + + + + + Vlan1000 + fortyGigE0/4;fortyGigE0/8;fortyGigE0/12;fortyGigE0/16;fortyGigE0/20;fortyGigE0/24;fortyGigE0/28;fortyGigE0/32;fortyGigE0/36;fortyGigE0/40;fortyGigE0/44;fortyGigE0/48;fortyGigE0/52;fortyGigE0/56;fortyGigE0/60;fortyGigE0/64;fortyGigE0/68;fortyGigE0/72;fortyGigE0/76;fortyGigE0/80;fortyGigE0/84;fortyGigE0/88;fortyGigE0/92;fortyGigE0/96 + True + + + 1000 + 1000 + 192.168.0.0/27 + + + + + Vlan2000 + PortChannel01;PortChannel02;PortChannel03 + True + + + 2000 + 2000 + 192.168.200.0/27 + + + + + Vlan99 + fortyGigE0/100 + True + + UserDefinedL2Vlan + 99 + 99 + + + + + + Vlan98 + fortyGigE0/100;PortChannel01;PortChannel03 + True + + UserDefinedL2Vlan + 98 + 98 + + + + + + + + + PortChannel01 + 10.0.0.56/31 + + + + PortChannel01 + FC00::71/126 + + + + PortChannel02 + 10.0.0.58/31 + + + + PortChannel02 + FC00::75/126 + + + + PortChannel03 + 10.0.0.60/31 + + + + PortChannel03 + FC00::79/126 + + + + PortChannel04 + 10.0.0.62/31 + + + + PortChannel04 + FC00::7D/126 + + + + Vlan1000 + 192.168.0.1/27 + + + + Vlan2000 + 192.168.200.1/27 + + + + + + ERSPAN + everflow + Everflow + + + ERSPANv6 + everflowV6 + Everflow + + + EGRESS_ERSPAN + everflow_egress + Everflow + + + PortChannel01;PortChannel02;PortChannel03;PortChannel04 + DataAclIngress + DataPlane + + + PortChannel01;PortChannel02;Vlan98 + DataAclEgress + DataPlane + + + SNMP + SNMP_ACL + SNMP + + + NTP + NTP_ACL + NTP + + + SSH + SSH_ACL + SSH + + + SSH + ROUTER-PROTECT + SSH + + + SNMP + ROUTER-PROTECT + SNMP + + + NTP + NTP_ACL + + + + + + + + + + DeviceInterfaceLink + ARISTA01T1 + Ethernet1/1 + switch-t0 + fortyGigE0/112 + + + DeviceInterfaceLink + ARISTA02T1 + Ethernet1/1 + switch-t0 + fortyGigE0/116 + + + DeviceInterfaceLink + ARISTA03T1 + Ethernet1/1 + switch-t0 + fortyGigE0/120 + + + DeviceInterfaceLink + ARISTA04T1 + Ethernet1/1 + switch-t0 + fortyGigE0/124 + 100000 + + + DeviceInterfaceLink + 100000 + switch-t0 + fortyGigE0/4 + true + ARISTA05T1 + Ethernet1/33 + true + + + DeviceInterfaceLink + Servers0 + eth0 + switch-t0 + fortyGigE0/4 + + + DeviceInterfaceLink + Servers100 + eth0 + switch-t0 + fortyGigE0/100 + + + + + switch-t0 + Force10-S6000 + + + ARISTA01T1 + Arista + + + ARISTA02T1 + Arista + + + ARISTA03T1 + Arista + + + ARISTA04T1 + Arista + + + + + + + + DeviceInterface + + true + 1 + Ethernet0 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet8 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet12 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet16 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet20 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet24 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet28 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet32 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet36 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet40 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet44 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet48 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet52 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet56 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet60 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet64 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet68 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet72 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet76 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet80 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet84 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet88 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet92 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet96 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet100 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet104 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet108 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet112 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet116 + + false + 0 + 0 + 40000 + + + DeviceInterface + + true + 1 + Ethernet120 + + false + 0 + 0 + 40000 + + + Force10-S6000 + + + + + + + switch-t0 + + + ErspanDestinationIpv4 + + 2.2.2.2 + + + + + + + + + + + + + AutoNegotiation + + True + + + FECDisabled + + True + + + ARISTA05T1:Ethernet1/33;switch-t0:fortyGigE0/4 + + + + + + AutoNegotiation + + False + + + FECDisabled + + True + + + ARISTA06T1:Ethernet1/34;switch-t0:fortyGigE0/8 + + + + + + + switch-t0 + + + DeploymentId + + 1 + + + + + + + switch-t0 + Force10-S6000 +
diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index d1baf4a3e85..38665c7080f 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -29,6 +29,7 @@ def setUp(self): self.t0_minigraph_two_mgmt = os.path.join(self.test_dir, 't0-sample-graph-two-mgmt.xml') self.t0_mvrf_minigraph_nomgmt = os.path.join(self.test_dir, 't0-sample-graph-mvrf-nomgmt.xml') self.pc_minigraph = os.path.join(self.test_dir, 'pc-test-graph.xml') + self.sonic_dhcp4relay_minigraph = os.path.join(self.test_dir, 't0-sonic-dhcp4relay-graph.xml') self.t0_port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') self.t0_port_config_tiny = os.path.join(self.test_dir, 't0-sample-port-config-tiny.ini') self.t1_ss_port_config = os.path.join(self.test_dir, 't1-ss-sample-port-config.ini') @@ -193,6 +194,33 @@ def test_dhcp_relay(self): self.assertTrue(utils.cmp(os.path.join(self.test_dir, 'sample_output', utils.PYvX_DIR, 'docker-dhcp-relay-secondary-subnets.supervisord.conf'), self.output_file)) + # Test generation of docker-dhcp-relay.supervisord.conf when has_sonic_dhcpv4_relay is True and dhcp relay config is present + sample_data = os.path.join(self.test_dir, "dhcp-sonic-relay-enabled-sample.json") + template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', + 'docker-dhcp-relay.supervisord.conf.j2') + argument = ['-m', self.t0_minigraph, '-j', 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-sonic-agent.supervisord.conf'), self.output_file)) + + # Test generation of docker-dhcp-relay.supervisord.conf when has_sonic_dhcpv4_relay is True and dhcp relay config is not present + sample_data = os.path.join(self.test_dir, "dhcp-sonic-relay-enabled-sample.json") + template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', + 'docker-dhcp-relay.supervisord.conf.j2') + argument = ['-m', self.sonic_dhcp4relay_minigraph, '-j', 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-sonic-agent-no-relay-cfg.supervisord.conf'), self.output_file)) + + # Test generation of docker-dhcp-relay.supervisord.conf when has_sonic_dhcpv4_relay is False + sample_data = os.path.join(self.test_dir, "dhcp-sonic-relay-disabled-sample.json") + template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', + 'docker-dhcp-relay.supervisord.conf.j2') + argument = ['-m', self.t0_minigraph_common_dhcp_relay, '-j', 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)) + def test_radv(self): # Test generation of radvd.conf with multiple ipv6 prefixes template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-router-advertiser', 'radvd.conf.j2') diff --git a/src/sonic-dhcp-utilities/dhcp_utilities/dhcprelayd/dhcprelayd.py b/src/sonic-dhcp-utilities/dhcp_utilities/dhcprelayd/dhcprelayd.py index 208ab9a6c93..0dc608febca 100644 --- a/src/sonic-dhcp-utilities/dhcp_utilities/dhcprelayd/dhcprelayd.py +++ b/src/sonic-dhcp-utilities/dhcp_utilities/dhcprelayd/dhcprelayd.py @@ -108,7 +108,9 @@ def refresh_dhcrelay(self, force_kill=False): set([FEATURE_CHECKER, DHCP_SERVER_CHECKER]) self._disable_checkers(checkers_to_be_disabled) - self._start_dhcrelay_process(dhcp_interfaces, dhcp_server_ip, force_kill) + feature_table = self.db_connector.get_config_db_table("DEVICE_METADATA") + if feature_table.get("localhost", {}).get("has_sonic_dhcpv4_relay", "False") == "False": + self._start_dhcrelay_process(dhcp_interfaces, dhcp_server_ip, force_kill) # TODO dhcpmon is not ready for count packet for dhcp_server, hence comment invoke it for now # self._start_dhcpmon_process(dhcp_interfaces, force_kill) diff --git a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang index 9f5394113dc..cc12e587a77 100644 --- a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang +++ b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang @@ -330,6 +330,12 @@ module sonic-device_metadata { default "false"; } + leaf has_sonic_dhcpv4_relay { + description "This configuration controls the dhcpv4 relay process"; + type stypes:boolean_type; + default "false"; + } + leaf zebra_nexthop { description "Enable or disable next hop group support. This value only takes effect during boot time"; type enumeration { From 46b6c9cd055183505769b23e63bcff2afa8b12fb Mon Sep 17 00:00:00 2001 From: Ashutosh Agrawal Date: Wed, 18 Mar 2026 13:54:32 -0700 Subject: [PATCH 2/2] Update sonic-dhcp-relay submodule to include boost dependency fixes Signed-off-by: Ashutosh Agrawal --- src/dhcprelay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcprelay b/src/dhcprelay index 7c42d606e93..83c7e06c18f 160000 --- a/src/dhcprelay +++ b/src/dhcprelay @@ -1 +1 @@ -Subproject commit 7c42d606e934fb477214d0c04b16ef85a607c723 +Subproject commit 83c7e06c18f9727fc51ecc07a72705fd3de1af91