Skip to content

Commit 311fbf1

Browse files
AkhileshSaminenipreetham-singh
authored andcommitted
Delete the IPv6 link-local Neighbor when ipv6 link-local mode is disabled (sonic-net#1897)
* IPv6 link-local Neighbor deletion when ipv6 link-local mode is disabled. Signed-off-by: Akhilesh Samineni <[email protected]>
1 parent d303a0c commit 311fbf1

File tree

4 files changed

+164
-1
lines changed

4 files changed

+164
-1
lines changed

cfgmgr/intfmgr.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c
4040
m_stateVrfTable(stateDb, STATE_VRF_TABLE_NAME),
4141
m_stateIntfTable(stateDb, STATE_INTERFACE_TABLE_NAME),
4242
m_appIntfTableProducer(appDb, APP_INTF_TABLE_NAME),
43+
m_neighTable(appDb, APP_NEIGH_TABLE_NAME),
4344
m_appLagTable(appDb, APP_LAG_TABLE_NAME)
4445
{
4546
auto subscriberStateTable = new swss::SubscriberStateTable(stateDb,
@@ -616,6 +617,35 @@ bool IntfMgr::isIntfStateOk(const string &alias)
616617
return false;
617618
}
618619

620+
void IntfMgr::delIpv6LinkLocalNeigh(const string &alias)
621+
{
622+
vector<string> neighEntries;
623+
624+
SWSS_LOG_INFO("Deleting ipv6 link local neighbors for %s", alias.c_str());
625+
626+
m_neighTable.getKeys(neighEntries);
627+
for (auto neighKey : neighEntries)
628+
{
629+
if (!neighKey.compare(0, alias.size(), alias.c_str()))
630+
{
631+
vector<string> keys = tokenize(neighKey, ':', 1);
632+
if (keys.size() == 2)
633+
{
634+
IpAddress ipAddress(keys[1]);
635+
if (ipAddress.getAddrScope() == IpAddress::AddrScope::LINK_SCOPE)
636+
{
637+
stringstream cmd;
638+
string res;
639+
640+
cmd << IP_CMD << " neigh del dev " << keys[0] << " " << keys[1] ;
641+
swss::exec(cmd.str(), res);
642+
SWSS_LOG_INFO("Deleted ipv6 link local neighbor - %s", keys[1].c_str());
643+
}
644+
}
645+
}
646+
}
647+
}
648+
619649
bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
620650
vector<FieldValueTuple> data,
621651
const string& op)
@@ -755,6 +785,17 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
755785
/* Set ipv6 mode */
756786
if (!ipv6_link_local_mode.empty())
757787
{
788+
if ((ipv6_link_local_mode == "enable") && (m_ipv6LinkLocalModeList.find(alias) == m_ipv6LinkLocalModeList.end()))
789+
{
790+
m_ipv6LinkLocalModeList.insert(alias);
791+
SWSS_LOG_INFO("Inserted ipv6 link local mode list for %s", alias.c_str());
792+
}
793+
else if ((ipv6_link_local_mode == "disable") && (m_ipv6LinkLocalModeList.find(alias) != m_ipv6LinkLocalModeList.end()))
794+
{
795+
m_ipv6LinkLocalModeList.erase(alias);
796+
delIpv6LinkLocalNeigh(alias);
797+
SWSS_LOG_INFO("Erased ipv6 link local mode list for %s", alias.c_str());
798+
}
758799
FieldValueTuple fvTuple("ipv6_use_link_local_only", ipv6_link_local_mode);
759800
data.push_back(fvTuple);
760801
}
@@ -910,6 +951,13 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
910951
removeSubIntfState(alias);
911952
}
912953

954+
if (m_ipv6LinkLocalModeList.find(alias) != m_ipv6LinkLocalModeList.end())
955+
{
956+
m_ipv6LinkLocalModeList.erase(alias);
957+
delIpv6LinkLocalNeigh(alias);
958+
SWSS_LOG_INFO("Erased ipv6 link local mode list for %s", alias.c_str());
959+
}
960+
913961
m_appIntfTableProducer.del(alias);
914962
m_stateIntfTable.del(alias);
915963
}

cfgmgr/intfmgr.h

+3
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ class IntfMgr : public Orch
3131
ProducerStateTable m_appIntfTableProducer;
3232
Table m_cfgIntfTable, m_cfgVlanIntfTable, m_cfgLagIntfTable, m_cfgLoopbackIntfTable;
3333
Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateVrfTable, m_stateIntfTable, m_appLagTable;
34+
Table m_neighTable;
3435

3536
SubIntfMap m_subIntfList;
3637
std::set<std::string> m_loopbackIntfList;
3738
std::set<std::string> m_pendingReplayIntfList;
39+
std::set<std::string> m_ipv6LinkLocalModeList;
3840

3941
void setIntfIp(const std::string &alias, const std::string &opCmd, const IpPrefix &ipPrefix);
4042
void setIntfVrf(const std::string &alias, const std::string &vrfName);
@@ -65,6 +67,7 @@ class IntfMgr : public Orch
6567
void removeHostSubIntf(const std::string &subIntf);
6668
void setSubIntfStateOk(const std::string &alias);
6769
void removeSubIntfState(const std::string &alias);
70+
void delIpv6LinkLocalNeigh(const std::string &alias);
6871

6972
bool setIntfProxyArp(const std::string &alias, const std::string &proxy_arp);
7073
bool setIntfGratArp(const std::string &alias, const std::string &grat_arp);

neighsyncd/neighsync.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj)
8282
/* Ignore IPv6 link-local addresses as neighbors, if ipv6 link local mode is disabled */
8383
if (family == IPV6_NAME && IN6_IS_ADDR_LINKLOCAL(nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh))))
8484
{
85-
if (isLinkLocalEnabled(intfName) == false)
85+
if ((isLinkLocalEnabled(intfName) == false) && (nlmsg_type != RTM_DELNEIGH))
8686
{
8787
return;
8888
}

tests/test_ipv6_link_local.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import time
2+
import json
3+
import pytest
4+
5+
from swsscommon import swsscommon
6+
7+
class TestIPv6LinkLocal(object):
8+
def setup_db(self, dvs):
9+
self.pdb = dvs.get_app_db()
10+
self.adb = dvs.get_asic_db()
11+
self.cdb = dvs.get_config_db()
12+
13+
def set_admin_status(self, interface, status):
14+
self.cdb.update_entry("PORT", interface, {"admin_status": status})
15+
16+
def add_ip_address(self, interface, ip):
17+
self.cdb.create_entry("INTERFACE", interface + "|" + ip, {"NULL": "NULL"})
18+
time.sleep(2)
19+
20+
def remove_ip_address(self, interface, ip):
21+
self.cdb.delete_entry("INTERFACE", interface + "|" + ip)
22+
time.sleep(2)
23+
24+
def create_ipv6_link_local_intf(self, interface):
25+
self.cdb.create_entry("INTERFACE", interface, {"ipv6_use_link_local_only": "enable"})
26+
time.sleep(2)
27+
28+
def remove_ipv6_link_local_intf(self, interface):
29+
self.cdb.delete_entry("INTERFACE", interface)
30+
time.sleep(2)
31+
32+
def test_NeighborAddRemoveIpv6LinkLocal(self, dvs, testlog):
33+
self.setup_db(dvs)
34+
35+
# create ipv6 link local intf
36+
self.create_ipv6_link_local_intf("Ethernet0")
37+
self.create_ipv6_link_local_intf("Ethernet4")
38+
39+
# bring up interface
40+
self.set_admin_status("Ethernet0", "up")
41+
self.set_admin_status("Ethernet4", "up")
42+
43+
# set ip address
44+
self.add_ip_address("Ethernet0", "2000::1/64")
45+
self.add_ip_address("Ethernet4", "2001::1/64")
46+
dvs.runcmd("sysctl -w net.ipv6.conf.all.forwarding=1")
47+
dvs.runcmd("sysctl -w net.ipv6.conf.default.forwarding=1")
48+
49+
# set ip address and default route
50+
dvs.servers[0].runcmd("ip -6 address add 2000::2/64 dev eth0")
51+
dvs.servers[0].runcmd("ip -6 route add default via 2000::1")
52+
53+
dvs.servers[1].runcmd("ip -6 address add 2001::2/64 dev eth0")
54+
dvs.servers[1].runcmd("ip -6 route add default via 2001::1")
55+
time.sleep(2)
56+
57+
# get neighbor entry
58+
dvs.servers[0].runcmd("ping -6 -c 1 2001::2")
59+
time.sleep(2)
60+
61+
# Neigh entries should contain Ipv6-link-local neighbors, should be 4
62+
neigh_entries = self.pdb.get_keys("NEIGH_TABLE")
63+
assert (len(neigh_entries) == 4)
64+
65+
found_entry = False
66+
for key in neigh_entries:
67+
if (key.find("Ethernet4:2001::2") or key.find("Ethernet0:2000::2")):
68+
found_entry = True
69+
70+
assert found_entry
71+
72+
# remove ip address
73+
self.remove_ip_address("Ethernet0", "2000::1/64")
74+
self.remove_ip_address("Ethernet4", "2001::1/64")
75+
76+
# remove ipv6 link local intf
77+
self.remove_ipv6_link_local_intf("Ethernet0")
78+
self.remove_ipv6_link_local_intf("Ethernet4")
79+
80+
# Neigh entries should not contain Ipv6-link-local neighbors, should be 2
81+
neigh_after_entries = self.pdb.get_keys("NEIGH_TABLE")
82+
print(neigh_after_entries)
83+
assert (len(neigh_after_entries) == 2)
84+
85+
found_existing_entry = False
86+
for key in neigh_entries:
87+
if (key.find("Ethernet4:2001::2") or key.find("Ethernet0:2000::2")):
88+
found_existing_entry = True
89+
90+
assert found_existing_entry
91+
92+
self.set_admin_status("Ethernet0", "down")
93+
self.set_admin_status("Ethernet4", "down")
94+
95+
# remove ip address and default route
96+
dvs.servers[0].runcmd("ip -6 route del default dev eth0")
97+
dvs.servers[0].runcmd("ip -6 address del 2000::2/64 dev eth0")
98+
99+
dvs.servers[1].runcmd("ip -6 route del default dev eth0")
100+
dvs.servers[1].runcmd("ip -6 address del 2001::2/64 dev eth0")
101+
102+
dvs.runcmd("sysctl -w net.ipv6.conf.all.forwarding=0")
103+
dvs.runcmd("sysctl -w net.ipv6.conf.default.forwarding=0")
104+
105+
neigh_entries = self.pdb.get_keys("NEIGH_TABLE")
106+
assert (len(neigh_entries) == 0)
107+
108+
# Add Dummy always-pass test at end as workaroud
109+
# for issue when Flaky fail on final test it invokes module tear-down before retrying
110+
def test_nonflaky_dummy():
111+
pass
112+

0 commit comments

Comments
 (0)