Skip to content

Commit 331c9de

Browse files
[config]: Dynamically start and stop ndppd (sonic-net#2814)
- When enabling proxy_arp for a VLAN, configure and start the ndppd service if it isn't already running - When removing the last VLAN, stop the ndppd service Signed-off-by: Lawrence Lee <[email protected]>
1 parent d1f307d commit 331c9de

File tree

2 files changed

+62
-11
lines changed

2 files changed

+62
-11
lines changed

config/vlan.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,24 @@ def del_vlan(db, vid, no_restart_dhcp_relay):
115115
# We need to restart dhcp_relay service after dhcpv6_relay config change
116116
if is_dhcp_relay_running():
117117
dhcp_relay_util.handle_restart_dhcp_relay_service()
118+
119+
vlans = db.cfgdb.get_keys('VLAN')
120+
if not vlans:
121+
docker_exec_cmd = "docker exec -i swss {}"
122+
_, rc = clicommon.run_command(docker_exec_cmd.format("supervisorctl status ndppd"), ignore_error=True, return_cmd=True)
123+
if rc == 0:
124+
click.echo("No VLANs remaining, stopping ndppd service")
125+
clicommon.run_command(docker_exec_cmd.format("supervisorctl stop ndppd"), ignore_error=True, return_cmd=True)
126+
clicommon.run_command(docker_exec_cmd.format("rm -f /etc/supervisor/conf.d/ndppd.conf"), ignore_error=True, return_cmd=True)
127+
clicommon.run_command(docker_exec_cmd.format("supervisorctl update"), return_cmd=True)
118128

119129

120130
def restart_ndppd():
121131
verify_swss_running_cmd = "docker container inspect -f '{{.State.Status}}' swss"
122132
docker_exec_cmd = "docker exec -i swss {}"
133+
ndppd_status_cmd= "supervisorctl status ndppd"
134+
ndppd_conf_copy_cmd = "cp /usr/share/sonic/templates/ndppd.conf /etc/supervisor/conf.d/"
135+
supervisor_update_cmd = "supervisorctl update"
123136
ndppd_config_gen_cmd = "sonic-cfggen -d -t /usr/share/sonic/templates/ndppd.conf.j2,/etc/ndppd.conf"
124137
ndppd_restart_cmd = "supervisorctl restart ndppd"
125138

@@ -129,9 +142,16 @@ def restart_ndppd():
129142
click.echo(click.style('SWSS container is not running, changes will take effect the next time the SWSS container starts', fg='red'),)
130143
return
131144

132-
clicommon.run_command(docker_exec_cmd.format(ndppd_config_gen_cmd), display_cmd=True)
145+
_, rc = clicommon.run_command(docker_exec_cmd.format(ndppd_status_cmd), ignore_error=True, return_cmd=True)
146+
147+
if rc != 0:
148+
clicommon.run_command(docker_exec_cmd.format(ndppd_conf_copy_cmd))
149+
clicommon.run_command(docker_exec_cmd.format(supervisor_update_cmd), return_cmd=True)
150+
151+
click.echo("Starting ndppd service")
152+
clicommon.run_command(docker_exec_cmd.format(ndppd_config_gen_cmd))
133153
sleep(3)
134-
clicommon.run_command(docker_exec_cmd.format(ndppd_restart_cmd), display_cmd=True)
154+
clicommon.run_command(docker_exec_cmd.format(ndppd_restart_cmd), return_cmd=True)
135155

136156

137157
@vlan.command('proxy_arp')

tests/vlan_test.py

+40-9
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,27 @@ def test_config_vlan_del_vlan(self, mock_restart_dhcp_relay_service):
403403
assert result.exit_code == 0
404404
assert result.output == show_vlan_brief_empty_output
405405

406+
def test_config_vlan_del_last_vlan(self):
407+
runner = CliRunner()
408+
db = Db()
409+
db.cfgdb.delete_table("VLAN_MEMBER")
410+
db.cfgdb.delete_table("VLAN_INTERFACE")
411+
db.cfgdb.set_entry("VLAN", "Vlan2000", None)
412+
db.cfgdb.set_entry("VLAN", "Vlan3000", None)
413+
db.cfgdb.set_entry("VLAN", "Vlan4000", None)
414+
415+
with mock.patch("utilities_common.cli.run_command", mock.Mock(return_value=("", 0))) as mock_run_command:
416+
result = runner.invoke(config.config.commands["vlan"].commands["del"], ["1000"], obj=db)
417+
print(result.exit_code)
418+
print(result.output)
419+
mock_run_command.assert_has_calls([
420+
mock.call("docker exec -i swss supervisorctl status ndppd", ignore_error=True, return_cmd=True),
421+
mock.call("docker exec -i swss supervisorctl stop ndppd", ignore_error=True, return_cmd=True),
422+
mock.call("docker exec -i swss rm -f /etc/supervisor/conf.d/ndppd.conf", ignore_error=True, return_cmd=True),
423+
mock.call("docker exec -i swss supervisorctl update", return_cmd=True)
424+
])
425+
assert result.exit_code == 0
426+
406427
def test_config_vlan_del_nonexist_vlan_member(self):
407428
runner = CliRunner()
408429

@@ -533,19 +554,29 @@ def test_config_vlan_proxy_arp_with_nonexist_vlan_intf(self):
533554
assert result.exit_code != 0
534555
assert "Interface Vlan1001 does not exist" in result.output
535556

536-
def test_config_vlan_proxy_arp_enable(self, mock_restart_dhcp_relay_service):
537-
runner = CliRunner()
538-
db = Db()
557+
def test_config_vlan_proxy_arp_enable(self):
558+
mock_cli_returns = [("running", 0),("", 1)] + [("", 0)] * 4
559+
with mock.patch("utilities_common.cli.run_command", mock.Mock(side_effect=mock_cli_returns)) as mock_run_command:
560+
runner = CliRunner()
561+
db = Db()
539562

540-
result = runner.invoke(config.config.commands["vlan"].commands["proxy_arp"], ["1000", "enabled"], obj=db)
563+
result = runner.invoke(config.config.commands["vlan"].commands["proxy_arp"], ["1000", "enabled"], obj=db)
541564

542-
print(result.exit_code)
543-
print(result.output)
565+
print(result.exit_code)
566+
print(result.output)
567+
568+
expected_calls = [mock.call("docker container inspect -f '{{.State.Status}}' swss", return_cmd=True),
569+
mock.call('docker exec -i swss supervisorctl status ndppd', ignore_error=True, return_cmd=True),
570+
mock.call('docker exec -i swss cp /usr/share/sonic/templates/ndppd.conf /etc/supervisor/conf.d/'),
571+
mock.call('docker exec -i swss supervisorctl update', return_cmd=True),
572+
mock.call('docker exec -i swss sonic-cfggen -d -t /usr/share/sonic/templates/ndppd.conf.j2,/etc/ndppd.conf'),
573+
mock.call('docker exec -i swss supervisorctl restart ndppd', return_cmd=True)]
574+
mock_run_command.assert_has_calls(expected_calls)
544575

545-
assert result.exit_code == 0
546-
assert db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan1000") == {"proxy_arp": "enabled"}
576+
assert result.exit_code == 0
577+
assert db.cfgdb.get_entry("VLAN_INTERFACE", "Vlan1000") == {"proxy_arp": "enabled"}
547578

548-
def test_config_vlan_proxy_arp_disable(self, mock_restart_dhcp_relay_service):
579+
def test_config_vlan_proxy_arp_disable(self):
549580
runner = CliRunner()
550581
db = Db()
551582

0 commit comments

Comments
 (0)