Skip to content

Commit

Permalink
Code changes to support IPv6 Link local enhancements (sonic-net#1463)
Browse files Browse the repository at this point in the history
* Code changes to support IPv6 Link local enchancements
- Changes to handle the "ipv6_use_link_local_only" option on a interface which is added/deleted based on Global Config or Interface config.
- Adds/Deletes the RIF for an interface in the absence of IPv6 global address on a interface based on "ipv6_use_link_local_only".
- Allow the ipv6 link-local address as neighbors.
- Allow adding the IPv6 routes with link-local nexthops.
- Skip Ipv4LL neighbor add in Orchagent for RFC5549.

Signed-off-by: Akhilesh Samineni <[email protected]>
  • Loading branch information
AkhileshSamineni authored Aug 5, 2021
1 parent 8674b3c commit 8f7ea14
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 17 deletions.
24 changes: 18 additions & 6 deletions cfgmgr/intfmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
string proxy_arp = "";
string grat_arp = "";
string mpls = "";
string ipv6_link_local_mode = "";

for (auto idx : data)
{
Expand Down Expand Up @@ -506,11 +507,14 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
{
mpls = value;
}

if (field == "nat_zone")
else if (field == "nat_zone")
{
nat_zone = value;
}
else if (field == "ipv6_use_link_local_only")
{
ipv6_link_local_mode = value;
}
}

if (op == SET_COMMAND)
Expand Down Expand Up @@ -551,6 +555,7 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
FieldValueTuple fvTuple("nat_zone", nat_zone);
data.push_back(fvTuple);
}

/* Set mpls */
if (!setIntfMpls(alias, mpls))
{
Expand All @@ -562,6 +567,13 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
FieldValueTuple fvTuple("mpls", mpls);
data.push_back(fvTuple);
}

/* Set ipv6 mode */
if (!ipv6_link_local_mode.empty())
{
FieldValueTuple fvTuple("ipv6_use_link_local_only", ipv6_link_local_mode);
data.push_back(fvTuple);
}
}

if (!parentAlias.empty())
Expand Down Expand Up @@ -731,8 +743,8 @@ bool IntfMgr::doIntfAddrTask(const vector<string>& keys,
std::vector<FieldValueTuple> fvVector;
FieldValueTuple f("family", ip_prefix.isV4() ? IPV4_NAME : IPV6_NAME);

// Don't send link local config to AppDB and Orchagent
if (ip_prefix.getIp().getAddrScope() != IpAddress::AddrScope::LINK_SCOPE)
// Don't send ipv4 link local config to AppDB and Orchagent
if ((ip_prefix.isV4() == false) || (ip_prefix.getIp().getAddrScope() != IpAddress::AddrScope::LINK_SCOPE))
{
FieldValueTuple s("scope", "global");
fvVector.push_back(s);
Expand All @@ -745,8 +757,8 @@ bool IntfMgr::doIntfAddrTask(const vector<string>& keys,
{
setIntfIp(alias, "del", ip_prefix);

// Don't send link local config to AppDB and Orchagent
if (ip_prefix.getIp().getAddrScope() != IpAddress::AddrScope::LINK_SCOPE)
// Don't send ipv4 link local config to AppDB and Orchagent
if ((ip_prefix.isV4() == false) || (ip_prefix.getIp().getAddrScope() != IpAddress::AddrScope::LINK_SCOPE))
{
m_appIntfTableProducer.del(appKey);
m_stateIntfTable.del(keys[0] + state_db_key_delimiter + keys[1]);
Expand Down
68 changes: 64 additions & 4 deletions neighsyncd/neighsync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@

#include "neighsync.h"
#include "warm_restart.h"
#include <algorithm>

using namespace std;
using namespace swss;

NeighSync::NeighSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb) :
NeighSync::NeighSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *cfgDb) :
m_neighTable(pipelineAppDB, APP_NEIGH_TABLE_NAME),
m_stateNeighRestoreTable(stateDb, STATE_NEIGH_RESTORE_TABLE_NAME)
m_stateNeighRestoreTable(stateDb, STATE_NEIGH_RESTORE_TABLE_NAME),
m_cfgInterfaceTable(cfgDb, CFG_INTF_TABLE_NAME),
m_cfgLagInterfaceTable(cfgDb, CFG_LAG_INTF_TABLE_NAME),
m_cfgVlanInterfaceTable(cfgDb, CFG_VLAN_INTF_TABLE_NAME)
{
m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "neighsyncd", "swss", DEFAULT_NEIGHSYNC_WARMSTART_TIMER);
if (m_AppRestartAssist)
Expand Down Expand Up @@ -57,6 +61,7 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj)
struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj;
string key;
string family;
string intfName;

if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) &&
(nlmsg_type != RTM_DELNEIGH))
Expand All @@ -70,12 +75,18 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj)
return;

key+= LinkCache::getInstance().ifindexToName(rtnl_neigh_get_ifindex(neigh));
intfName = key;
key+= ":";

nl_addr2str(rtnl_neigh_get_dst(neigh), ipStr, MAX_ADDR_SIZE);
/* Ignore IPv6 link-local addresses as neighbors */
/* 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))))
return;
{
if (isLinkLocalEnabled(intfName) == false)
{
return;
}
}
/* Ignore IPv6 multicast link-local addresses as neighbors */
if (family == IPV6_NAME && IN6_IS_ADDR_MC_LINKLOCAL(nl_addr_get_binary_addr(rtnl_neigh_get_dst(neigh))))
return;
Expand Down Expand Up @@ -124,3 +135,52 @@ void NeighSync::onMsg(int nlmsg_type, struct nl_object *obj)
m_neighTable.set(key, fvVector);
}
}

/* To check the ipv6 link local is enabled on a given port */
bool NeighSync::isLinkLocalEnabled(const string &port)
{
vector<FieldValueTuple> values;

if (!port.compare(0, strlen("Vlan"), "Vlan"))
{
if (!m_cfgVlanInterfaceTable.get(port, values))
{
SWSS_LOG_INFO("IPv6 Link local is not enabled on %s", port.c_str());
return false;
}
}
else if (!port.compare(0, strlen("PortChannel"), "PortChannel"))
{
if (!m_cfgLagInterfaceTable.get(port, values))
{
SWSS_LOG_INFO("IPv6 Link local is not enabled on %s", port.c_str());
return false;
}
}
else if (!port.compare(0, strlen("Ethernet"), "Ethernet"))
{
if (!m_cfgInterfaceTable.get(port, values))
{
SWSS_LOG_INFO("IPv6 Link local is not enabled on %s", port.c_str());
return false;
}
}
else
{
SWSS_LOG_INFO("IPv6 Link local is not supported for %s ", port.c_str());
return false;
}

auto it = std::find_if(values.begin(), values.end(), [](const FieldValueTuple& t){ return t.first == "ipv6_use_link_local_only";});
if (it != values.end())
{
if (it->second == "enable")
{
SWSS_LOG_INFO("IPv6 Link local is enabled on %s", port.c_str());
return true;
}
}

SWSS_LOG_INFO("IPv6 Link local is not enabled on %s", port.c_str());
return false;
}
5 changes: 4 additions & 1 deletion neighsyncd/neighsync.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class NeighSync : public NetMsg
public:
enum { MAX_ADDR_SIZE = 64 };

NeighSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb);
NeighSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *cfgDb);
~NeighSync();

virtual void onMsg(int nlmsg_type, struct nl_object *obj);
Expand All @@ -39,6 +39,9 @@ class NeighSync : public NetMsg
Table m_stateNeighRestoreTable;
ProducerStateTable m_neighTable;
AppRestartAssist *m_AppRestartAssist;
Table m_cfgVlanInterfaceTable, m_cfgLagInterfaceTable, m_cfgInterfaceTable;

bool isLinkLocalEnabled(const std::string &port);
};

}
Expand Down
3 changes: 2 additions & 1 deletion neighsyncd/neighsyncd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ int main(int argc, char **argv)
DBConnector appDb("APPL_DB", 0);
RedisPipeline pipelineAppDB(&appDb);
DBConnector stateDb("STATE_DB", 0);
DBConnector cfgDb("CONFIG_DB", 0);

NeighSync sync(&pipelineAppDB, &stateDb);
NeighSync sync(&pipelineAppDB, &stateDb, &cfgDb);

NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync);
NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync);
Expand Down
13 changes: 13 additions & 0 deletions orchagent/neighorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,19 @@ void NeighOrch::doTask(Consumer &consumer)

IpAddress ip_address(key.substr(found+1));

/* Verify Ipv4 LinkLocal and skip neighbor entry added for RFC5549 */
if ((ip_address.getAddrScope() == IpAddress::LINK_SCOPE) && (ip_address.isV4()))
{
/* Check if this prefix is not a configured ip, if so allow */
IpPrefix ipll_prefix(ip_address.getV4Addr(), 16);
if (!m_intfsOrch->isPrefixSubnet (ipll_prefix, alias))
{
SWSS_LOG_NOTICE("Skip IPv4LL neighbor %s, Intf:%s op: %s ", ip_address.to_string().c_str(), alias.c_str(), op.c_str());
it = consumer.m_toSync.erase(it);
continue;
}
}

NeighborEntry neighbor_entry = { ip_address, alias };

if (op == SET_COMMAND)
Expand Down
25 changes: 23 additions & 2 deletions orchagent/routeorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,15 @@ RouteOrch::RouteOrch(DBConnector *db, vector<table_name_with_pri_t> &tableNames,
IpPrefix linklocal_prefix = getLinkLocalEui64Addr();

addLinkLocalRouteToMe(gVirtualRouterId, linklocal_prefix);
SWSS_LOG_NOTICE("Created link local ipv6 route %s to cpu", linklocal_prefix.to_string().c_str());

/* Add fe80::/10 subnet route to forward all link-local packets
* destined to us, to CPU */
IpPrefix default_link_local_prefix("fe80::/10");

addLinkLocalRouteToMe(gVirtualRouterId, default_link_local_prefix);
SWSS_LOG_NOTICE("Created link local ipv6 route %s to cpu", default_link_local_prefix.to_string().c_str());

/* TODO: Add the link-local fe80::/10 route to cpu in every VRF created from
* vrforch::addOperation. */
}

std::string RouteOrch::getLinkLocalEui64Addr(void)
Expand Down Expand Up @@ -205,6 +205,27 @@ void RouteOrch::addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal
SWSS_LOG_NOTICE("Created link local ipv6 route %s to cpu", linklocal_prefix.to_string().c_str());
}

void RouteOrch::delLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix)
{
sai_route_entry_t unicast_route_entry;
unicast_route_entry.switch_id = gSwitchId;
unicast_route_entry.vr_id = vrf_id;
copy(unicast_route_entry.destination, linklocal_prefix);
subnet(unicast_route_entry.destination, unicast_route_entry.destination);

sai_status_t status = sai_route_api->remove_route_entry(&unicast_route_entry);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to delete link local ipv6 route %s to cpu, rv:%d",
linklocal_prefix.getIp().to_string().c_str(), status);
return;
}

gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE);

SWSS_LOG_NOTICE("Deleted link local ipv6 route %s to cpu", linklocal_prefix.to_string().c_str());
}

bool RouteOrch::hasNextHopGroup(const NextHopGroupKey& nexthops) const
{
return m_syncdNextHopGroups.find(nexthops) != m_syncdNextHopGroups.end();
Expand Down
7 changes: 4 additions & 3 deletions orchagent/routeorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ class RouteOrch : public Orch, public Subject
bool createFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id, vector<sai_attribute_t> &nhg_attrs);
bool removeFineGrainedNextHopGroup(sai_object_id_t &next_hop_group_id);

void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix);
void delLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix);
std::string getLinkLocalEui64Addr(void);

private:
SwitchOrch *m_switchOrch;
NeighOrch *m_neighOrch;
Expand Down Expand Up @@ -188,9 +192,6 @@ class RouteOrch : public Orch, public Subject
bool addLabelRoutePost(const LabelRouteBulkContext& ctx, const NextHopGroupKey &nextHops);
bool removeLabelRoutePost(const LabelRouteBulkContext& ctx);

std::string getLinkLocalEui64Addr(void);
void addLinkLocalRouteToMe(sai_object_id_t vrf_id, IpPrefix linklocal_prefix);

void doTask(Consumer& consumer);
void doLabelTask(Consumer& consumer);
};
Expand Down
Loading

0 comments on commit 8f7ea14

Please sign in to comment.