Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
261 changes: 243 additions & 18 deletions fpmsyncd/routesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ using namespace swss;
#define VRF_PREFIX "Vrf"
#define MGMT_VRF_PREFIX "mgmt"

#define NHG_DELIMITER ','

#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
Expand All @@ -44,6 +46,7 @@ using namespace swss;

RouteSync::RouteSync(RedisPipeline *pipeline) :
m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true),
m_label_routeTable(pipeline, APP_LABEL_ROUTE_TABLE_NAME, true),
m_vnet_routeTable(pipeline, APP_VNET_RT_TABLE_NAME, true),
m_vnet_tunnelTable(pipeline, APP_VNET_RT_TUNNEL_TABLE_NAME, true),
m_warmStartHelper(pipeline, &m_routeTable, APP_ROUTE_TABLE_NAME, "bgp", "bgp"),
Expand Down Expand Up @@ -113,10 +116,10 @@ void RouteSync::parseEncap(struct rtattr *tb, uint32_t &encap_value, string &rma
void RouteSync::getEvpnNextHopSep(string& nexthops, string& vni_list,
string& mac_list, string& intf_list)
{
nexthops += string(",");
vni_list += string(",");
mac_list += string(",");
intf_list += string(",");
nexthops += NHG_DELIMITER;
vni_list += NHG_DELIMITER;
mac_list += NHG_DELIMITER;
intf_list += NHG_DELIMITER;

return;
}
Expand Down Expand Up @@ -571,6 +574,12 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)

/* Supports IPv4 or IPv6 address, otherwise return immediately */
auto family = rtnl_route_get_family(route_obj);
/* Check for Label route. */
if (family == AF_MPLS)
{
onLabelRouteMsg(nlmsg_type, obj);
return;
}
if (family != AF_INET && family != AF_INET6)
{
SWSS_LOG_INFO("Unknown route family support (object: %s)", nl_object_get_type(obj));
Expand Down Expand Up @@ -708,11 +717,13 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
}

/* Get nexthop lists */
string nexthops = getNextHopGw(route_obj);
string ifnames = getNextHopIf(route_obj);
string gw_list;
string intf_list;
string mpls_list;
getNextHopList(route_obj, gw_list, mpls_list, intf_list);
string weights = getNextHopWt(route_obj);

vector<string> alsv = tokenize(ifnames, ',');
vector<string> alsv = tokenize(intf_list, NHG_DELIMITER);
for (auto alias : alsv)
{
/*
Expand All @@ -722,17 +733,22 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
if (alias == "eth0" || alias == "docker0")
{
SWSS_LOG_DEBUG("Skip routes to eth0 or docker0: %s %s %s",
destipprefix, nexthops.c_str(), ifnames.c_str());
destipprefix, gw_list.c_str(), intf_list.c_str());
return;
}
}

vector<FieldValueTuple> fvVector;
FieldValueTuple nh("nexthop", nexthops);
FieldValueTuple idx("ifname", ifnames);
FieldValueTuple gw("nexthop", gw_list);
FieldValueTuple intf("ifname", intf_list);

fvVector.push_back(nh);
fvVector.push_back(idx);
fvVector.push_back(gw);
fvVector.push_back(intf);
if (!mpls_list.empty())
{
FieldValueTuple mpls_nh("mpls_nh", mpls_list);
fvVector.push_back(mpls_nh);
}
if (!weights.empty())
{
FieldValueTuple wt("weight", weights);
Expand All @@ -742,8 +758,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
if (!warmRestartInProgress)
{
m_routeTable.set(destipprefix, fvVector);
SWSS_LOG_DEBUG("RouteTable set msg: %s %s %s",
destipprefix, nexthops.c_str(), ifnames.c_str());
SWSS_LOG_DEBUG("RouteTable set msg: %s %s %s %s", destipprefix,
gw_list.c_str(), intf_list.c_str(), mpls_list.c_str());
}

/*
Expand All @@ -752,8 +768,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
*/
else
{
SWSS_LOG_INFO("Warm-Restart mode: RouteTable set msg: %s %s %s",
destipprefix, nexthops.c_str(), ifnames.c_str());
SWSS_LOG_INFO("Warm-Restart mode: RouteTable set msg: %s %s %s %s", destipprefix,
gw_list.c_str(), intf_list.c_str(), mpls_list.c_str());

const KeyOpFieldsValuesTuple kfv = std::make_tuple(destipprefix,
SET_COMMAND,
Expand All @@ -763,6 +779,98 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
}

/*
* Handle label route
* @arg nlmsg_type Netlink message type
* @arg obj Netlink object
*/
void RouteSync::onLabelRouteMsg(int nlmsg_type, struct nl_object *obj)
{
struct rtnl_route *route_obj = (struct rtnl_route *)obj;
struct nl_addr *daddr;
char destaddr[MAX_ADDR_SIZE + 1] = {0};

daddr = rtnl_route_get_dst(route_obj);
nl_addr2str(daddr, destaddr, MAX_ADDR_SIZE);
SWSS_LOG_INFO("Receive new LabelRoute message dest addr: %s", destaddr);
if (nl_addr_iszero(daddr)) return;

if (nlmsg_type == RTM_DELROUTE)
{
m_label_routeTable.del(destaddr);
return;
}
else if (nlmsg_type != RTM_NEWROUTE)
{
SWSS_LOG_INFO("Unknown message-type: %d for LabelRoute %s", nlmsg_type, destaddr);
return;
}

/* Get the index of the master device */
uint32_t master_index = rtnl_route_get_table(route_obj);
/* if the table_id is not set in the route obj then route is for default vrf. */
if (master_index)
Copy link
Copy Markdown
Contributor

@smaheshm smaheshm Jul 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you find out non-zero value implies a VRF table. "254" is the main table that ip route installs, 255 and 253 are local and default route table. All these are non-VRF tables.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smahesh You do know that SONiC has modified the fpm netlink message content from frr to something non-standard, right? The rtnl_route_get_table() function will not return the RT_TABLE value in SONiC fpmsyncd, it returns the VRF ifindex value instead because SONiC has patched this.
https://github.com/Azure/sonic-buildimage/blob/master/src/sonic-frr/patch/0003-Use-vrf_id-for-vrf-not-tabled_id.patch

Copy link
Copy Markdown
Contributor

@smaheshm smaheshm Jul 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the info, no I wasn't aware.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smaheshm Yes, this is the reason I have to disable VRF support in the other PR (#1765) where I provide the fpmsyncd runtime option to listen to kernel netlink instead of frr fpm. kernel netlink messages send the standard RT_TABLE ID in the netlink message, whereas frr fpm substitutes the patched VRF ifindex value.

{
SWSS_LOG_INFO("Unsupported Non-default VRF: %d for LabelRoute %s",
master_index, destaddr);
return;
}

switch (rtnl_route_get_type(route_obj))
{
case RTN_BLACKHOLE:
{
vector<FieldValueTuple> fvVector;
FieldValueTuple fv("blackhole", "true");
fvVector.push_back(fv);
m_label_routeTable.set(destaddr, fvVector);
return;
}
case RTN_UNICAST:
break;

case RTN_MULTICAST:
case RTN_BROADCAST:
case RTN_LOCAL:
SWSS_LOG_INFO("BUM routes aren't supported yet (%s)", destaddr);
return;

default:
return;
}

struct nl_list_head *nhs = rtnl_route_get_nexthops(route_obj);
if (!nhs)
{
SWSS_LOG_INFO("Nexthop list is empty for LabelRoute %s", destaddr);
return;
}

/* Get nexthop lists */
string gw_list;
string intf_list;
string mpls_list;
getNextHopList(route_obj, gw_list, mpls_list, intf_list);

vector<FieldValueTuple> fvVector;
FieldValueTuple gw("nexthop", gw_list);
FieldValueTuple intf("ifname", intf_list);
FieldValueTuple mpls_pop("mpls_pop", "1");

fvVector.push_back(gw);
fvVector.push_back(intf);
if (!mpls_list.empty())
{
FieldValueTuple mpls_nh("mpls_nh", mpls_list);
fvVector.push_back(mpls_nh);
}
fvVector.push_back(mpls_pop);

m_label_routeTable.set(destaddr, fvVector);
SWSS_LOG_INFO("LabelRouteTable set msg: %s %s %s %s", destaddr,
gw_list.c_str(), intf_list.c_str(), mpls_list.c_str());
}

/*
* Handle vnet route
* @arg nlmsg_type Netlink message type
* @arg obj Netlink object
Expand Down Expand Up @@ -902,6 +1010,123 @@ bool RouteSync::getIfName(int if_index, char *if_name, size_t name_len)
return true;
}

#ifndef LIBNL3_ENCAP_MPLS
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets remove this and update azure pipeline to fetch libnl3 debian package from sonic-buildimaage

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smaheshm I am not familiar with the azure pipeline infrastructure and will need input with exact changes required to fetch libnl3 debian packages from sonic-buildimage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smaheshm I have submitted a new PR sonic-net/sonic-buildimage#8064 that is the only other change required to make this PR work in the Azure pipeline as it is currently.

/* Thise stub is needed for sonic-swss Azure pipeline, since encap_mpls
* accessor is not yet upstreamed to external libnl3 project and sonic-swss
* uses released version of libnl3 rather than customized version available
* in sonic-buildimage.
*/
static
struct nl_addr *rtnl_route_nh_get_encap_mpls_dst(struct rtnl_nexthop *nh)
{
return NULL;
}
#endif // LIBNL3_ENCAP_MPLS

/*
* getNextHopList() - parses next hop list attached to route_obj
* @arg route_obj (input) Netlink route object
* @arg gw_list (output) comma-separated list of NH IP gateways
* @arg mpls_list (output) comma-separated list of NH MPLS info
* @arg intf_list (output) comma-separated list of NH interfaces
*
* Return void
*/
void RouteSync::getNextHopList(struct rtnl_route *route_obj, string& gw_list,
string& mpls_list, string& intf_list)
{
bool mpls_found = false;

for (int i = 0; i < rtnl_route_get_nnexthops(route_obj); i++)
{
struct rtnl_nexthop *nexthop = rtnl_route_nexthop_n(route_obj, i);
struct nl_addr *addr = NULL;

/* RTA_GATEWAY is NH gateway info for IP routes only */
if ((addr = rtnl_route_nh_get_gateway(nexthop)))
{
char gw_ip[MAX_ADDR_SIZE + 1] = {0};
nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE);
gw_list += gw_ip;

/* LWTUNNEL_ENCAP_MPLS RTA_DST is MPLS NH label stack for IP routes only */
if ((addr = rtnl_route_nh_get_encap_mpls_dst(nexthop)))
{
char labelstack[MAX_ADDR_SIZE + 1] = {0};
nl_addr2str(addr, labelstack, MAX_ADDR_SIZE);
mpls_list += string("push");
mpls_list += labelstack;
mpls_found = true;
}
/* Filler for proper parsing in routeorch */
else
{
mpls_list += string("na");
}
}
/* RTA_VIA is NH gateway info for MPLS routes only */
else if ((addr = rtnl_route_nh_get_via(nexthop)))
{
char gw_ip[MAX_ADDR_SIZE + 1] = {0};
nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE);
gw_list += gw_ip;

/* RTA_NEWDST is MPLS NH label stack for MPLS routes only */
if ((addr = rtnl_route_nh_get_newdst(nexthop)))
{
char labelstack[MAX_ADDR_SIZE + 1] = {0};
nl_addr2str(addr, labelstack, MAX_ADDR_SIZE);
mpls_list += string("swap");
mpls_list += labelstack;
mpls_found = true;
}
/* Filler for proper parsing in routeorch */
else
{
mpls_list += string("na");
}
}
else
{
if (rtnl_route_get_family(route_obj) == AF_INET6)
{
gw_list += "::";
}
/* for MPLS route, use IPv4 as default gateway. */
else
{
gw_list += "0.0.0.0";
}
mpls_list += string("na");
}

/* Get the ID of next hop interface */
unsigned if_index = rtnl_route_nh_get_ifindex(nexthop);
char if_name[IFNAMSIZ] = "0";
if (getIfName(if_index, if_name, IFNAMSIZ))
{
intf_list += if_name;
}
/* If we cannot get the interface name */
else
{
intf_list += "unknown";
}

if (i + 1 < rtnl_route_get_nnexthops(route_obj))
{
gw_list += NHG_DELIMITER;
mpls_list += NHG_DELIMITER;
intf_list += NHG_DELIMITER;
}
}

if (!mpls_found)
{
mpls_list.clear();
}
}

/*
* Get next hop gateway IP addresses
* @arg route_obj route object
Expand Down Expand Up @@ -938,7 +1163,7 @@ string RouteSync::getNextHopGw(struct rtnl_route *route_obj)

if (i + 1 < rtnl_route_get_nnexthops(route_obj))
{
result += string(",");
result += NHG_DELIMITER;
}
}

Expand Down Expand Up @@ -972,7 +1197,7 @@ string RouteSync::getNextHopIf(struct rtnl_route *route_obj)

if (i + 1 < rtnl_route_get_nnexthops(route_obj))
{
result += string(",");
result += NHG_DELIMITER;
}
}

Expand Down
9 changes: 9 additions & 0 deletions fpmsyncd/routesync.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class RouteSync : public NetMsg
private:
/* regular route table */
ProducerStateTable m_routeTable;
/* label route table */
ProducerStateTable m_label_routeTable;
/* vnet route table */
ProducerStateTable m_vnet_routeTable;
/* vnet vxlan tunnel table */
Expand All @@ -41,6 +43,9 @@ class RouteSync : public NetMsg
/* Handle regular route (include VRF route) */
void onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf);

/* Handle label route */
void onLabelRouteMsg(int nlmsg_type, struct nl_object *obj);

void parseEncap(struct rtattr *tb, uint32_t &encap_value, string &rmac);

void parseRtAttrNested(struct rtattr **tb, int max,
Expand Down Expand Up @@ -70,6 +75,10 @@ class RouteSync : public NetMsg
string& nexthops, string& vni_list, string& mac_list,
string& intf_list);

/* Get next hop list */
void getNextHopList(struct rtnl_route *route_obj, string& gw_list,
string& mpls_list, string& intf_list);

/* Get next hop gateway IP addresses */
string getNextHopGw(struct rtnl_route *route_obj);

Expand Down