Skip to content

Commit 52de963

Browse files
baiwei0427lguohan
authored andcommitted
[fpmsyncd] Add VNET routes support (sonic-net#772)
* Add VNET support to fpmsyncd * Use marcos defined in SONiC SWSS common * Use { for new line * Use old variable names * Return if we cannot get VRF name * Use switch statement to handle route types * Add comment for future VRF routes support
1 parent d27f49e commit 52de963

File tree

2 files changed

+269
-50
lines changed

2 files changed

+269
-50
lines changed

fpmsyncd/routesync.cpp

+247-50
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@
99
#include "producerstatetable.h"
1010
#include "fpmsyncd/fpmlink.h"
1111
#include "fpmsyncd/routesync.h"
12+
#include <string.h>
1213

1314
using namespace std;
1415
using namespace swss;
1516

17+
#define VXLAN_IF_NAME_PREFIX "brvxlan"
18+
1619
RouteSync::RouteSync(RedisPipeline *pipeline) :
17-
m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true),
20+
m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true),
21+
m_vnet_routeTable(pipeline, APP_VNET_RT_TABLE_NAME, true),
22+
m_vnet_tunnelTable(pipeline, APP_VNET_RT_TUNNEL_TABLE_NAME, true),
1823
m_warmStartHelper(pipeline, &m_routeTable, APP_ROUTE_TABLE_NAME, "bgp", "bgp")
1924
{
2025
m_nl_sock = nl_socket_alloc();
@@ -25,20 +30,41 @@ RouteSync::RouteSync(RedisPipeline *pipeline) :
2530
void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
2631
{
2732
struct rtnl_route *route_obj = (struct rtnl_route *)obj;
28-
struct nl_addr *dip;
29-
char destipprefix[MAX_ADDR_SIZE + 1] = {0};
30-
31-
dip = rtnl_route_get_dst(route_obj);
32-
nl_addr2str(dip, destipprefix, MAX_ADDR_SIZE);
33-
SWSS_LOG_DEBUG("Receive new route message dest ip prefix: %s\n", destipprefix);
33+
3434
/* Supports IPv4 or IPv6 address, otherwise return immediately */
3535
auto family = rtnl_route_get_family(route_obj);
3636
if (family != AF_INET && family != AF_INET6)
3737
{
38-
SWSS_LOG_INFO("Unknown route family support: %s (object: %s)\n", destipprefix, nl_object_get_type(obj));
38+
SWSS_LOG_INFO("Unknown route family support (object: %s)\n", nl_object_get_type(obj));
3939
return;
4040
}
4141

42+
/* Get the index of routing table */
43+
unsigned int table_index = rtnl_route_get_table(route_obj);
44+
45+
/* Default routing table. This line may have problems. */
46+
if (table_index == RT_TABLE_UNSPEC)
47+
{
48+
onRouteMsg(nlmsg_type, obj);
49+
}
50+
/* VNET route. We will handle VRF routes in the future. */
51+
else
52+
{
53+
onVnetRouteMsg(nlmsg_type, obj);
54+
}
55+
}
56+
57+
/* Handle regular route (without vnet) */
58+
void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj)
59+
{
60+
struct rtnl_route *route_obj = (struct rtnl_route *)obj;
61+
struct nl_addr *dip;
62+
char destipprefix[MAX_ADDR_SIZE + 1] = {0};
63+
64+
dip = rtnl_route_get_dst(route_obj);
65+
nl_addr2str(dip, destipprefix, MAX_ADDR_SIZE);
66+
SWSS_LOG_DEBUG("Receive new route message dest ip prefix: %s\n", destipprefix);
67+
4268
/*
4369
* Upon arrival of a delete msg we could either push the change right away,
4470
* or we could opt to defer it if we are going through a warm-reboot cycle.
@@ -74,13 +100,13 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
74100
switch (rtnl_route_get_type(route_obj))
75101
{
76102
case RTN_BLACKHOLE:
77-
{
78-
vector<FieldValueTuple> fvVector;
79-
FieldValueTuple fv("blackhole", "true");
80-
fvVector.push_back(fv);
81-
m_routeTable.set(destipprefix, fvVector);
82-
return;
83-
}
103+
{
104+
vector<FieldValueTuple> fvVector;
105+
FieldValueTuple fv("blackhole", "true");
106+
fvVector.push_back(fv);
107+
m_routeTable.set(destipprefix, fvVector);
108+
return;
109+
}
84110
case RTN_UNICAST:
85111
break;
86112

@@ -94,48 +120,16 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
94120
return;
95121
}
96122

97-
/* Geting nexthop lists */
98-
string nexthops;
99-
string ifnames;
100-
101123
struct nl_list_head *nhs = rtnl_route_get_nexthops(route_obj);
102124
if (!nhs)
103125
{
104126
SWSS_LOG_INFO("Nexthop list is empty for %s\n", destipprefix);
105127
return;
106128
}
107129

108-
char ifname[IFNAMSIZ] = {0};
109-
for (int i = 0; i < rtnl_route_get_nnexthops(route_obj); i++)
110-
{
111-
struct rtnl_nexthop *nexthop = rtnl_route_nexthop_n(route_obj, i);
112-
struct nl_addr *addr = rtnl_route_nh_get_gateway(nexthop);
113-
unsigned int ifindex = rtnl_route_nh_get_ifindex(nexthop);
114-
115-
if (addr != NULL)
116-
{
117-
char gwipprefix[MAX_ADDR_SIZE + 1] = {0};
118-
nl_addr2str(addr, gwipprefix, MAX_ADDR_SIZE);
119-
nexthops += gwipprefix;
120-
}
121-
122-
rtnl_link_i2name(m_link_cache, ifindex, ifname, IFNAMSIZ);
123-
/* Cannot get ifname. Possibly interfaces get re-created. */
124-
if (!strlen(ifname))
125-
{
126-
rtnl_link_alloc_cache(m_nl_sock, AF_UNSPEC, &m_link_cache);
127-
rtnl_link_i2name(m_link_cache, ifindex, ifname, IFNAMSIZ);
128-
if (!strlen(ifname))
129-
strcpy(ifname, "unknown");
130-
}
131-
ifnames += ifname;
132-
133-
if (i + 1 < rtnl_route_get_nnexthops(route_obj))
134-
{
135-
nexthops += string(",");
136-
ifnames += string(",");
137-
}
138-
}
130+
/* Get nexthop lists */
131+
string nexthops = getNextHopGw(route_obj);
132+
string ifnames = getNextHopIf(route_obj);
139133

140134
vector<FieldValueTuple> fvVector;
141135
FieldValueTuple nh("nexthop", nexthops);
@@ -166,3 +160,206 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
166160
m_warmStartHelper.insertRefreshMap(kfv);
167161
}
168162
}
163+
164+
/* Handle vnet route */
165+
void RouteSync::onVnetRouteMsg(int nlmsg_type, struct nl_object *obj)
166+
{
167+
struct rtnl_route *route_obj = (struct rtnl_route *)obj;
168+
169+
/* Get the destination IP prefix */
170+
struct nl_addr *dip = rtnl_route_get_dst(route_obj);
171+
char destipprefix[MAX_ADDR_SIZE + 1] = {0};
172+
nl_addr2str(dip, destipprefix, MAX_ADDR_SIZE);
173+
174+
/* Get VRF index and VRF name */
175+
unsigned int vrf_index = rtnl_route_get_table(route_obj);
176+
char vrf_name[IFNAMSIZ] = {0};
177+
178+
/* If we cannot get the VRF name */
179+
if (!getIfName(vrf_index, vrf_name, IFNAMSIZ))
180+
{
181+
SWSS_LOG_INFO("Fail to get the VRF name (table ID %u)\n", vrf_index);
182+
return;
183+
}
184+
185+
/* vrf name = vnet name */
186+
string vnet_dip = vrf_name + string(":") + destipprefix;
187+
SWSS_LOG_DEBUG("Receive new vnet route message %s\n", vnet_dip.c_str());
188+
189+
if (nlmsg_type == RTM_DELROUTE)
190+
{
191+
/* Duplicated delete as we do not know if it is a VXLAN tunnel route*/
192+
m_vnet_routeTable.del(vnet_dip);
193+
m_vnet_tunnelTable.del(vnet_dip);
194+
return;
195+
}
196+
else if (nlmsg_type != RTM_NEWROUTE)
197+
{
198+
SWSS_LOG_INFO("Unknown message-type: %d for %s\n", nlmsg_type, vnet_dip.c_str());
199+
return;
200+
}
201+
202+
switch (rtnl_route_get_type(route_obj))
203+
{
204+
case RTN_UNICAST:
205+
break;
206+
207+
/* We may support blackhole in the future */
208+
case RTN_BLACKHOLE:
209+
SWSS_LOG_INFO("Blackhole route is supported yet (%s)\n", vnet_dip.c_str());
210+
return;
211+
212+
case RTN_MULTICAST:
213+
case RTN_BROADCAST:
214+
case RTN_LOCAL:
215+
SWSS_LOG_INFO("BUM routes aren't supported yet (%s)\n", vnet_dip.c_str());
216+
return;
217+
218+
default:
219+
return;
220+
}
221+
222+
struct nl_list_head *nhs = rtnl_route_get_nexthops(route_obj);
223+
if (!nhs)
224+
{
225+
SWSS_LOG_INFO("Nexthop list is empty for %s\n", vnet_dip.c_str());
226+
return;
227+
}
228+
229+
/* Get nexthop lists */
230+
string nexthops = getNextHopGw(route_obj);
231+
string ifnames = getNextHopIf(route_obj);
232+
233+
/* If the the first interface name starts with VXLAN_IF_NAME_PREFIX,
234+
the route is a VXLAN tunnel route. */
235+
if (ifnames.find(VXLAN_IF_NAME_PREFIX) == 0)
236+
{
237+
vector<FieldValueTuple> fvVector;
238+
FieldValueTuple ep("endpoint", nexthops);
239+
fvVector.push_back(ep);
240+
241+
m_vnet_tunnelTable.set(vnet_dip, fvVector);
242+
SWSS_LOG_DEBUG("%s set msg: %s %s\n",
243+
APP_VNET_RT_TUNNEL_TABLE_NAME, vnet_dip.c_str(), nexthops.c_str());
244+
return;
245+
}
246+
/* Regular VNET route */
247+
else
248+
{
249+
vector<FieldValueTuple> fvVector;
250+
FieldValueTuple idx("ifname", ifnames);
251+
fvVector.push_back(idx);
252+
253+
/* If the route has at least one next hop gateway, e.g., nexthops does not only have ',' */
254+
if (nexthops.length() + 1 > (unsigned int)rtnl_route_get_nnexthops(route_obj))
255+
{
256+
FieldValueTuple nh("nexthop", nexthops);
257+
fvVector.push_back(nh);
258+
SWSS_LOG_DEBUG("%s set msg: %s %s %s\n",
259+
APP_VNET_RT_TABLE_NAME, vnet_dip.c_str(), ifnames.c_str(), nexthops.c_str());
260+
}
261+
else
262+
{
263+
SWSS_LOG_DEBUG("%s set msg: %s %s\n",
264+
APP_VNET_RT_TABLE_NAME, vnet_dip.c_str(), ifnames.c_str());
265+
}
266+
267+
m_vnet_routeTable.set(vnet_dip, fvVector);
268+
}
269+
}
270+
271+
/*
272+
* Get interface/VRF name based on interface/VRF index
273+
* @arg if_index Interface/VRF index
274+
* @arg if_name String to store interface name
275+
* @arg name_len Length of destination string, including terminating zero byte
276+
*
277+
* Return true if we successfully gets the interface/VRF name.
278+
*/
279+
bool RouteSync::getIfName(int if_index, char *if_name, size_t name_len)
280+
{
281+
if (!if_name || name_len == 0)
282+
{
283+
return false;
284+
}
285+
286+
memset(if_name, 0, name_len);
287+
288+
/* Cannot get interface name. Possibly the interface gets re-created. */
289+
if (!rtnl_link_i2name(m_link_cache, if_index, if_name, name_len))
290+
{
291+
rtnl_link_alloc_cache(m_nl_sock, AF_UNSPEC, &m_link_cache);
292+
if (!rtnl_link_i2name(m_link_cache, if_index, if_name, name_len))
293+
{
294+
return false;
295+
}
296+
}
297+
298+
return true;
299+
}
300+
301+
/*
302+
* Get next hop gateway IP addresses
303+
* @arg route_obj route object
304+
*
305+
* Return concatenation of IP addresses: gw0 + "," + gw1 + .... + "," + gwN
306+
*/
307+
string RouteSync::getNextHopGw(struct rtnl_route *route_obj)
308+
{
309+
string result = "";
310+
311+
for (int i = 0; i < rtnl_route_get_nnexthops(route_obj); i++)
312+
{
313+
struct rtnl_nexthop *nexthop = rtnl_route_nexthop_n(route_obj, i);
314+
struct nl_addr *addr = rtnl_route_nh_get_gateway(nexthop);
315+
316+
/* Next hop gateway is not empty */
317+
if (addr)
318+
{
319+
char gw_ip[MAX_ADDR_SIZE + 1] = {0};
320+
nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE);
321+
result += gw_ip;
322+
}
323+
324+
if (i + 1 < rtnl_route_get_nnexthops(route_obj))
325+
{
326+
result += string(",");
327+
}
328+
}
329+
330+
return result;
331+
}
332+
333+
/*
334+
* Get next hop interface names
335+
* @arg route_obj route object
336+
*
337+
* Return concatenation of interface names: if0 + "," + if1 + .... + "," + ifN
338+
*/
339+
string RouteSync::getNextHopIf(struct rtnl_route *route_obj)
340+
{
341+
string result = "";
342+
343+
for (int i = 0; i < rtnl_route_get_nnexthops(route_obj); i++)
344+
{
345+
struct rtnl_nexthop *nexthop = rtnl_route_nexthop_n(route_obj, i);
346+
/* Get the ID of next hop interface */
347+
unsigned if_index = rtnl_route_nh_get_ifindex(nexthop);
348+
char if_name[IFNAMSIZ] = "0";
349+
350+
/* If we cannot get the interface name */
351+
if (!getIfName(if_index, if_name, IFNAMSIZ))
352+
{
353+
strcpy(if_name, "unknown");
354+
}
355+
356+
result += if_name;
357+
358+
if (i + 1 < rtnl_route_get_nnexthops(route_obj))
359+
{
360+
result += string(",");
361+
}
362+
}
363+
364+
return result;
365+
}

fpmsyncd/routesync.h

+22
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
#include "producerstatetable.h"
66
#include "netmsg.h"
77
#include "warmRestartHelper.h"
8+
#include <string.h>
89

10+
using namespace std;
911

1012
namespace swss {
1113

@@ -21,9 +23,29 @@ class RouteSync : public NetMsg
2123
WarmStartHelper m_warmStartHelper;
2224

2325
private:
26+
/* regular route table */
2427
ProducerStateTable m_routeTable;
28+
/* vnet route table */
29+
ProducerStateTable m_vnet_routeTable;
30+
/* vnet vxlan tunnel table */
31+
ProducerStateTable m_vnet_tunnelTable;
2532
struct nl_cache *m_link_cache;
2633
struct nl_sock *m_nl_sock;
34+
35+
/* Handle regular route (without vnet) */
36+
void onRouteMsg(int nlmsg_type, struct nl_object *obj);
37+
38+
/* Handle vnet route */
39+
void onVnetRouteMsg(int nlmsg_type, struct nl_object *obj);
40+
41+
/* Get interface/VRF name based on interface/VRF index */
42+
bool getIfName(int if_index, char *if_name, size_t name_len);
43+
44+
/* Get next hop gateway IP addresses */
45+
string getNextHopGw(struct rtnl_route *route_obj);
46+
47+
/* Get next hop interfaces */
48+
string getNextHopIf(struct rtnl_route *route_obj);
2749
};
2850

2951
}

0 commit comments

Comments
 (0)