99#include " producerstatetable.h"
1010#include " fpmsyncd/fpmlink.h"
1111#include " fpmsyncd/routesync.h"
12+ #include < string.h>
1213
1314using namespace std ;
1415using namespace swss ;
1516
17+ #define VXLAN_IF_NAME_PREFIX " brvxlan"
18+
1619RouteSync::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) :
2530void 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+ }
0 commit comments