Skip to content

Commit

Permalink
fpmsyncd updates for MPLS
Browse files Browse the repository at this point in the history
  • Loading branch information
qbdwlr committed Jun 23, 2021
1 parent 1e3a532 commit af3ff53
Show file tree
Hide file tree
Showing 2 changed files with 262 additions and 19 deletions.
272 changes: 253 additions & 19 deletions fpmsyncd/routesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ using namespace swss;
#define VNET_PREFIX "Vnet"
#define VRF_PREFIX "Vrf"

#define LABELSTACK_DELIMITER '+'
#define NHG_DELIMITER ','

#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
Expand All @@ -43,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 @@ -112,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 @@ -570,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 @@ -597,7 +607,6 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
{
onRouteMsg(nlmsg_type, obj, master_name);
}

}
else
{
Expand Down Expand Up @@ -698,10 +707,12 @@ 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);

vector<string> alsv = tokenize(ifnames, ',');
vector<string> alsv = tokenize(intf_list, NHG_DELIMITER);
for (auto alias : alsv)
{
/*
Expand All @@ -711,23 +722,28 @@ 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 (!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 @@ -736,8 +752,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 @@ -747,6 +763,105 @@ 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)
{
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);

string weights = getNextHopWt(route_obj);

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);
if (!weights.empty())
{
FieldValueTuple wt("weight", weights);
fvVector.push_back(wt);
}

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 @@ -886,6 +1001,125 @@ bool RouteSync::getIfName(int if_index, char *if_name, size_t name_len)
return true;
}

#ifndef LIBNL3_ENCAP_MPLS
/* 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_DELIMITER;
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_DELIMITER;
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 @@ -922,7 +1156,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 @@ -956,7 +1190,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

0 comments on commit af3ff53

Please sign in to comment.