linux-cp: handle ipv4 routes when link goes down
[vpp.git] / src / plugins / linux-cp / lcp_router.c
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <sys/socket.h>
17 #include <linux/if.h>
18
19 //#include <vlib/vlib.h>
20 #include <vlib/unix/plugin.h>
21 #include <linux-cp/lcp_nl.h>
22 #include <linux-cp/lcp_interface.h>
23
24 #include <netlink/msg.h>
25 #include <netlink/netlink.h>
26 #include <netlink/socket.h>
27 #include <netlink/route/link.h>
28 #include <netlink/route/route.h>
29 #include <netlink/route/neighbour.h>
30 #include <netlink/route/addr.h>
31 #include <netlink/route/link/vlan.h>
32
33 #include <vnet/fib/fib_table.h>
34 #include <vnet/mfib/mfib_table.h>
35 #include <vnet/ip/ip6_ll_table.h>
36 #include <vnet/ip-neighbor/ip_neighbor.h>
37 #include <vnet/ip/ip6_link.h>
38
39 typedef struct lcp_router_table_t_
40 {
41   uint32_t nlt_id;
42   fib_protocol_t nlt_proto;
43   u32 nlt_fib_index;
44   u32 nlt_mfib_index;
45   u32 nlt_refs;
46 } lcp_router_table_t;
47
48 static uword *lcp_router_table_db[FIB_PROTOCOL_MAX];
49 static lcp_router_table_t *lcp_router_table_pool;
50 static vlib_log_class_t lcp_router_logger;
51
52 const static fib_prefix_t pfx_all1s = {
53   .fp_addr = {
54     .ip4 = {
55       .as_u32 = 0xffffffff,
56     }
57   },
58   .fp_proto = FIB_PROTOCOL_IP4,
59   .fp_len = 32,
60 };
61
62 static fib_source_t lcp_rt_fib_src;
63 static fib_source_t lcp_rt_fib_src_dynamic;
64
65 #define LCP_ROUTER_DBG(...) vlib_log_debug (lcp_router_logger, __VA_ARGS__);
66
67 #define LCP_ROUTER_INFO(...) vlib_log_notice (lcp_router_logger, __VA_ARGS__);
68
69 #define LCP_ROUTER_ERROR(...) vlib_log_err (lcp_router_logger, __VA_ARGS__);
70
71 static const mfib_prefix_t ip4_specials[] = {
72   /* ALL prefixes are in network order */
73   {
74    /* (*,224.0.0.0)/24 - all local subnet */
75    .fp_grp_addr = {
76                    .ip4.data_u32 = 0x000000e0,
77                    },
78    .fp_len = 24,
79    .fp_proto = FIB_PROTOCOL_IP4,
80    },
81 };
82
83 static const mfib_prefix_t ip6_specials[] = {
84   /* ALL prefixes are in network order */
85   {
86    /* (*,ff00::)/8 - all local subnet */
87    .fp_grp_addr = {
88                    .ip6.as_u64[0] = 0x00000000000000ff,
89                    },
90    .fp_len = 8,
91    .fp_proto = FIB_PROTOCOL_IP6,
92    },
93 };
94
95 /* VIF to PHY DB of managed interfaces */
96 static uword *lcp_routing_itf_db;
97
98 static u32
99 lcp_router_intf_h2p (u32 host)
100 {
101   lcp_itf_pair_t *lip;
102   index_t lipi;
103   uword *p;
104
105   /*
106    * first check the linux side created interface (i.e. vlans, tunnels etc)
107    */
108   p = hash_get (lcp_routing_itf_db, host);
109
110   if (p)
111     return p[0];
112
113   /*
114    * then check the paired phys
115    */
116   lipi = lcp_itf_pair_find_by_vif (host);
117
118   if (INDEX_INVALID == lipi)
119     return (~0);
120
121   lip = lcp_itf_pair_get (lipi);
122
123   return lip->lip_phy_sw_if_index;
124 }
125
126 /*
127  * Check timestamps on netlink message and interface pair to decide whether
128  * the message should be applied. See the declaration of nl_msg_info_t for
129  * an explanation on why this is necessary.
130  * If timestamps are good (message ts is newer than intf pair ts), return 0.
131  * Else, return -1.
132  */
133 static int
134 lcp_router_lip_ts_check (nl_msg_info_t *msg_info, lcp_itf_pair_t *lip)
135 {
136   if (!msg_info)
137     return 0;
138
139   if (msg_info->ts > lip->lip_create_ts)
140     return 0;
141
142   LCP_ROUTER_INFO ("Early message received for %U",
143                    format_vnet_sw_if_index_name, vnet_get_main (),
144                    lip->lip_phy_sw_if_index);
145   return -1;
146 }
147
148 static void
149 lcp_router_link_del (struct rtnl_link *rl, void *ctx)
150 {
151   index_t lipi;
152
153   if (!lcp_auto_subint ())
154     return;
155
156   lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
157
158   if (INDEX_INVALID != lipi)
159     {
160       lcp_itf_pair_t *lip;
161
162       lip = lcp_itf_pair_get (lipi);
163
164       if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
165         return;
166
167       LCP_ROUTER_INFO ("delete link: %s - %U", rtnl_link_get_type (rl),
168                        format_vnet_sw_if_index_name, vnet_get_main (),
169                        lip->lip_phy_sw_if_index);
170       lcp_itf_pair_delete (lip->lip_phy_sw_if_index);
171
172       if (rtnl_link_is_vlan (rl))
173         {
174           LCP_ROUTER_INFO ("delete vlan: %s -> %U", rtnl_link_get_name (rl),
175                            format_vnet_sw_if_index_name, vnet_get_main (),
176                            lip->lip_phy_sw_if_index);
177           vnet_delete_sub_interface (lip->lip_phy_sw_if_index);
178           vnet_delete_sub_interface (lip->lip_host_sw_if_index);
179         }
180     }
181   else
182     LCP_ROUTER_INFO ("ignore link del: %s - %s", rtnl_link_get_type (rl),
183                      rtnl_link_get_name (rl));
184 }
185
186 static void
187 lcp_router_ip4_mroutes_add_del (u32 sw_if_index, u8 is_add)
188 {
189   const fib_route_path_t path = {
190     .frp_proto = DPO_PROTO_IP4,
191     .frp_addr = zero_addr,
192     .frp_sw_if_index = sw_if_index,
193     .frp_fib_index = ~0,
194     .frp_weight = 1,
195     .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
196   };
197   u32 mfib_index;
198   int ii;
199
200   mfib_index =
201     mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
202
203   for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
204     {
205       if (is_add)
206         {
207           mfib_table_entry_path_update (mfib_index, &ip4_specials[ii],
208                                         MFIB_SOURCE_PLUGIN_LOW,
209                                         MFIB_ENTRY_FLAG_NONE, &path);
210         }
211       else
212         {
213           mfib_table_entry_path_remove (mfib_index, &ip4_specials[ii],
214                                         MFIB_SOURCE_PLUGIN_LOW, &path);
215         }
216     }
217 }
218
219 static void
220 lcp_router_ip6_mroutes_add_del (u32 sw_if_index, u8 is_add)
221 {
222   const fib_route_path_t path = {
223     .frp_proto = DPO_PROTO_IP6,
224     .frp_addr = zero_addr,
225     .frp_sw_if_index = sw_if_index,
226     .frp_fib_index = ~0,
227     .frp_weight = 1,
228     .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
229   };
230   u32 mfib_index;
231   int ii;
232
233   mfib_index =
234     mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
235
236   for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
237     {
238       if (is_add)
239         {
240           mfib_table_entry_path_update (mfib_index, &ip6_specials[ii],
241                                         MFIB_SOURCE_PLUGIN_LOW,
242                                         MFIB_ENTRY_FLAG_NONE, &path);
243         }
244       else
245         {
246           mfib_table_entry_path_remove (mfib_index, &ip6_specials[ii],
247                                         MFIB_SOURCE_PLUGIN_LOW, &path);
248         }
249     }
250 }
251
252 static void
253 lcp_router_link_mtu (struct rtnl_link *rl, u32 sw_if_index)
254 {
255   vnet_main_t *vnm = vnet_get_main ();
256   u32 mtu;
257   vnet_sw_interface_t *sw;
258   vnet_hw_interface_t *hw;
259
260   mtu = rtnl_link_get_mtu (rl);
261   if (!mtu)
262     return;
263
264   sw = vnet_get_sw_interface (vnm, sw_if_index);
265   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
266
267   /* If HW interface, try to change hw link */
268   if ((sw->type == sw->sup_sw_if_index) &&
269       (hw->hw_class_index == ethernet_hw_interface_class.index))
270     vnet_hw_interface_set_mtu (vnm, hw->hw_if_index, mtu);
271   else
272     vnet_sw_interface_set_mtu (vnm, sw->sw_if_index, mtu);
273 }
274
275 static void
276 lcp_router_link_addr (struct rtnl_link *rl, lcp_itf_pair_t *lip)
277 {
278   vnet_main_t *vnm = vnet_get_main ();
279   struct nl_addr *mac_addr;
280   vnet_sw_interface_t *sw;
281   vnet_hw_interface_t *hw;
282   void *mac_addr_bytes;
283
284   mac_addr = rtnl_link_get_addr (rl);
285   if (!mac_addr || (nl_addr_get_family (mac_addr) != AF_LLC))
286     return;
287
288   sw = vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index);
289
290   /* can only change address on hw interface */
291   if (sw->sw_if_index != sw->sup_sw_if_index)
292     return;
293
294   hw = vnet_get_sup_hw_interface (vnm, lip->lip_phy_sw_if_index);
295   if (!vec_len (hw->hw_address))
296     return;
297
298   mac_addr_bytes = nl_addr_get_binary_addr (mac_addr);
299   if (clib_memcmp (mac_addr_bytes, hw->hw_address, nl_addr_get_len (mac_addr)))
300     vnet_hw_interface_change_mac_address (vnm, hw->hw_if_index,
301                                           mac_addr_bytes);
302
303   /* mcast adjacencies need to be updated */
304   vnet_update_adjacency_for_sw_interface (vnm, lip->lip_phy_sw_if_index,
305                                           lip->lip_phy_adjs.adj_index[AF_IP4]);
306   vnet_update_adjacency_for_sw_interface (vnm, lip->lip_phy_sw_if_index,
307                                           lip->lip_phy_adjs.adj_index[AF_IP6]);
308 }
309
310 static void lcp_router_table_flush (lcp_router_table_t *nlt, u32 sw_if_index,
311                                     fib_source_t source);
312
313 static void
314 lcp_router_link_add (struct rtnl_link *rl, void *ctx)
315 {
316   index_t lipi;
317   int up;
318   vnet_main_t *vnm = vnet_get_main ();
319
320   lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
321   up = IFF_UP & rtnl_link_get_flags (rl);
322
323   if (INDEX_INVALID != lipi)
324     {
325       lcp_itf_pair_t *lip;
326       u32 sw_if_flags;
327       u32 sw_if_up;
328
329       lip = lcp_itf_pair_get (lipi);
330       if (!vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index))
331         return;
332
333       if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
334         return;
335
336       sw_if_flags =
337         vnet_sw_interface_get_flags (vnm, lip->lip_phy_sw_if_index);
338       sw_if_up = (sw_if_flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
339
340       if (!sw_if_up && up)
341         {
342           vnet_sw_interface_admin_up (vnet_get_main (),
343                                       lip->lip_phy_sw_if_index);
344         }
345       else if (sw_if_up && !up)
346         {
347           vnet_sw_interface_admin_down (vnet_get_main (),
348                                         lip->lip_phy_sw_if_index);
349
350           /* When an interface is brought down administratively, the kernel
351            * removes routes which resolve through that interface. For IPv4
352            * routes, the kernel will not send any explicit RTM_DELROUTE
353            * messages about removing them. In order to synchronize with the
354            * kernel, affected IPv4 routes need to be manually removed from the
355            * FIB. The behavior is different for IPv6 routes. Explicit
356            * RTM_DELROUTE messages are sent about IPv6 routes being removed.
357            */
358           u32 fib_index;
359           lcp_router_table_t *nlt;
360
361           fib_index = fib_table_get_index_for_sw_if_index (
362             FIB_PROTOCOL_IP4, lip->lip_phy_sw_if_index);
363
364           pool_foreach (nlt, lcp_router_table_pool)
365             {
366               if (fib_index == nlt->nlt_fib_index &&
367                   FIB_PROTOCOL_IP4 == nlt->nlt_proto)
368                 {
369                   lcp_router_table_flush (nlt, lip->lip_phy_sw_if_index,
370                                           lcp_rt_fib_src);
371                   lcp_router_table_flush (nlt, lip->lip_phy_sw_if_index,
372                                           lcp_rt_fib_src_dynamic);
373                   break;
374                 }
375             }
376         }
377
378       LCP_ROUTER_DBG ("link: %s (%d) -> %U/%U %s", rtnl_link_get_name (rl),
379                       rtnl_link_get_ifindex (rl), format_vnet_sw_if_index_name,
380                       vnm, lip->lip_phy_sw_if_index,
381                       format_vnet_sw_if_index_name, vnm,
382                       lip->lip_host_sw_if_index, (up ? "up" : "down"));
383
384       lcp_router_link_mtu (rl, lip->lip_phy_sw_if_index);
385       lcp_router_link_addr (rl, lip);
386     }
387   else if (lcp_auto_subint () && rtnl_link_is_vlan (rl))
388     {
389       /* Find the pair based on the parent VIF */
390       lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_link (rl));
391
392       if (INDEX_INVALID != lipi)
393         {
394           u32 sub_phy_sw_if_index, sub_host_sw_if_index;
395           const lcp_itf_pair_t *lip;
396           int vlan;
397           u8 *ns = 0; /* FIXME */
398
399           lip = lcp_itf_pair_get (lipi);
400
401           vlan = rtnl_link_vlan_get_id (rl);
402
403           /* create the vlan interface on the parent phy */
404           if (vnet_create_sub_interface (lip->lip_phy_sw_if_index, vlan, 18, 0,
405                                          vlan, &sub_phy_sw_if_index))
406             {
407               LCP_ROUTER_INFO ("failed create phy vlan: %s on %U",
408                                rtnl_link_get_name (rl),
409                                format_vnet_sw_if_index_name, vnet_get_main (),
410                                lip->lip_phy_sw_if_index);
411               return;
412             }
413           /* create the vlan interface on the parent host */
414           if (vnet_create_sub_interface (lip->lip_host_sw_if_index, vlan, 18,
415                                          0, vlan, &sub_host_sw_if_index))
416             {
417               LCP_ROUTER_INFO ("failed create vlan: %s on %U",
418                                rtnl_link_get_name (rl),
419                                format_vnet_sw_if_index_name, vnet_get_main (),
420                                lip->lip_host_sw_if_index);
421               return;
422             }
423
424           char *if_name;
425           u8 *if_namev = 0;
426
427           LCP_ROUTER_INFO (
428             "create vlan: %s -> (%U, %U) : (%U, %U)", rtnl_link_get_name (rl),
429             format_vnet_sw_if_index_name, vnet_get_main (),
430             lip->lip_phy_sw_if_index, format_vnet_sw_if_index_name,
431             vnet_get_main (), sub_phy_sw_if_index,
432             format_vnet_sw_if_index_name, vnet_get_main (),
433             lip->lip_host_sw_if_index, format_vnet_sw_if_index_name,
434             vnet_get_main (), sub_host_sw_if_index);
435
436           if ((if_name = rtnl_link_get_name (rl)) != NULL)
437             vec_validate_init_c_string (if_namev, if_name,
438                                         strnlen (if_name, IFNAMSIZ));
439           lcp_itf_pair_add (sub_host_sw_if_index, sub_phy_sw_if_index,
440                             if_namev, rtnl_link_get_ifindex (rl),
441                             lip->lip_host_type, ns);
442           if (up)
443             vnet_sw_interface_admin_up (vnet_get_main (), sub_phy_sw_if_index);
444           vnet_sw_interface_admin_up (vnet_get_main (), sub_host_sw_if_index);
445
446           vec_free (if_namev);
447         }
448       else
449         {
450           LCP_ROUTER_INFO ("ignore parent-link add: %s - %s",
451                            rtnl_link_get_type (rl), rtnl_link_get_name (rl));
452         }
453     }
454   else
455     LCP_ROUTER_INFO ("ignore link add: %s - %s", rtnl_link_get_type (rl),
456                      rtnl_link_get_name (rl));
457 }
458
459 static void
460 lcp_router_link_sync_begin (void)
461 {
462   LCP_ROUTER_INFO ("Begin synchronization of interface configurations");
463 }
464
465 static void
466 lcp_router_link_sync_end (void)
467 {
468   LCP_ROUTER_INFO ("End synchronization of interface configurations");
469 }
470
471 static clib_error_t *
472 lcp_router_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
473 {
474   vnet_hw_interface_t *hi;
475   index_t lipi;
476
477   hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
478   if (!hi)
479     return 0;
480
481   lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
482   if (lipi == INDEX_INVALID)
483     return 0;
484
485   /* When the link goes down on an interface, the kernel processes routes which
486    * resolve through that interface depending on how they were created:
487    *   - Legacy Route API: the kernel retains the routes and marks them as
488    *     "linkdown";
489    *   - Nexthop API: the kernel removes the next-hop objects and the routes
490    *     which reference them.
491    *
492    * For IPv4 routes created with Nexthop API, the kernel will not send any
493    * explicit RTM_DELROUTE messages about removing them. In order to
494    * synchronize with the kernel, affected routes need to be manually removed
495    * from the FIB.
496    *
497    * The behavior is different for IPv6 routes created with Nexthop API. The
498    * kernel will send explicit RTM_DELROUTE messages about IPv6 routes being
499    * removed.
500    */
501   if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
502       (lcp_get_del_static_on_link_down () ||
503        lcp_get_del_dynamic_on_link_down ()))
504     {
505       u32 fib_index;
506       lcp_router_table_t *nlt;
507
508       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
509                                                        hi->sw_if_index);
510
511       pool_foreach (nlt, lcp_router_table_pool)
512         {
513           if (fib_index == nlt->nlt_fib_index &&
514               FIB_PROTOCOL_IP4 == nlt->nlt_proto)
515             {
516               if (lcp_get_del_static_on_link_down ())
517                 lcp_router_table_flush (nlt, hi->sw_if_index, lcp_rt_fib_src);
518               if (lcp_get_del_dynamic_on_link_down ())
519                 lcp_router_table_flush (nlt, hi->sw_if_index,
520                                         lcp_rt_fib_src_dynamic);
521               break;
522             }
523         }
524     }
525
526   return 0;
527 }
528
529 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_router_link_up_down);
530
531 static fib_protocol_t
532 lcp_router_proto_k2f (uint32_t k)
533 {
534   if (AF_INET6 == k)
535     return (FIB_PROTOCOL_IP6);
536   return (FIB_PROTOCOL_IP4);
537 }
538
539 static void
540 lcp_router_mk_addr (const struct nl_addr *rna, ip_address_t *ia)
541 {
542   fib_protocol_t fproto;
543
544   ip_address_reset (ia);
545   fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
546
547   ip_address_set (ia, nl_addr_get_binary_addr (rna),
548                   FIB_PROTOCOL_IP4 == fproto ? AF_IP4 : AF_IP6);
549 }
550
551 static fib_protocol_t
552 lcp_router_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
553 {
554   fib_protocol_t fproto;
555
556   fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
557   ip46_address_reset (ia);
558   if (FIB_PROTOCOL_IP4 == fproto)
559     memcpy (&ia->ip4, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
560   else
561     memcpy (&ia->ip6, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
562
563   return (fproto);
564 }
565
566 static void
567 lcp_router_link_addr_add_del (struct rtnl_addr *rla, int is_del)
568 {
569   u32 sw_if_index;
570
571   sw_if_index = lcp_router_intf_h2p (rtnl_addr_get_ifindex (rla));
572
573   if (~0 != sw_if_index)
574     {
575       ip_address_t nh;
576
577       lcp_router_mk_addr (rtnl_addr_get_local (rla), &nh);
578
579       if (AF_IP4 == ip_addr_version (&nh))
580         {
581           ip4_add_del_interface_address (
582             vlib_get_main (), sw_if_index, &ip_addr_v4 (&nh),
583             rtnl_addr_get_prefixlen (rla), is_del);
584           lcp_router_ip4_mroutes_add_del (sw_if_index, !is_del);
585         }
586       else if (AF_IP6 == ip_addr_version (&nh))
587         {
588           if (ip6_address_is_link_local_unicast (&ip_addr_v6 (&nh)))
589             if (is_del)
590               ip6_link_disable (sw_if_index);
591             else
592               {
593                 ip6_link_enable (sw_if_index, NULL);
594                 ip6_link_set_local_address (sw_if_index, &ip_addr_v6 (&nh));
595               }
596           else
597             ip6_add_del_interface_address (
598               vlib_get_main (), sw_if_index, &ip_addr_v6 (&nh),
599               rtnl_addr_get_prefixlen (rla), is_del);
600           lcp_router_ip6_mroutes_add_del (sw_if_index, !is_del);
601         }
602
603       LCP_ROUTER_DBG ("link-addr: %U %U/%d", format_vnet_sw_if_index_name,
604                       vnet_get_main (), sw_if_index, format_ip_address, &nh,
605                       rtnl_addr_get_prefixlen (rla));
606     }
607 }
608
609 static void
610 lcp_router_link_addr_del (struct rtnl_addr *la)
611 {
612   lcp_router_link_addr_add_del (la, 1);
613 }
614
615 static void
616 lcp_router_link_addr_add (struct rtnl_addr *la)
617 {
618   lcp_router_link_addr_add_del (la, 0);
619 }
620
621 static void
622 lcp_router_link_addr_sync_begin (void)
623 {
624   ip_interface_address_mark ();
625
626   LCP_ROUTER_INFO ("Begin synchronization of interface addresses");
627 }
628
629 static void
630 lcp_router_link_addr_sync_end (void)
631 {
632   ip_interface_address_sweep ();
633
634   LCP_ROUTER_INFO ("End synchronization of interface addresses");
635 }
636
637 static void
638 lcp_router_mk_mac_addr (const struct nl_addr *rna, mac_address_t *mac)
639 {
640   mac_address_from_bytes (mac, nl_addr_get_binary_addr (rna));
641 }
642
643 static void
644 lcp_router_neigh_del (struct rtnl_neigh *rn)
645 {
646   u32 sw_if_index;
647
648   sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
649
650   if (~0 != sw_if_index)
651     {
652       ip_address_t nh;
653       int rv;
654
655       lcp_router_mk_addr (rtnl_neigh_get_dst (rn), &nh);
656
657       if (ip46_address_is_multicast (&ip_addr_46 (&nh)))
658         {
659           LCP_ROUTER_DBG ("ignore neighbor del: %U %U", format_ip_address, &nh,
660                           format_vnet_sw_if_index_name, vnet_get_main (),
661                           sw_if_index);
662           return;
663         }
664
665       rv = ip_neighbor_del (&nh, sw_if_index);
666
667       if (rv)
668         {
669           LCP_ROUTER_ERROR (
670             "Failed to delete neighbor: %U %U", format_ip_address, &nh,
671             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
672         }
673       else
674         {
675           LCP_ROUTER_DBG ("neighbor del: %U %U", format_ip_address, &nh,
676                           format_vnet_sw_if_index_name, vnet_get_main (),
677                           sw_if_index);
678         }
679     }
680   else
681     LCP_ROUTER_INFO ("ignore neighbour del on: %d",
682                      rtnl_neigh_get_ifindex (rn));
683 }
684
685 #ifndef NUD_VALID
686 #define NUD_VALID                                                             \
687   (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE |        \
688    NUD_DELAY)
689 #endif
690
691 static void
692 lcp_router_neigh_add (struct rtnl_neigh *rn)
693 {
694   u32 sw_if_index;
695
696   sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
697
698   if (~0 != sw_if_index)
699     {
700       struct nl_addr *ll;
701       ip_address_t nh;
702       int state;
703
704       lcp_router_mk_addr (rtnl_neigh_get_dst (rn), &nh);
705
706       if (ip46_address_is_multicast (&ip_addr_46 (&nh)))
707         {
708           LCP_ROUTER_DBG ("ignore neighbor add: %U %U", format_ip_address, &nh,
709                           format_vnet_sw_if_index_name, vnet_get_main (),
710                           sw_if_index);
711           return;
712         }
713
714       ll = rtnl_neigh_get_lladdr (rn);
715       state = rtnl_neigh_get_state (rn);
716
717       if (ll && (state & NUD_VALID))
718         {
719           mac_address_t mac;
720           ip_neighbor_flags_t flags;
721           int rv;
722
723           lcp_router_mk_mac_addr (ll, &mac);
724
725           if (state & (NUD_NOARP | NUD_PERMANENT))
726             flags = IP_NEIGHBOR_FLAG_STATIC;
727           else
728             flags = IP_NEIGHBOR_FLAG_DYNAMIC;
729
730           rv = ip_neighbor_add (&nh, &mac, sw_if_index, flags, NULL);
731
732           if (rv)
733             {
734               LCP_ROUTER_ERROR (
735                 "Failed to create neighbor: %U %U", format_ip_address, &nh,
736                 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
737             }
738           else
739             {
740               LCP_ROUTER_DBG ("neighbor add: %U %U", format_ip_address, &nh,
741                               format_vnet_sw_if_index_name, vnet_get_main (),
742                               sw_if_index);
743             }
744         }
745       else
746         /* It's a delete */
747         lcp_router_neigh_del (rn);
748     }
749   else
750     LCP_ROUTER_INFO ("ignore neighbour add on: %d",
751                      rtnl_neigh_get_ifindex (rn));
752 }
753
754 static void
755 lcp_router_neigh_sync_begin (void)
756 {
757   ip_neighbor_mark (AF_IP4);
758   ip_neighbor_mark (AF_IP6);
759
760   LCP_ROUTER_INFO ("Begin synchronization of neighbors");
761 }
762
763 static void
764 lcp_router_neigh_sync_end (void)
765 {
766   ip_neighbor_sweep (AF_IP4);
767   ip_neighbor_sweep (AF_IP6);
768
769   LCP_ROUTER_INFO ("End synchronization of neighbors");
770 }
771
772 static lcp_router_table_t *
773 lcp_router_table_find (uint32_t id, fib_protocol_t fproto)
774 {
775   uword *p;
776
777   p = hash_get (lcp_router_table_db[fproto], id);
778
779   if (p)
780     return pool_elt_at_index (lcp_router_table_pool, p[0]);
781
782   return (NULL);
783 }
784
785 static uint32_t
786 lcp_router_table_k2f (uint32_t k)
787 {
788   // the kernel's table ID 255 is the default table
789   if (k == 255 || k == 254)
790     return 0;
791   return k;
792 }
793
794 static lcp_router_table_t *
795 lcp_router_table_add_or_lock (uint32_t id, fib_protocol_t fproto)
796 {
797   lcp_router_table_t *nlt;
798
799   id = lcp_router_table_k2f (id);
800   nlt = lcp_router_table_find (id, fproto);
801
802   if (NULL == nlt)
803     {
804       pool_get_zero (lcp_router_table_pool, nlt);
805
806       nlt->nlt_id = id;
807       nlt->nlt_proto = fproto;
808
809       nlt->nlt_fib_index = fib_table_find_or_create_and_lock (
810         nlt->nlt_proto, nlt->nlt_id, lcp_rt_fib_src);
811       nlt->nlt_mfib_index = mfib_table_find_or_create_and_lock (
812         nlt->nlt_proto, nlt->nlt_id, MFIB_SOURCE_PLUGIN_LOW);
813
814       hash_set (lcp_router_table_db[fproto], nlt->nlt_id,
815                 nlt - lcp_router_table_pool);
816
817       if (FIB_PROTOCOL_IP4 == fproto)
818         {
819           /* Set the all 1s address in this table to punt */
820           fib_table_entry_special_add (nlt->nlt_fib_index, &pfx_all1s,
821                                        lcp_rt_fib_src, FIB_ENTRY_FLAG_LOCAL);
822
823           const fib_route_path_t path = {
824             .frp_proto = DPO_PROTO_IP4,
825             .frp_addr = zero_addr,
826             .frp_sw_if_index = ~0,
827             .frp_fib_index = ~0,
828             .frp_weight = 1,
829             .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
830             .frp_flags = FIB_ROUTE_PATH_LOCAL,
831           };
832           int ii;
833
834           for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
835             {
836               mfib_table_entry_path_update (
837                 nlt->nlt_mfib_index, &ip4_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
838                 MFIB_ENTRY_FLAG_NONE, &path);
839             }
840         }
841       else if (FIB_PROTOCOL_IP6 == fproto)
842         {
843           const fib_route_path_t path = {
844             .frp_proto = DPO_PROTO_IP6,
845             .frp_addr = zero_addr,
846             .frp_sw_if_index = ~0,
847             .frp_fib_index = ~0,
848             .frp_weight = 1,
849             .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
850             .frp_flags = FIB_ROUTE_PATH_LOCAL,
851           };
852           int ii;
853
854           for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
855             {
856               mfib_table_entry_path_update (
857                 nlt->nlt_mfib_index, &ip6_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
858                 MFIB_ENTRY_FLAG_NONE, &path);
859             }
860         }
861     }
862
863   nlt->nlt_refs++;
864
865   return (nlt);
866 }
867
868 static void
869 lcp_router_table_unlock (lcp_router_table_t *nlt)
870 {
871   nlt->nlt_refs--;
872
873   if (0 == nlt->nlt_refs)
874     {
875       if (FIB_PROTOCOL_IP4 == nlt->nlt_proto)
876         {
877           /* Set the all 1s address in this table to punt */
878           fib_table_entry_special_remove (nlt->nlt_fib_index, &pfx_all1s,
879                                           lcp_rt_fib_src);
880         }
881
882       fib_table_unlock (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
883
884       hash_unset (lcp_router_table_db[nlt->nlt_proto], nlt->nlt_id);
885       pool_put (lcp_router_table_pool, nlt);
886     }
887 }
888
889 static void
890 lcp_router_route_mk_prefix (struct rtnl_route *r, fib_prefix_t *p)
891 {
892   const struct nl_addr *addr = rtnl_route_get_dst (r);
893
894   p->fp_len = nl_addr_get_prefixlen (addr);
895   p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_addr);
896 }
897
898 static void
899 lcp_router_route_mk_mprefix (struct rtnl_route *r, mfib_prefix_t *p)
900 {
901   const struct nl_addr *addr;
902
903   addr = rtnl_route_get_dst (r);
904
905   p->fp_len = nl_addr_get_prefixlen (addr);
906   p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_grp_addr);
907
908   addr = rtnl_route_get_src (r);
909   if (addr)
910     p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_src_addr);
911 }
912
913 typedef struct lcp_router_route_path_parse_t_
914 {
915   fib_route_path_t *paths;
916   fib_protocol_t route_proto;
917   bool is_mcast;
918   fib_route_path_flags_t type_flags;
919   u8 preference;
920 } lcp_router_route_path_parse_t;
921
922 static void
923 lcp_router_route_path_parse (struct rtnl_nexthop *rnh, void *arg)
924 {
925   lcp_router_route_path_parse_t *ctx = arg;
926   fib_route_path_t *path;
927   u32 sw_if_index;
928
929   sw_if_index = lcp_router_intf_h2p (rtnl_route_nh_get_ifindex (rnh));
930
931   if (~0 != sw_if_index)
932     {
933       fib_protocol_t fproto;
934       struct nl_addr *addr;
935
936       vec_add2 (ctx->paths, path, 1);
937
938       path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
939       path->frp_sw_if_index = sw_if_index;
940       path->frp_weight = rtnl_route_nh_get_weight (rnh);
941       path->frp_preference = ctx->preference;
942
943       addr = rtnl_route_nh_get_gateway (rnh);
944
945       if (addr)
946         fproto = lcp_router_mk_addr46 (rtnl_route_nh_get_gateway (rnh),
947                                        &path->frp_addr);
948       else
949         fproto = ctx->route_proto;
950
951       path->frp_proto = fib_proto_to_dpo (fproto);
952
953       if (ctx->is_mcast)
954         path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
955
956       LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
957     }
958 }
959
960 /*
961  * blackhole, unreachable, prohibit will not have a next hop in an
962  * RTM_NEWROUTE. Add a path for them.
963  */
964 static void
965 lcp_router_route_path_add_special (struct rtnl_route *rr,
966                                    lcp_router_route_path_parse_t *ctx)
967 {
968   fib_route_path_t *path;
969
970   if (rtnl_route_get_type (rr) < RTN_BLACKHOLE)
971     return;
972
973   /* if it already has a path, it does not need us to add one */
974   if (vec_len (ctx->paths) > 0)
975     return;
976
977   vec_add2 (ctx->paths, path, 1);
978
979   path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
980   path->frp_sw_if_index = ~0;
981   path->frp_proto = fib_proto_to_dpo (ctx->route_proto);
982   path->frp_preference = ctx->preference;
983
984   LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
985 }
986
987 /*
988  * Map of supported route types. Some types are omitted:
989  * RTN_LOCAL - interface address addition creates these automatically
990  * RTN_BROADCAST - same as RTN_LOCAL
991  * RTN_UNSPEC, RTN_ANYCAST, RTN_THROW, RTN_NAT, RTN_XRESOLVE -
992  *   There's not a VPP equivalent for these currently.
993  */
994 static const u8 lcp_router_route_type_valid[__RTN_MAX] = {
995   [RTN_UNICAST] = 1,     [RTN_MULTICAST] = 1, [RTN_BLACKHOLE] = 1,
996   [RTN_UNREACHABLE] = 1, [RTN_PROHIBIT] = 1,
997 };
998
999 /* Map of fib entry flags by route type */
1000 static const fib_entry_flag_t lcp_router_route_type_feflags[__RTN_MAX] = {
1001   [RTN_LOCAL] = FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED,
1002   [RTN_BROADCAST] = FIB_ENTRY_FLAG_DROP | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT,
1003   [RTN_BLACKHOLE] = FIB_ENTRY_FLAG_DROP,
1004 };
1005
1006 /* Map of fib route path flags by route type */
1007 static const fib_route_path_flags_t
1008   lcp_router_route_type_frpflags[__RTN_MAX] = {
1009     [RTN_UNREACHABLE] = FIB_ROUTE_PATH_ICMP_UNREACH,
1010     [RTN_PROHIBIT] = FIB_ROUTE_PATH_ICMP_PROHIBIT,
1011     [RTN_BLACKHOLE] = FIB_ROUTE_PATH_DROP,
1012   };
1013
1014 static inline fib_source_t
1015 lcp_router_proto_fib_source (u8 rt_proto)
1016 {
1017   return (rt_proto <= RTPROT_STATIC) ? lcp_rt_fib_src : lcp_rt_fib_src_dynamic;
1018 }
1019
1020 static fib_entry_flag_t
1021 lcp_router_route_mk_entry_flags (uint8_t rtype, int table_id, uint8_t rproto)
1022 {
1023   fib_entry_flag_t fef = FIB_ENTRY_FLAG_NONE;
1024
1025   fef |= lcp_router_route_type_feflags[rtype];
1026   if ((rproto == RTPROT_KERNEL) || PREDICT_FALSE (255 == table_id))
1027     /* kernel proto is interface prefixes, 255 is linux's 'local' table */
1028     fef |= FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED;
1029
1030   return (fef);
1031 }
1032
1033 static void
1034 lcp_router_route_del (struct rtnl_route *rr)
1035 {
1036   fib_entry_flag_t entry_flags;
1037   uint32_t table_id;
1038   fib_prefix_t pfx;
1039   lcp_router_table_t *nlt;
1040   uint8_t rtype, rproto;
1041
1042   rtype = rtnl_route_get_type (rr);
1043   table_id = rtnl_route_get_table (rr);
1044   rproto = rtnl_route_get_protocol (rr);
1045
1046   /* skip unsupported route types and local table */
1047   if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
1048     return;
1049
1050   lcp_router_route_mk_prefix (rr, &pfx);
1051   entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
1052   nlt = lcp_router_table_find (lcp_router_table_k2f (table_id), pfx.fp_proto);
1053
1054   LCP_ROUTER_DBG ("route del: %d:%U %U", rtnl_route_get_table (rr),
1055                   format_fib_prefix, &pfx, format_fib_entry_flags,
1056                   entry_flags);
1057
1058   if (NULL == nlt)
1059     return;
1060
1061   lcp_router_route_path_parse_t np = {
1062     .route_proto = pfx.fp_proto,
1063     .type_flags = lcp_router_route_type_frpflags[rtype],
1064   };
1065
1066   rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
1067   lcp_router_route_path_add_special (rr, &np);
1068
1069   if (0 != vec_len (np.paths))
1070     {
1071       fib_source_t fib_src;
1072
1073       fib_src = lcp_router_proto_fib_source (rproto);
1074
1075       if (pfx.fp_proto == FIB_PROTOCOL_IP6)
1076         fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
1077       else
1078         fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
1079                                       np.paths);
1080     }
1081
1082   vec_free (np.paths);
1083
1084   lcp_router_table_unlock (nlt);
1085 }
1086
1087 static void
1088 lcp_router_route_add (struct rtnl_route *rr)
1089 {
1090   fib_entry_flag_t entry_flags;
1091   uint32_t table_id;
1092   fib_prefix_t pfx;
1093   lcp_router_table_t *nlt;
1094   uint8_t rtype, rproto;
1095
1096   rtype = rtnl_route_get_type (rr);
1097   table_id = rtnl_route_get_table (rr);
1098   rproto = rtnl_route_get_protocol (rr);
1099
1100   /* skip unsupported route types and local table */
1101   if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
1102     return;
1103
1104   lcp_router_route_mk_prefix (rr, &pfx);
1105   entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
1106
1107   nlt = lcp_router_table_add_or_lock (table_id, pfx.fp_proto);
1108   /* Skip any kernel routes and IPv6 LL or multicast routes */
1109   if (rproto == RTPROT_KERNEL ||
1110       (FIB_PROTOCOL_IP6 == pfx.fp_proto &&
1111        (ip6_address_is_multicast (&pfx.fp_addr.ip6) ||
1112         ip6_address_is_link_local_unicast (&pfx.fp_addr.ip6))))
1113     {
1114       LCP_ROUTER_DBG ("route skip: %d:%U %U", rtnl_route_get_table (rr),
1115                       format_fib_prefix, &pfx, format_fib_entry_flags,
1116                       entry_flags);
1117     }
1118   else
1119     {
1120       LCP_ROUTER_DBG ("route add: %d:%U %U", rtnl_route_get_table (rr),
1121                       format_fib_prefix, &pfx, format_fib_entry_flags,
1122                       entry_flags);
1123
1124       lcp_router_route_path_parse_t np = {
1125         .route_proto = pfx.fp_proto,
1126         .is_mcast = (rtype == RTN_MULTICAST),
1127         .type_flags = lcp_router_route_type_frpflags[rtype],
1128         .preference = (u8) rtnl_route_get_priority (rr),
1129       };
1130
1131       rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
1132       lcp_router_route_path_add_special (rr, &np);
1133
1134       if (0 != vec_len (np.paths))
1135         {
1136           if (rtype == RTN_MULTICAST)
1137             {
1138               /* it's not clear to me how linux expresses the RPF paramters
1139                * so we'll allow from all interfaces and hope for the best */
1140               mfib_prefix_t mpfx = {};
1141
1142               lcp_router_route_mk_mprefix (rr, &mpfx);
1143
1144               mfib_table_entry_update (
1145                 nlt->nlt_mfib_index, &mpfx, MFIB_SOURCE_PLUGIN_LOW,
1146                 MFIB_RPF_ID_NONE, MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF);
1147
1148               mfib_table_entry_paths_update (nlt->nlt_mfib_index, &mpfx,
1149                                              MFIB_SOURCE_PLUGIN_LOW,
1150                                              MFIB_ENTRY_FLAG_NONE, np.paths);
1151             }
1152           else
1153             {
1154               fib_source_t fib_src;
1155
1156               fib_src = lcp_router_proto_fib_source (rproto);
1157
1158               if (pfx.fp_proto == FIB_PROTOCOL_IP6)
1159                 fib_table_entry_path_add2 (nlt->nlt_fib_index, &pfx, fib_src,
1160                                            entry_flags, np.paths);
1161               else
1162                 fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
1163                                         entry_flags, np.paths);
1164             }
1165         }
1166       else
1167         LCP_ROUTER_DBG ("no paths for route add: %d:%U %U",
1168                         rtnl_route_get_table (rr), format_fib_prefix, &pfx,
1169                         format_fib_entry_flags, entry_flags);
1170       vec_free (np.paths);
1171     }
1172 }
1173
1174 static void
1175 lcp_router_route_sync_begin (void)
1176 {
1177   lcp_router_table_t *nlt;
1178
1179   pool_foreach (nlt, lcp_router_table_pool)
1180     {
1181       fib_table_mark (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
1182       fib_table_mark (nlt->nlt_fib_index, nlt->nlt_proto,
1183                       lcp_rt_fib_src_dynamic);
1184
1185       LCP_ROUTER_INFO ("Begin synchronization of %U routes in table %u",
1186                        format_fib_protocol, nlt->nlt_proto,
1187                        nlt->nlt_fib_index);
1188     }
1189 }
1190
1191 static void
1192 lcp_router_route_sync_end (void)
1193 {
1194   lcp_router_table_t *nlt;
1195
1196   pool_foreach (nlt, lcp_router_table_pool)
1197     {
1198       fib_table_sweep (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
1199       fib_table_sweep (nlt->nlt_fib_index, nlt->nlt_proto,
1200                        lcp_rt_fib_src_dynamic);
1201
1202       LCP_ROUTER_INFO ("End synchronization of %U routes in table %u",
1203                        format_fib_protocol, nlt->nlt_proto,
1204                        nlt->nlt_fib_index);
1205     }
1206 }
1207
1208 typedef struct lcp_router_table_flush_ctx_t_
1209 {
1210   fib_node_index_t *lrtf_entries;
1211   u32 lrtf_sw_if_index;
1212   fib_source_t lrtf_source;
1213 } lcp_router_table_flush_ctx_t;
1214
1215 static fib_table_walk_rc_t
1216 lcp_router_table_flush_cb (fib_node_index_t fib_entry_index, void *arg)
1217 {
1218   lcp_router_table_flush_ctx_t *ctx = arg;
1219
1220   if (fib_entry_get_resolving_interface_for_source (
1221         fib_entry_index, ctx->lrtf_source) == ctx->lrtf_sw_if_index)
1222     {
1223       vec_add1 (ctx->lrtf_entries, fib_entry_index);
1224     }
1225   return (FIB_TABLE_WALK_CONTINUE);
1226 }
1227
1228 static void
1229 lcp_router_table_flush (lcp_router_table_t *nlt, u32 sw_if_index,
1230                         fib_source_t source)
1231 {
1232   fib_node_index_t *fib_entry_index;
1233   lcp_router_table_flush_ctx_t ctx = {
1234     .lrtf_entries = NULL,
1235     .lrtf_sw_if_index = sw_if_index,
1236     .lrtf_source = source,
1237   };
1238
1239   fib_table_walk (nlt->nlt_fib_index, nlt->nlt_proto,
1240                   lcp_router_table_flush_cb, &ctx);
1241
1242   LCP_ROUTER_DBG (
1243     "Flush table: proto %U, fib-index %u, resolved via %U for source %U",
1244     format_fib_protocol, nlt->nlt_proto, nlt->nlt_fib_index,
1245     format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
1246     format_fib_source, source);
1247
1248   vec_foreach (fib_entry_index, ctx.lrtf_entries)
1249     {
1250       fib_table_entry_delete_index (*fib_entry_index, source);
1251       lcp_router_table_unlock (nlt);
1252     }
1253
1254   vec_free (ctx.lrtf_entries);
1255 }
1256
1257 const nl_vft_t lcp_router_vft = {
1258   .nvl_rt_link_add = { .is_mp_safe = 0, .cb = lcp_router_link_add },
1259   .nvl_rt_link_del = { .is_mp_safe = 0, .cb = lcp_router_link_del },
1260   .nvl_rt_link_sync_begin = { .is_mp_safe = 0,
1261                               .cb = lcp_router_link_sync_begin },
1262   .nvl_rt_link_sync_end = { .is_mp_safe = 0, .cb = lcp_router_link_sync_end },
1263   .nvl_rt_addr_add = { .is_mp_safe = 0, .cb = lcp_router_link_addr_add },
1264   .nvl_rt_addr_del = { .is_mp_safe = 0, .cb = lcp_router_link_addr_del },
1265   .nvl_rt_addr_sync_begin = { .is_mp_safe = 0,
1266                               .cb = lcp_router_link_addr_sync_begin },
1267   .nvl_rt_addr_sync_end = { .is_mp_safe = 0,
1268                             .cb = lcp_router_link_addr_sync_end },
1269   .nvl_rt_neigh_add = { .is_mp_safe = 0, .cb = lcp_router_neigh_add },
1270   .nvl_rt_neigh_del = { .is_mp_safe = 0, .cb = lcp_router_neigh_del },
1271   .nvl_rt_neigh_sync_begin = { .is_mp_safe = 0,
1272                                .cb = lcp_router_neigh_sync_begin },
1273   .nvl_rt_neigh_sync_end = { .is_mp_safe = 0,
1274                              .cb = lcp_router_neigh_sync_end },
1275   .nvl_rt_route_add = { .is_mp_safe = 1, .cb = lcp_router_route_add },
1276   .nvl_rt_route_del = { .is_mp_safe = 1, .cb = lcp_router_route_del },
1277   .nvl_rt_route_sync_begin = { .is_mp_safe = 0,
1278                                .cb = lcp_router_route_sync_begin },
1279   .nvl_rt_route_sync_end = { .is_mp_safe = 0,
1280                              .cb = lcp_router_route_sync_end },
1281 };
1282
1283 static clib_error_t *
1284 lcp_router_init (vlib_main_t *vm)
1285 {
1286   lcp_router_logger = vlib_log_register_class ("linux-cp", "router");
1287
1288   nl_register_vft (&lcp_router_vft);
1289
1290   /*
1291    * allocate 2 route sources. The low priority source will be for
1292    * dynamic routes. If a dynamic route daemon (FRR) tries to remove its
1293    * route, it will use the low priority source to ensure it will not
1294    * remove static routes which were added with the higher priority source.
1295    */
1296   lcp_rt_fib_src =
1297     fib_source_allocate ("lcp-rt", FIB_SOURCE_PRIORITY_HI, FIB_SOURCE_BH_API);
1298
1299   lcp_rt_fib_src_dynamic = fib_source_allocate (
1300     "lcp-rt-dynamic", FIB_SOURCE_PRIORITY_HI + 1, FIB_SOURCE_BH_API);
1301
1302   return (NULL);
1303 }
1304
1305 VLIB_INIT_FUNCTION (lcp_router_init) = {
1306   .runs_before = VLIB_INITS ("lcp_nl_init"),
1307 };
1308
1309 /*
1310  * fd.io coding-style-patch-verification: ON
1311  *
1312  * Local Variables:
1313  * eval: (c-set-style "gnu")
1314  * End:
1315  */