Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flush ARP/neighbor entry on FDB flush when port L2-L3 #1506

Merged
merged 6 commits into from
Nov 25, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 193 additions & 47 deletions cfgmgr/nbrmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ NbrMgr::NbrMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, con
{
SWSS_LOG_ERROR("Netlink socket connect failed, error '%s'", nl_geterror(err));
}

auto consumerStateTable = new swss::ConsumerStateTable(appDb, APP_NEIGH_RESOLVE_TABLE_NAME,
TableConsumable::DEFAULT_POP_BATCH_SIZE, default_orch_pri);
auto consumer = new Consumer(consumerStateTable, this, APP_NEIGH_RESOLVE_TABLE_NAME);
Orch::addExecutor(consumer);
}

bool NbrMgr::isIntfStateOk(const string &alias)
Expand Down Expand Up @@ -87,105 +92,229 @@ bool NbrMgr::isNeighRestoreDone()
return false;
}

bool NbrMgr::setNeighbor(const string& alias, const IpAddress& ip, const MacAddress& mac)

bool NbrMgr::addIp(struct nl_msg* msg_p, const IpAddress& ip)
{
auto ip_addr = ip.getIp();
auto addr_len = ip.isV4()? sizeof(struct in_addr) : sizeof(struct in6_addr);

struct rtattr *rta_p = static_cast<struct rtattr *>
(nlmsg_reserve(msg_p, sizeof(struct rtattr) + addr_len, NLMSG_ALIGNTO));
if (!rta_p)
{
SWSS_LOG_ERROR("Netlink rtattr (IP) failed for '%s'", ip.to_string().c_str());
return false;
}

rta_p->rta_type = NDA_DST;
rta_p->rta_len = static_cast<short>(RTA_LENGTH(addr_len));
ip.isV4() ? memcpy(RTA_DATA(rta_p), &ip_addr.ip_addr.ipv4_addr, addr_len) :
memcpy(RTA_DATA(rta_p), &ip_addr.ip_addr.ipv6_addr, addr_len);

return true;
}

bool NbrMgr::addMac(struct nl_msg* msg_p, const MacAddress& mac)
{
auto mac_len = ETHER_ADDR_LEN;
auto mac_addr = mac.getMac();

struct rtattr *rta_p = static_cast<struct rtattr *>
(nlmsg_reserve(msg_p, sizeof(struct rtattr) + mac_len, NLMSG_ALIGNTO));
if (!rta_p)
{
SWSS_LOG_ERROR("Netlink rtattr (MAC) failed for '%s'", mac.to_string().c_str());
return false;
}

rta_p->rta_type = NDA_LLADDR;
rta_p->rta_len = static_cast<short>(RTA_LENGTH(mac_len));
memcpy(RTA_DATA(rta_p), mac_addr, mac_len);

return true;
}

bool NbrMgr::deleteNeighbor(const string& alias, const IpAddress& ip, const MacAddress& mac)
{
SWSS_LOG_ENTER();

struct nl_msg *msg = nlmsg_alloc();
if (!msg)
SWSS_LOG_NOTICE("Remove ARP entry '%s:%s -> %s'",
alias.c_str(), ip.to_string().c_str(), mac.to_string().c_str());

struct nl_msg *msg_p = nlmsg_alloc();
if (!msg_p)
{
SWSS_LOG_ERROR("Netlink message alloc failed for '%s'", ip.to_string().c_str());
return false;
}

auto flags = (NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);

struct nlmsghdr *hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, RTM_NEWNEIGH, 0, flags);
if (!hdr)
auto flags = (NLM_F_REQUEST | NLM_F_ACK);
struct nlmsghdr *hdr_p = nlmsg_put(msg_p, NL_AUTO_PORT, NL_AUTO_SEQ, RTM_DELNEIGH, 0, flags);
if (!hdr_p)
{
SWSS_LOG_ERROR("Netlink message header alloc failed for '%s'", ip.to_string().c_str());
nlmsg_free(msg);
nlmsg_free(msg_p);
return false;
}

struct ndmsg *nd_msg = static_cast<struct ndmsg *>
(nlmsg_reserve(msg, sizeof(struct ndmsg), NLMSG_ALIGNTO));
if (!nd_msg)
// Prepare ndmsg to remove an entry from neighbor table
struct ndmsg *nd_msg_p = static_cast<struct ndmsg *>
(nlmsg_reserve(msg_p, sizeof(struct ndmsg), NLMSG_ALIGNTO));
if (!nd_msg_p)
{
SWSS_LOG_ERROR("Netlink ndmsg reserve failed for '%s'", ip.to_string().c_str());
nlmsg_free(msg);
nlmsg_free(msg_p);
return false;
}
memset(nd_msg_p, 0, sizeof(struct ndmsg));

memset(nd_msg, 0, sizeof(struct ndmsg));
// Fill in the interface
nd_msg_p->ndm_ifindex = if_nametoindex(alias.c_str());

nd_msg->ndm_ifindex = if_nametoindex(alias.c_str());
// Fill in the IPv4/IPv6 address
if (!addIp(msg_p, ip))
{
nlmsg_free(msg_p);
return false;
}
nd_msg_p->ndm_type = RTN_UNICAST;
nd_msg_p->ndm_family = ip.isV4() ? AF_INET : AF_INET6;

auto addr_len = ip.isV4()? sizeof(struct in_addr) : sizeof(struct in6_addr);
// Fill in the MAC address
if (!addMac(msg_p, mac))
{
nlmsg_free(msg_p);
return false;
}

// Send ndmsg
return send_message(m_nl_sock, msg_p);
}

struct rtattr *rta = static_cast<struct rtattr *>
(nlmsg_reserve(msg, sizeof(struct rtattr) + addr_len, NLMSG_ALIGNTO));
if (!rta)
bool NbrMgr::setNeighbor(const string& alias, const IpAddress& ip, const MacAddress& mac)
{
SWSS_LOG_ENTER();

struct nl_msg *msg_p = nlmsg_alloc();
if (!msg_p)
{
SWSS_LOG_ERROR("Netlink rtattr (IP) failed for '%s'", ip.to_string().c_str());
nlmsg_free(msg);
SWSS_LOG_ERROR("Netlink message alloc failed for '%s'", ip.to_string().c_str());
return false;
}

rta->rta_type = NDA_DST;
rta->rta_len = static_cast<short>(RTA_LENGTH(addr_len));
auto flags = (NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);

nd_msg->ndm_type = RTN_UNICAST;
auto ip_addr = ip.getIp();
struct nlmsghdr *hdr_p = nlmsg_put(msg_p, NL_AUTO_PORT, NL_AUTO_SEQ, RTM_NEWNEIGH, 0, flags);
if (!hdr_p)
{
SWSS_LOG_ERROR("Netlink message header alloc failed for '%s'", ip.to_string().c_str());
nlmsg_free(msg_p);
return false;
}

if (ip.isV4())
// Prepare ndmsg to add an entry to neighbor table
struct ndmsg *nd_msg_p = static_cast<struct ndmsg *>
(nlmsg_reserve(msg_p, sizeof(struct ndmsg), NLMSG_ALIGNTO));
if (!nd_msg_p)
{
nd_msg->ndm_family = AF_INET;
memcpy(RTA_DATA(rta), &ip_addr.ip_addr.ipv4_addr, addr_len);
SWSS_LOG_ERROR("Netlink ndmsg reserve failed for '%s'", ip.to_string().c_str());
nlmsg_free(msg_p);
return false;
}
else
memset(nd_msg_p, 0, sizeof(struct ndmsg));

// Populate interface
nd_msg_p->ndm_ifindex = if_nametoindex(alias.c_str());

// Populate IP
if (!addIp(msg_p, ip))
{
nd_msg->ndm_family = AF_INET6;
memcpy(RTA_DATA(rta), &ip_addr.ip_addr.ipv6_addr, addr_len);
nlmsg_free(msg_p);
return false;
}
nd_msg_p->ndm_type = RTN_UNICAST;
nd_msg_p->ndm_family = ip.isV4() ? AF_INET : AF_INET6;

// Populate MAC is provided
if (!mac)
{
/*
* If mac is not provided, expected to resolve the MAC
*/
nd_msg->ndm_state = NUD_DELAY;
nd_msg->ndm_flags = NTF_USE;
nd_msg_p->ndm_state = NUD_DELAY;
nd_msg_p->ndm_flags = NTF_USE;

SWSS_LOG_INFO("Resolve request for '%s'", ip.to_string().c_str());
}
else
{
SWSS_LOG_INFO("Set mac address '%s'", mac.to_string().c_str());

nd_msg->ndm_state = NUD_PERMANENT;

auto mac_len = ETHER_ADDR_LEN;
auto mac_addr = mac.getMac();

struct rtattr *rta = static_cast<struct rtattr *>
(nlmsg_reserve(msg, sizeof(struct rtattr) + mac_len, NLMSG_ALIGNTO));
if (!rta)
if (!addMac(msg_p, mac))
{
SWSS_LOG_ERROR("Netlink rtattr (MAC) failed for '%s'", ip.to_string().c_str());
nlmsg_free(msg);
nlmsg_free(msg_p);
return false;
}

rta->rta_type = NDA_LLADDR;
rta->rta_len = static_cast<short>(RTA_LENGTH(mac_len));
memcpy(RTA_DATA(rta), mac_addr, mac_len);
nd_msg_p->ndm_state = NUD_PERMANENT;
}

return send_message(m_nl_sock, msg);
// Send ndmsg
return send_message(m_nl_sock, msg_p);
}

void NbrMgr::doTask(Consumer &consumer)
void NbrMgr::doDeleteNeighTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

auto it = consumer.m_toSync.begin();
while (it != consumer.m_toSync.end())
{
KeyOpFieldsValuesTuple t = it->second;
vector<string> keys = tokenize(kfvKey(t),delimiter);
const vector<FieldValueTuple>& data = kfvFieldsValues(t);

string alias(keys[0]);
IpAddress ip(keys[1]);
string op = kfvOp(t);
MacAddress mac;
bool invalid_mac = false;

for (auto idx : data)
{
const auto &field = fvField(idx);
const auto &value = fvValue(idx);
if (field == "mac")
{
try
{
mac = value;
}
catch (const std::invalid_argument& e)
{
SWSS_LOG_ERROR("Invalid Mac addr '%s' for '%s'", value.c_str(), kfvKey(t).c_str());
invalid_mac = true;
break;
}
}
}


if (invalid_mac)
{
it = consumer.m_toSync.erase(it);
continue;
}

if (!deleteNeighbor(alias, ip, mac))
{
SWSS_LOG_ERROR("Neigh entry resolve failed for '%s'", kfvKey(t).c_str());
}
it = consumer.m_toSync.erase(it);
}
}

void NbrMgr::doSetNeighTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

Expand Down Expand Up @@ -257,3 +386,20 @@ void NbrMgr::doTask(Consumer &consumer)
it = consumer.m_toSync.erase(it);
}
}

void NbrMgr::doTask(Consumer &consumer)
{
string table_name = consumer.getTableName();

if (table_name == CFG_NEIGH_TABLE_NAME)
{
doSetNeighTask(consumer);
}

if (table_name == APP_NEIGH_RESOLVE_TABLE_NAME)
{
doDeleteNeighTask(consumer);
vasant17 marked this conversation as resolved.
Show resolved Hide resolved
}

SWSS_LOG_ERROR("Unknown REDIS table %s ", table_name.c_str());
vasant17 marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 5 additions & 0 deletions cfgmgr/nbrmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ class NbrMgr : public Orch

private:
bool isIntfStateOk(const std::string &alias);
bool addMac(struct nl_msg* msg_p, const MacAddress& mac);
bool addIp(struct nl_msg* msg_p, const IpAddress& ip);
bool setNeighbor(const std::string& alias, const IpAddress& ip, const MacAddress& mac);
bool deleteNeighbor(const std::string& alias, const IpAddress& ip, const MacAddress& mac);

void doDeleteNeighTask(Consumer &consumer);
void doSetNeighTask(Consumer &consumer);
void doTask(Consumer &consumer);

Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateIntfTable, m_stateNeighRestoreTable;
Expand Down
Loading