From e81ed20b8f7f2243e050b122dc1d2d1c48645e82 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 4 Oct 2022 08:36:34 -0700 Subject: [PATCH] [intfmgr]: Enable `accept_untracked_na` kernel param (#2436) * [intfmgr]: Enable `accept_untracked_na` kernel param * When enabling gratuitous ARP, also enable acceptance of untracked neighbor advertisements --- cfgmgr/intfmgr.cpp | 20 +++++++++++++-- tests/dvslib/dvs_vlan.py | 11 ++++++++ tests/test_vlan.py | 54 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/cfgmgr/intfmgr.cpp b/cfgmgr/intfmgr.cpp index 3651a5515059..9e30e1265f41 100644 --- a/cfgmgr/intfmgr.cpp +++ b/cfgmgr/intfmgr.cpp @@ -535,11 +535,12 @@ void IntfMgr::removeSubIntfState(const string &alias) bool IntfMgr::setIntfGratArp(const string &alias, const string &grat_arp) { /* - * Enable gratuitous ARP by accepting unsolicited ARP replies + * Enable gratuitous ARP by accepting unsolicited ARP replies and untracked neighbor advertisements */ stringstream cmd; string res; string garp_enabled; + int rc; if (grat_arp == "enabled") { @@ -557,8 +558,23 @@ bool IntfMgr::setIntfGratArp(const string &alias, const string &grat_arp) cmd << ECHO_CMD << " " << garp_enabled << " > /proc/sys/net/ipv4/conf/" << alias << "/arp_accept"; EXEC_WITH_ERROR_THROW(cmd.str(), res); - SWSS_LOG_INFO("ARP accept set to \"%s\" on interface \"%s\"", grat_arp.c_str(), alias.c_str()); + + cmd.clear(); + cmd.str(std::string()); + + // `accept_untracked_na` is not available in all kernels, so check for it before trying to set it + cmd << "test -f /proc/sys/net/ipv6/conf/" << alias << "/accept_untracked_na"; + rc = swss::exec(cmd.str(), res); + + if (rc == 0) { + cmd.clear(); + cmd.str(std::string()); + cmd << ECHO_CMD << " " << garp_enabled << " > /proc/sys/net/ipv6/conf/" << alias << "/accept_untracked_na"; + EXEC_WITH_ERROR_THROW(cmd.str(), res); + SWSS_LOG_INFO("`accept_untracked_na` set to \"%s\" on interface \"%s\"", grat_arp.c_str(), alias.c_str()); + } + return true; } diff --git a/tests/dvslib/dvs_vlan.py b/tests/dvslib/dvs_vlan.py index 5ebbf51d454a..ad024a2f63ac 100644 --- a/tests/dvslib/dvs_vlan.py +++ b/tests/dvslib/dvs_vlan.py @@ -13,6 +13,17 @@ def create_vlan(self, vlanID): vlan_entry = {"vlanid": vlanID} self.config_db.create_entry("VLAN", vlan, vlan_entry) + def create_vlan_interface(self, vlanID): + vlan = "Vlan{}".format(vlanID) + vlan_intf_entry = {} + self.config_db.create_entry("VLAN_INTERFACE", vlan, vlan_intf_entry) + + def set_vlan_intf_property(self, vlanID, property, value): + vlan_key = "Vlan{}".format(vlanID) + vlan_entry = self.config_db.get_entry("VLAN_INTERFACE", vlan_key) + vlan_entry[property] = value + self.config_db.update_entry("VLAN_INTERFACE", vlan_key, vlan_entry) + def create_vlan_hostif(self, vlan, hostif_name): vlan = "Vlan{}".format(vlan) vlan_entry = {"vlanid": vlan, "host_ifname": hostif_name} diff --git a/tests/test_vlan.py b/tests/test_vlan.py index 6e43227a5655..a3c905a21420 100644 --- a/tests/test_vlan.py +++ b/tests/test_vlan.py @@ -2,7 +2,7 @@ import pytest from distutils.version import StrictVersion -from dvslib.dvs_common import PollingConfig +from dvslib.dvs_common import PollingConfig, wait_for_result @pytest.mark.usefixtures("testlog") @pytest.mark.usefixtures('dvs_vlan_manager') @@ -436,6 +436,58 @@ def test_VlanHostIf(self, dvs): self.dvs_vlan.get_and_verify_vlan_ids(0) self.dvs_vlan.get_and_verify_vlan_hostif_ids(len(dvs.asic_db.hostif_name_map) - 1) + def test_VlanGratArp(self, dvs): + def arp_accept_enabled(): + rc, res = dvs.runcmd("cat /proc/sys/net/ipv4/conf/Vlan{}/arp_accept".format(vlan)) + return (res.strip("\n") == "1", res) + + def arp_accept_disabled(): + rc, res = dvs.runcmd("cat /proc/sys/net/ipv4/conf/Vlan{}/arp_accept".format(vlan)) + return (res.strip("\n") == "0", res) + + vlan = "2" + self.dvs_vlan.create_vlan(vlan) + self.dvs_vlan.create_vlan_interface(vlan) + self.dvs_vlan.set_vlan_intf_property(vlan, "grat_arp", "enabled") + + wait_for_result(arp_accept_enabled, PollingConfig(), "IPv4 arp_accept not enabled") + + # Not currently possible to test `accept_untracked_na` as it doesn't exist in the kernel for + # our test VMs (only present in kernels 5.19 and above) + + self.dvs_vlan.set_vlan_intf_property(vlan, "grat_arp", "disabled") + + wait_for_result(arp_accept_disabled, PollingConfig(), "IPv4 arp_accept not disabled") + + self.dvs_vlan.remove_vlan(vlan) + + def test_VlanProxyArp(self, dvs): + + def proxy_arp_enabled(): + rc, proxy_arp_res = dvs.runcmd("cat /proc/sys/net/ipv4/conf/Vlan{}/proxy_arp".format(vlan)) + rc, pvlan_res = dvs.runcmd("cat /proc/sys/net/ipv4/conf/Vlan{}/proxy_arp_pvlan".format(vlan)) + + return (proxy_arp_res.strip("\n") == "1" and pvlan_res.strip("\n") == "1", (proxy_arp_res, pvlan_res)) + + def proxy_arp_disabled(): + rc, proxy_arp_res = dvs.runcmd("cat /proc/sys/net/ipv4/conf/Vlan{}/proxy_arp".format(vlan)) + rc, pvlan_res = dvs.runcmd("cat /proc/sys/net/ipv4/conf/Vlan{}/proxy_arp_pvlan".format(vlan)) + + return (proxy_arp_res.strip("\n") == "0" and pvlan_res.strip("\n") == "0", (proxy_arp_res, pvlan_res)) + + vlan = "2" + self.dvs_vlan.create_vlan(vlan) + self.dvs_vlan.create_vlan_interface(vlan) + self.dvs_vlan.set_vlan_intf_property(vlan, "proxy_arp", "enabled") + + wait_for_result(proxy_arp_enabled, PollingConfig(), 'IPv4 proxy_arp or proxy_arp_pvlan not enabled') + + self.dvs_vlan.set_vlan_intf_property(vlan, "proxy_arp", "disabled") + + wait_for_result(proxy_arp_disabled, PollingConfig(), 'IPv4 proxy_arp or proxy_arp_pvlan not disabled') + + self.dvs_vlan.remove_vlan(vlan) + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying def test_nonflaky_dummy():