9
9
#include " producerstatetable.h"
10
10
#include " fpmsyncd/fpmlink.h"
11
11
#include " fpmsyncd/routesync.h"
12
+ #include < string.h>
12
13
13
14
using namespace std ;
14
15
using namespace swss ;
15
16
17
+ #define VXLAN_IF_NAME_PREFIX " brvxlan"
18
+
16
19
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 ),
18
23
m_warmStartHelper(pipeline, &m_routeTable, APP_ROUTE_TABLE_NAME, " bgp" , " bgp" )
19
24
{
20
25
m_nl_sock = nl_socket_alloc ();
@@ -25,20 +30,41 @@ RouteSync::RouteSync(RedisPipeline *pipeline) :
25
30
void RouteSync::onMsg (int nlmsg_type, struct nl_object *obj)
26
31
{
27
32
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
+
34
34
/* Supports IPv4 or IPv6 address, otherwise return immediately */
35
35
auto family = rtnl_route_get_family (route_obj);
36
36
if (family != AF_INET && family != AF_INET6)
37
37
{
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));
39
39
return ;
40
40
}
41
41
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
+
42
68
/*
43
69
* Upon arrival of a delete msg we could either push the change right away,
44
70
* 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)
74
100
switch (rtnl_route_get_type (route_obj))
75
101
{
76
102
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
+ }
84
110
case RTN_UNICAST:
85
111
break ;
86
112
@@ -94,48 +120,16 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
94
120
return ;
95
121
}
96
122
97
- /* Geting nexthop lists */
98
- string nexthops;
99
- string ifnames;
100
-
101
123
struct nl_list_head *nhs = rtnl_route_get_nexthops (route_obj);
102
124
if (!nhs)
103
125
{
104
126
SWSS_LOG_INFO (" Nexthop list is empty for %s\n " , destipprefix);
105
127
return ;
106
128
}
107
129
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);
139
133
140
134
vector<FieldValueTuple> fvVector;
141
135
FieldValueTuple nh (" nexthop" , nexthops);
@@ -166,3 +160,206 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
166
160
m_warmStartHelper.insertRefreshMap (kfv);
167
161
}
168
162
}
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
+ }
0 commit comments