Skip to content

Commit

Permalink
Delete the IPv6 link-local Neighbor when ipv6 link-local mode is disa…
Browse files Browse the repository at this point in the history
…bled (sonic-net#1897)

* IPv6 link-local Neighbor deletion when ipv6 link-local mode is disabled.
Signed-off-by: Akhilesh Samineni <akhilesh.samineni@broadcom.com>
  • Loading branch information
AkhileshSamineni authored Dec 1, 2021
1 parent ed783e1 commit 15a3b6c
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 1 deletion.
48 changes: 48 additions & 0 deletions cfgmgr/intfmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c
m_stateVrfTable(stateDb, STATE_VRF_TABLE_NAME),
m_stateIntfTable(stateDb, STATE_INTERFACE_TABLE_NAME),
m_appIntfTableProducer(appDb, APP_INTF_TABLE_NAME),
m_neighTable(appDb, APP_NEIGH_TABLE_NAME),
m_appLagTable(appDb, APP_LAG_TABLE_NAME)
{
auto subscriberStateTable = new swss::SubscriberStateTable(stateDb,
Expand Down Expand Up @@ -616,6 +617,35 @@ bool IntfMgr::isIntfStateOk(const string &alias)
return false;
}

void IntfMgr::delIpv6LinkLocalNeigh(const string &alias)
{
vector<string> neighEntries;

SWSS_LOG_INFO("Deleting ipv6 link local neighbors for %s", alias.c_str());

m_neighTable.getKeys(neighEntries);
for (auto neighKey : neighEntries)
{
if (!neighKey.compare(0, alias.size(), alias.c_str()))
{
vector<string> keys = tokenize(neighKey, ':', 1);
if (keys.size() == 2)
{
IpAddress ipAddress(keys[1]);
if (ipAddress.getAddrScope() == IpAddress::AddrScope::LINK_SCOPE)
{
stringstream cmd;
string res;

cmd << IP_CMD << " neigh del dev " << keys[0] << " " << keys[1] ;
swss::exec(cmd.str(), res);
SWSS_LOG_INFO("Deleted ipv6 link local neighbor - %s", keys[1].c_str());
}
}
}
}
}

bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
vector<FieldValueTuple> data,
const string& op)
Expand Down Expand Up @@ -755,6 +785,17 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
/* Set ipv6 mode */
if (!ipv6_link_local_mode.empty())
{
if ((ipv6_link_local_mode == "enable") && (m_ipv6LinkLocalModeList.find(alias) == m_ipv6LinkLocalModeList.end()))
{
m_ipv6LinkLocalModeList.insert(alias);
SWSS_LOG_INFO("Inserted ipv6 link local mode list for %s", alias.c_str());
}
else if ((ipv6_link_local_mode == "disable") && (m_ipv6LinkLocalModeList.find(alias) != m_ipv6LinkLocalModeList.end()))
{
m_ipv6LinkLocalModeList.erase(alias);
delIpv6LinkLocalNeigh(alias);
SWSS_LOG_INFO("Erased ipv6 link local mode list for %s", alias.c_str());
}
FieldValueTuple fvTuple("ipv6_use_link_local_only", ipv6_link_local_mode);
data.push_back(fvTuple);
}
Expand Down Expand Up @@ -910,6 +951,13 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
removeSubIntfState(alias);
}

if (m_ipv6LinkLocalModeList.find(alias) != m_ipv6LinkLocalModeList.end())
{
m_ipv6LinkLocalModeList.erase(alias);
delIpv6LinkLocalNeigh(alias);
SWSS_LOG_INFO("Erased ipv6 link local mode list for %s", alias.c_str());
}

m_appIntfTableProducer.del(alias);
m_stateIntfTable.del(alias);
}
Expand Down
3 changes: 3 additions & 0 deletions cfgmgr/intfmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ class IntfMgr : public Orch
ProducerStateTable m_appIntfTableProducer;
Table m_cfgIntfTable, m_cfgVlanIntfTable, m_cfgLagIntfTable, m_cfgLoopbackIntfTable;
Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateVrfTable, m_stateIntfTable, m_appLagTable;
Table m_neighTable;

SubIntfMap m_subIntfList;
std::set<std::string> m_loopbackIntfList;
std::set<std::string> m_pendingReplayIntfList;
std::set<std::string> m_ipv6LinkLocalModeList;

void setIntfIp(const std::string &alias, const std::string &opCmd, const IpPrefix &ipPrefix);
void setIntfVrf(const std::string &alias, const std::string &vrfName);
Expand Down Expand Up @@ -65,6 +67,7 @@ class IntfMgr : public Orch
void removeHostSubIntf(const std::string &subIntf);
void setSubIntfStateOk(const std::string &alias);
void removeSubIntfState(const std::string &alias);
void delIpv6LinkLocalNeigh(const std::string &alias);

bool setIntfProxyArp(const std::string &alias, const std::string &proxy_arp);
bool setIntfGratArp(const std::string &alias, const std::string &grat_arp);
Expand Down
2 changes: 1 addition & 1 deletion neighsyncd/neighsync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj)
/* Ignore IPv6 link-local addresses as neighbors, if ipv6 link local mode is disabled */
if (family == IPV6_NAME && IN6_IS_ADDR_LINKLOCAL(nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh))))
{
if (isLinkLocalEnabled(intfName) == false)
if ((isLinkLocalEnabled(intfName) == false) && (nlmsg_type != RTM_DELNEIGH))
{
return;
}
Expand Down
112 changes: 112 additions & 0 deletions tests/test_ipv6_link_local.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import time
import json
import pytest

from swsscommon import swsscommon

class TestIPv6LinkLocal(object):
def setup_db(self, dvs):
self.pdb = dvs.get_app_db()
self.adb = dvs.get_asic_db()
self.cdb = dvs.get_config_db()

def set_admin_status(self, interface, status):
self.cdb.update_entry("PORT", interface, {"admin_status": status})

def add_ip_address(self, interface, ip):
self.cdb.create_entry("INTERFACE", interface + "|" + ip, {"NULL": "NULL"})
time.sleep(2)

def remove_ip_address(self, interface, ip):
self.cdb.delete_entry("INTERFACE", interface + "|" + ip)
time.sleep(2)

def create_ipv6_link_local_intf(self, interface):
self.cdb.create_entry("INTERFACE", interface, {"ipv6_use_link_local_only": "enable"})
time.sleep(2)

def remove_ipv6_link_local_intf(self, interface):
self.cdb.delete_entry("INTERFACE", interface)
time.sleep(2)

def test_NeighborAddRemoveIpv6LinkLocal(self, dvs, testlog):
self.setup_db(dvs)

# create ipv6 link local intf
self.create_ipv6_link_local_intf("Ethernet0")
self.create_ipv6_link_local_intf("Ethernet4")

# bring up interface
self.set_admin_status("Ethernet0", "up")
self.set_admin_status("Ethernet4", "up")

# set ip address
self.add_ip_address("Ethernet0", "2000::1/64")
self.add_ip_address("Ethernet4", "2001::1/64")
dvs.runcmd("sysctl -w net.ipv6.conf.all.forwarding=1")
dvs.runcmd("sysctl -w net.ipv6.conf.default.forwarding=1")

# set ip address and default route
dvs.servers[0].runcmd("ip -6 address add 2000::2/64 dev eth0")
dvs.servers[0].runcmd("ip -6 route add default via 2000::1")

dvs.servers[1].runcmd("ip -6 address add 2001::2/64 dev eth0")
dvs.servers[1].runcmd("ip -6 route add default via 2001::1")
time.sleep(2)

# get neighbor entry
dvs.servers[0].runcmd("ping -6 -c 1 2001::2")
time.sleep(2)

# Neigh entries should contain Ipv6-link-local neighbors, should be 4
neigh_entries = self.pdb.get_keys("NEIGH_TABLE")
assert (len(neigh_entries) == 4)

found_entry = False
for key in neigh_entries:
if (key.find("Ethernet4:2001::2") or key.find("Ethernet0:2000::2")):
found_entry = True

assert found_entry

# remove ip address
self.remove_ip_address("Ethernet0", "2000::1/64")
self.remove_ip_address("Ethernet4", "2001::1/64")

# remove ipv6 link local intf
self.remove_ipv6_link_local_intf("Ethernet0")
self.remove_ipv6_link_local_intf("Ethernet4")

# Neigh entries should not contain Ipv6-link-local neighbors, should be 2
neigh_after_entries = self.pdb.get_keys("NEIGH_TABLE")
print(neigh_after_entries)
assert (len(neigh_after_entries) == 2)

found_existing_entry = False
for key in neigh_entries:
if (key.find("Ethernet4:2001::2") or key.find("Ethernet0:2000::2")):
found_existing_entry = True

assert found_existing_entry

self.set_admin_status("Ethernet0", "down")
self.set_admin_status("Ethernet4", "down")

# remove ip address and default route
dvs.servers[0].runcmd("ip -6 route del default dev eth0")
dvs.servers[0].runcmd("ip -6 address del 2000::2/64 dev eth0")

dvs.servers[1].runcmd("ip -6 route del default dev eth0")
dvs.servers[1].runcmd("ip -6 address del 2001::2/64 dev eth0")

dvs.runcmd("sysctl -w net.ipv6.conf.all.forwarding=0")
dvs.runcmd("sysctl -w net.ipv6.conf.default.forwarding=0")

neigh_entries = self.pdb.get_keys("NEIGH_TABLE")
assert (len(neigh_entries) == 0)

# 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():
pass

0 comments on commit 15a3b6c

Please sign in to comment.