From 7350d49ba7d7e0fe06184775f4e321f00e5a62f8 Mon Sep 17 00:00:00 2001 From: Vivek R Date: Fri, 25 Mar 2022 17:06:52 -0700 Subject: [PATCH] [Vxlanmgr] vnet netdev cleanup during config reload fix (#2191) * Enhanced the Existing cleanup methods i.e. getAllVxlanNetDevices & clearAllVxlanDevices to also include any stale Brvxlan interfaces and remove them. Signed-off-by: Vivek Reddy Karri --- cfgmgr/vxlanmgr.cpp | 71 +++++++++++++++++++++++++++++-------- cfgmgr/vxlanmgr.h | 2 ++ tests/test_vxlan_tunnel.py | 72 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 14 deletions(-) diff --git a/cfgmgr/vxlanmgr.cpp b/cfgmgr/vxlanmgr.cpp index e45c59380315..a0549684833c 100644 --- a/cfgmgr/vxlanmgr.cpp +++ b/cfgmgr/vxlanmgr.cpp @@ -1031,29 +1031,59 @@ int VxlanMgr::deleteVxlanNetdevice(std::string vxlan_dev_name) return swss::exec(cmd, res); } +std::vector VxlanMgr::parseNetDev(const string& stdout){ + std::vector netdevs; + std::regex device_name_pattern("^\\d+:\\s+([^:]+)"); + std::smatch match_result; + auto lines = tokenize(stdout, '\n'); + for (const std::string & line : lines) + { + SWSS_LOG_DEBUG("line : %s\n",line.c_str()); + if (!std::regex_search(line, match_result, device_name_pattern)) + { + continue; + } + std::string dev_name = match_result[1]; + netdevs.push_back(dev_name); + } + return netdevs; +} + void VxlanMgr::getAllVxlanNetDevices() { std::string stdout; - const std::string cmd = std::string("") + IP_CMD + " link show type vxlan"; + + // Get VxLan Netdev Interfaces + std::string cmd = std::string("") + IP_CMD + " link show type vxlan"; int ret = swss::exec(cmd, stdout); if (ret != 0) { - SWSS_LOG_ERROR("Cannot get devices by command : %s", cmd.c_str()); - return; + SWSS_LOG_ERROR("Cannot get vxlan devices by command : %s", cmd.c_str()); + stdout.clear(); } - std::regex device_name_pattern("^\\d+:\\s+([^:]+)"); - std::smatch match_result; - auto lines = tokenize(stdout, '\n'); - for (const std::string & line : lines) + std::vector netdevs = parseNetDev(stdout); + for (auto netdev : netdevs) { - SWSS_LOG_INFO("line : %s\n",line.c_str()); - if (!std::regex_search(line, match_result, device_name_pattern)) + m_vxlanNetDevices[netdev] = VXLAN; + } + + // Get VxLanIf Netdev Interfaces + cmd = std::string("") + IP_CMD + " link show type bridge"; + ret = swss::exec(cmd, stdout); + if (ret != 0) + { + SWSS_LOG_ERROR("Cannot get vxlanIf devices by command : %s", cmd.c_str()); + stdout.clear(); + } + netdevs = parseNetDev(stdout); + for (auto netdev : netdevs) + { + if (netdev.find(VXLAN_IF_NAME_PREFIX) == 0) { - continue; + m_vxlanNetDevices[netdev] = VXLAN_IF; } - std::string vxlan_dev_name = match_result[1]; - m_vxlanNetDevices[vxlan_dev_name] = vxlan_dev_name; } + return; } @@ -1150,8 +1180,21 @@ void VxlanMgr::clearAllVxlanDevices() { for (auto it = m_vxlanNetDevices.begin(); it != m_vxlanNetDevices.end();) { - SWSS_LOG_INFO("Deleting Stale NetDevice vxlandevname %s\n", (it->first).c_str()); - deleteVxlanNetdevice(it->first); + std::string netdev_name = it->first; + std::string netdev_type = it->second; + SWSS_LOG_INFO("Deleting Stale NetDevice %s, type: %s\n", netdev_name.c_str(), netdev_type.c_str()); + VxlanInfo info; + std::string res; + if (netdev_type.compare(VXLAN)) + { + info.m_vxlan = netdev_name; + cmdDeleteVxlan(info, res); + } + else if(netdev_type.compare(VXLAN_IF)) + { + info.m_vxlanIf = netdev_name; + cmdDeleteVxlanIf(info, res); + } it = m_vxlanNetDevices.erase(it); } } diff --git a/cfgmgr/vxlanmgr.h b/cfgmgr/vxlanmgr.h index 1988e253aec7..b8bb61c49801 100644 --- a/cfgmgr/vxlanmgr.h +++ b/cfgmgr/vxlanmgr.h @@ -6,6 +6,7 @@ #include "orch.h" #include +#include #include #include #include @@ -70,6 +71,7 @@ class VxlanMgr : public Orch int createVxlanNetdevice(std::string vxlanTunnelName, std::string vni_id, std::string src_ip, std::string dst_ip, std::string vlan_id); int deleteVxlanNetdevice(std::string vxlan_dev_name); + std::vector parseNetDev(const std::string& stdout); void getAllVxlanNetDevices(); /* diff --git a/tests/test_vxlan_tunnel.py b/tests/test_vxlan_tunnel.py index 14fe28261f3d..d296fcc74128 100644 --- a/tests/test_vxlan_tunnel.py +++ b/tests/test_vxlan_tunnel.py @@ -26,6 +26,18 @@ def create_entry_pst(db, table, separator, key, pairs): create_entry(tbl, key, pairs) +def delete_entry_pst(db, table, key): + tbl = swsscommon.ProducerStateTable(db, table) + tbl._del(key) + time.sleep(1) + + +def delete_entry_tbl(db, table, key): + tbl = swsscommon.Table(db, table) + tbl._del(key) + time.sleep(1) + + def how_many_entries_exist(db, table): tbl = swsscommon.Table(db, table) return len(tbl.getKeys()) @@ -324,6 +336,66 @@ def test_vxlan_term_orch(self, dvs, testlog): create_vxlan_tunnel_entry(dvs, 'tunnel_4', 'entry_2', tunnel_map_map, 'Vlan57', '857', tunnel_map_ids, tunnel_map_entry_ids, tunnel_ids, tunnel_term_ids) +def apply_test_vnet_cfg(cfg_db): + + # create VXLAN Tunnel + create_entry_tbl( + cfg_db, + "VXLAN_TUNNEL", '|', "tunnel1", + [ + ("src_ip", "1.1.1.1") + ], + ) + + # create VNET + create_entry_tbl( + cfg_db, + "VNET", '|', "tunnel1", + [ + ("vxlan_tunnel", "tunnel1"), + ("vni", "1") + ], + ) + + return + + +@pytest.fixture +def env_setup(dvs): + cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + create_entry_pst( + app_db, + "SWITCH_TABLE", ':', "switch", + [ + ("vxlan_router_mac", "00:01:02:03:04:05") + ], + ) + + apply_test_vnet_cfg(cfg_db) + + yield + + delete_entry_pst(app_db, "SWITCH_TABLE", "switch") + delete_entry_tbl(cfg_db, "VXLAN_TUNNEL", "tunnel1") + delete_entry_tbl(cfg_db, "VNET", "Vnet1") + +def test_vnet_cleanup_config_reload(dvs, env_setup): + + # Restart vxlanmgrd Process + dvs.runcmd(["systemctl", "restart", "vxlanmgrd"]) + + # Reapply cfg to simulate cfg reload + cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + apply_test_vnet_cfg(cfg_db) + + time.sleep(0.5) + + # Check if the netdevices is created as expected + ret, stdout = dvs.runcmd(["ip", "link", "show"]) + assert "Vxlan1" in stdout + assert "Brvxlan1" in stdout # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying