linux-cp: handle AF_BRIDGE neighbors
[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->sw_if_index == 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,
311                                     u32 *sw_if_index_to_bool,
312                                     fib_source_t source);
313
314 static void
315 lcp_router_link_add (struct rtnl_link *rl, void *ctx)
316 {
317   index_t lipi;
318   int up;
319   vnet_main_t *vnm = vnet_get_main ();
320
321   lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
322   up = IFF_UP & rtnl_link_get_flags (rl);
323
324   if (INDEX_INVALID != lipi)
325     {
326       lcp_itf_pair_t *lip;
327       u32 sw_if_flags;
328       u32 sw_if_up;
329
330       lip = lcp_itf_pair_get (lipi);
331       if (!vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index))
332         return;
333
334       if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
335         return;
336
337       sw_if_flags =
338         vnet_sw_interface_get_flags (vnm, lip->lip_phy_sw_if_index);
339       sw_if_up = (sw_if_flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
340
341       if (!sw_if_up && up)
342         {
343           vnet_sw_interface_admin_up (vnet_get_main (),
344                                       lip->lip_phy_sw_if_index);
345         }
346       else if (sw_if_up && !up)
347         {
348           vnet_sw_interface_admin_down (vnet_get_main (),
349                                         lip->lip_phy_sw_if_index);
350
351           /* When an interface is brought down administratively, the kernel
352            * removes routes which resolve through that interface. For IPv4
353            * routes, the kernel will not send any explicit RTM_DELROUTE
354            * messages about removing them. In order to synchronize with the
355            * kernel, affected IPv4 routes need to be manually removed from the
356            * FIB. The behavior is different for IPv6 routes. Explicit
357            * RTM_DELROUTE messages are sent about IPv6 routes being removed.
358            */
359           u32 fib_index;
360           lcp_router_table_t *nlt;
361
362           fib_index = fib_table_get_index_for_sw_if_index (
363             FIB_PROTOCOL_IP4, lip->lip_phy_sw_if_index);
364
365           pool_foreach (nlt, lcp_router_table_pool)
366             {
367               if (fib_index == nlt->nlt_fib_index &&
368                   FIB_PROTOCOL_IP4 == nlt->nlt_proto)
369                 {
370                   u32 *sw_if_index_to_bool = NULL;
371
372                   vec_validate_init_empty (sw_if_index_to_bool,
373                                            lip->lip_phy_sw_if_index, false);
374                   sw_if_index_to_bool[lip->lip_phy_sw_if_index] = true;
375
376                   lcp_router_table_flush (nlt, sw_if_index_to_bool,
377                                           lcp_rt_fib_src);
378                   lcp_router_table_flush (nlt, sw_if_index_to_bool,
379                                           lcp_rt_fib_src_dynamic);
380
381                   vec_free (sw_if_index_to_bool);
382                   break;
383                 }
384             }
385         }
386
387       LCP_ROUTER_DBG ("link: %s (%d) -> %U/%U %s", rtnl_link_get_name (rl),
388                       rtnl_link_get_ifindex (rl), format_vnet_sw_if_index_name,
389                       vnm, lip->lip_phy_sw_if_index,
390                       format_vnet_sw_if_index_name, vnm,
391                       lip->lip_host_sw_if_index, (up ? "up" : "down"));
392
393       lcp_router_link_mtu (rl, lip->lip_phy_sw_if_index);
394       lcp_router_link_addr (rl, lip);
395     }
396   else if (lcp_auto_subint () && rtnl_link_is_vlan (rl))
397     {
398       /* Find the pair based on the parent VIF */
399       lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_link (rl));
400
401       if (INDEX_INVALID != lipi)
402         {
403           u32 sub_phy_sw_if_index, sub_host_sw_if_index;
404           const lcp_itf_pair_t *lip;
405           int vlan;
406           u8 *ns = 0; /* FIXME */
407
408           lip = lcp_itf_pair_get (lipi);
409
410           vlan = rtnl_link_vlan_get_id (rl);
411
412           /* create the vlan interface on the parent phy */
413           if (vnet_create_sub_interface (lip->lip_phy_sw_if_index, vlan, 18, 0,
414                                          vlan, &sub_phy_sw_if_index))
415             {
416               LCP_ROUTER_INFO ("failed create phy vlan: %s on %U",
417                                rtnl_link_get_name (rl),
418                                format_vnet_sw_if_index_name, vnet_get_main (),
419                                lip->lip_phy_sw_if_index);
420               return;
421             }
422           /* create the vlan interface on the parent host */
423           if (vnet_create_sub_interface (lip->lip_host_sw_if_index, vlan, 18,
424                                          0, vlan, &sub_host_sw_if_index))
425             {
426               LCP_ROUTER_INFO ("failed create vlan: %s on %U",
427                                rtnl_link_get_name (rl),
428                                format_vnet_sw_if_index_name, vnet_get_main (),
429                                lip->lip_host_sw_if_index);
430               return;
431             }
432
433           char *if_name;
434           u8 *if_namev = 0;
435
436           LCP_ROUTER_INFO (
437             "create vlan: %s -> (%U, %U) : (%U, %U)", rtnl_link_get_name (rl),
438             format_vnet_sw_if_index_name, vnet_get_main (),
439             lip->lip_phy_sw_if_index, format_vnet_sw_if_index_name,
440             vnet_get_main (), sub_phy_sw_if_index,
441             format_vnet_sw_if_index_name, vnet_get_main (),
442             lip->lip_host_sw_if_index, format_vnet_sw_if_index_name,
443             vnet_get_main (), sub_host_sw_if_index);
444
445           if ((if_name = rtnl_link_get_name (rl)) != NULL)
446             vec_validate_init_c_string (if_namev, if_name,
447                                         strnlen (if_name, IFNAMSIZ));
448           lcp_itf_pair_add (sub_host_sw_if_index, sub_phy_sw_if_index,
449                             if_namev, rtnl_link_get_ifindex (rl),
450                             lip->lip_host_type, ns);
451           if (up)
452             vnet_sw_interface_admin_up (vnet_get_main (), sub_phy_sw_if_index);
453           vnet_sw_interface_admin_up (vnet_get_main (), sub_host_sw_if_index);
454
455           vec_free (if_namev);
456         }
457       else
458         {
459           LCP_ROUTER_INFO ("ignore parent-link add: %s - %s",
460                            rtnl_link_get_type (rl), rtnl_link_get_name (rl));
461         }
462     }
463   else
464     LCP_ROUTER_INFO ("ignore link add: %s - %s", rtnl_link_get_type (rl),
465                      rtnl_link_get_name (rl));
466 }
467
468 static void
469 lcp_router_link_sync_begin (void)
470 {
471   LCP_ROUTER_INFO ("Begin synchronization of interface configurations");
472 }
473
474 static void
475 lcp_router_link_sync_end (void)
476 {
477   LCP_ROUTER_INFO ("End synchronization of interface configurations");
478 }
479
480 static clib_error_t *
481 lcp_router_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
482 {
483   vnet_hw_interface_t *hi;
484   index_t lipi;
485
486   hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
487   if (!hi)
488     return 0;
489
490   lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
491   if (lipi == INDEX_INVALID)
492     return 0;
493
494   /* When the link goes down on an interface, the kernel processes routes which
495    * resolve through that interface depending on how they were created:
496    *   - Legacy Route API: the kernel retains the routes and marks them as
497    *     "linkdown";
498    *   - Nexthop API: the kernel removes the next-hop objects and the routes
499    *     which reference them.
500    *
501    * For IPv4 routes created with Nexthop API, the kernel will not send any
502    * explicit RTM_DELROUTE messages about removing them. In order to
503    * synchronize with the kernel, affected routes need to be manually removed
504    * from the FIB.
505    *
506    * The behavior is different for IPv6 routes created with Nexthop API. The
507    * kernel will send explicit RTM_DELROUTE messages about IPv6 routes being
508    * removed.
509    */
510   if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
511       (lcp_get_del_static_on_link_down () ||
512        lcp_get_del_dynamic_on_link_down ()))
513     {
514       u32 fib_index;
515       u32 **fib_index_to_sw_if_index_to_bool = NULL;
516       u32 id, sw_if_index;
517       lcp_router_table_t *nlt;
518
519       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
520                                                        hi->sw_if_index);
521
522       vec_validate_init_empty (fib_index_to_sw_if_index_to_bool, fib_index,
523                                NULL);
524       vec_validate_init_empty (fib_index_to_sw_if_index_to_bool[fib_index],
525                                hi->sw_if_index, false);
526       fib_index_to_sw_if_index_to_bool[fib_index][hi->sw_if_index] = true;
527
528       /* clang-format off */
529       hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
530       ({
531         fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
532                                                          sw_if_index);
533         vec_validate_init_empty (fib_index_to_sw_if_index_to_bool, fib_index,
534                                  NULL);
535         vec_validate_init_empty (fib_index_to_sw_if_index_to_bool[fib_index],
536                                  sw_if_index, false);
537         fib_index_to_sw_if_index_to_bool[fib_index][sw_if_index] = true;
538       }));
539       /* clang-format on */
540
541       vec_foreach_index (fib_index, fib_index_to_sw_if_index_to_bool)
542         {
543           u32 *sw_if_index_to_bool;
544
545           sw_if_index_to_bool = fib_index_to_sw_if_index_to_bool[fib_index];
546           if (NULL == sw_if_index_to_bool)
547             continue;
548
549           pool_foreach (nlt, lcp_router_table_pool)
550             {
551               if (fib_index == nlt->nlt_fib_index &&
552                   FIB_PROTOCOL_IP4 == nlt->nlt_proto)
553                 {
554                   if (lcp_get_del_static_on_link_down ())
555                     lcp_router_table_flush (nlt, sw_if_index_to_bool,
556                                             lcp_rt_fib_src);
557                   if (lcp_get_del_dynamic_on_link_down ())
558                     lcp_router_table_flush (nlt, sw_if_index_to_bool,
559                                             lcp_rt_fib_src_dynamic);
560                   break;
561                 }
562             }
563
564           vec_free (sw_if_index_to_bool);
565         }
566
567       vec_free (fib_index_to_sw_if_index_to_bool);
568     }
569
570   return 0;
571 }
572
573 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_router_link_up_down);
574
575 static fib_protocol_t
576 lcp_router_proto_k2f (uint32_t k)
577 {
578   if (AF_INET6 == k)
579     return (FIB_PROTOCOL_IP6);
580   return (FIB_PROTOCOL_IP4);
581 }
582
583 static void
584 lcp_router_mk_addr (const struct nl_addr *rna, ip_address_t *ia)
585 {
586   fib_protocol_t fproto;
587
588   ip_address_reset (ia);
589   fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
590
591   ip_address_set (ia, nl_addr_get_binary_addr (rna),
592                   FIB_PROTOCOL_IP4 == fproto ? AF_IP4 : AF_IP6);
593 }
594
595 static fib_protocol_t
596 lcp_router_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
597 {
598   fib_protocol_t fproto;
599
600   fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
601   ip46_address_reset (ia);
602   if (FIB_PROTOCOL_IP4 == fproto)
603     memcpy (&ia->ip4, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
604   else
605     memcpy (&ia->ip6, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
606
607   return (fproto);
608 }
609
610 static void
611 lcp_router_link_addr_add_del (struct rtnl_addr *rla, int is_del)
612 {
613   u32 sw_if_index;
614
615   sw_if_index = lcp_router_intf_h2p (rtnl_addr_get_ifindex (rla));
616
617   if (~0 != sw_if_index)
618     {
619       ip_address_t nh;
620
621       lcp_router_mk_addr (rtnl_addr_get_local (rla), &nh);
622
623       if (AF_IP4 == ip_addr_version (&nh))
624         {
625           ip4_add_del_interface_address (
626             vlib_get_main (), sw_if_index, &ip_addr_v4 (&nh),
627             rtnl_addr_get_prefixlen (rla), is_del);
628           lcp_router_ip4_mroutes_add_del (sw_if_index, !is_del);
629         }
630       else if (AF_IP6 == ip_addr_version (&nh))
631         {
632           if (ip6_address_is_link_local_unicast (&ip_addr_v6 (&nh)))
633             if (is_del)
634               ip6_link_disable (sw_if_index);
635             else
636               {
637                 ip6_link_enable (sw_if_index, NULL);
638                 ip6_link_set_local_address (sw_if_index, &ip_addr_v6 (&nh));
639               }
640           else
641             ip6_add_del_interface_address (
642               vlib_get_main (), sw_if_index, &ip_addr_v6 (&nh),
643               rtnl_addr_get_prefixlen (rla), is_del);
644           lcp_router_ip6_mroutes_add_del (sw_if_index, !is_del);
645         }
646
647       LCP_ROUTER_DBG ("link-addr: %U %U/%d", format_vnet_sw_if_index_name,
648                       vnet_get_main (), sw_if_index, format_ip_address, &nh,
649                       rtnl_addr_get_prefixlen (rla));
650     }
651 }
652
653 static void
654 lcp_router_link_addr_del (struct rtnl_addr *la)
655 {
656   lcp_router_link_addr_add_del (la, 1);
657 }
658
659 static void
660 lcp_router_link_addr_add (struct rtnl_addr *la)
661 {
662   lcp_router_link_addr_add_del (la, 0);
663 }
664
665 static walk_rc_t
666 lcp_router_address_mark (index_t index, void *ctx)
667 {
668   vnet_main_t *vnm = vnet_get_main ();
669
670   lcp_itf_pair_t *lip = lcp_itf_pair_get (index);
671   if (!lip)
672     return WALK_CONTINUE;
673
674   ip_interface_address_mark_one_interface (
675     vnm, vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index), 0);
676
677   return WALK_CONTINUE;
678 }
679
680 static void
681 lcp_router_link_addr_sync_begin (void)
682 {
683   lcp_itf_pair_walk (lcp_router_address_mark, 0);
684
685   LCP_ROUTER_INFO ("Begin synchronization of interface addresses");
686 }
687
688 static void
689 lcp_router_link_addr_sync_end (void)
690 {
691   ip_interface_address_sweep ();
692
693   LCP_ROUTER_INFO ("End synchronization of interface addresses");
694 }
695
696 static void
697 lcp_router_mk_mac_addr (const struct nl_addr *rna, mac_address_t *mac)
698 {
699   mac_address_from_bytes (mac, nl_addr_get_binary_addr (rna));
700 }
701
702 static void
703 lcp_router_neigh_del (struct rtnl_neigh *rn)
704 {
705   u32 sw_if_index;
706
707   sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
708
709   if (~0 != sw_if_index)
710     {
711       ip_address_t nh;
712       int rv;
713       struct nl_addr *rna;
714
715       if ((rna = rtnl_neigh_get_dst (rn)) == NULL)
716         return;
717       lcp_router_mk_addr (rna, &nh);
718
719       if (ip46_address_is_multicast (&ip_addr_46 (&nh)))
720         {
721           LCP_ROUTER_DBG ("ignore neighbor del: %U %U", format_ip_address, &nh,
722                           format_vnet_sw_if_index_name, vnet_get_main (),
723                           sw_if_index);
724           return;
725         }
726
727       rv = ip_neighbor_del (&nh, sw_if_index);
728
729       if (rv)
730         {
731           LCP_ROUTER_ERROR (
732             "Failed to delete neighbor: %U %U", format_ip_address, &nh,
733             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
734         }
735       else
736         {
737           LCP_ROUTER_DBG ("neighbor del: %U %U", format_ip_address, &nh,
738                           format_vnet_sw_if_index_name, vnet_get_main (),
739                           sw_if_index);
740         }
741     }
742   else
743     LCP_ROUTER_INFO ("ignore neighbour del on: %d",
744                      rtnl_neigh_get_ifindex (rn));
745 }
746
747 #ifndef NUD_VALID
748 #define NUD_VALID                                                             \
749   (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE |        \
750    NUD_DELAY)
751 #endif
752
753 static void
754 lcp_router_neigh_add (struct rtnl_neigh *rn)
755 {
756   u32 sw_if_index;
757
758   sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
759
760   if (~0 != sw_if_index)
761     {
762       struct nl_addr *ll;
763       ip_address_t nh;
764       int state;
765       struct nl_addr *rna;
766
767       if ((rna = rtnl_neigh_get_dst (rn)) == NULL)
768         return;
769       lcp_router_mk_addr (rna, &nh);
770
771       if (ip46_address_is_multicast (&ip_addr_46 (&nh)))
772         {
773           LCP_ROUTER_DBG ("ignore neighbor add: %U %U", format_ip_address, &nh,
774                           format_vnet_sw_if_index_name, vnet_get_main (),
775                           sw_if_index);
776           return;
777         }
778
779       ll = rtnl_neigh_get_lladdr (rn);
780       state = rtnl_neigh_get_state (rn);
781
782       if (ll && (state & NUD_VALID))
783         {
784           mac_address_t mac;
785           ip_neighbor_flags_t flags;
786           int rv;
787
788           lcp_router_mk_mac_addr (ll, &mac);
789
790           if (state & (NUD_NOARP | NUD_PERMANENT))
791             flags = IP_NEIGHBOR_FLAG_STATIC;
792           else
793             flags = IP_NEIGHBOR_FLAG_DYNAMIC;
794
795           rv = ip_neighbor_add (&nh, &mac, sw_if_index, flags, NULL);
796
797           if (rv)
798             {
799               LCP_ROUTER_ERROR (
800                 "Failed to create neighbor: %U %U", format_ip_address, &nh,
801                 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
802             }
803           else
804             {
805               LCP_ROUTER_DBG ("neighbor add: %U %U", format_ip_address, &nh,
806                               format_vnet_sw_if_index_name, vnet_get_main (),
807                               sw_if_index);
808             }
809         }
810       else
811         /* It's a delete */
812         lcp_router_neigh_del (rn);
813     }
814   else
815     LCP_ROUTER_INFO ("ignore neighbour add on: %d",
816                      rtnl_neigh_get_ifindex (rn));
817 }
818
819 static walk_rc_t
820 lcp_router_neighbor_mark (index_t index, void *ctx)
821 {
822   lcp_itf_pair_t *lip = lcp_itf_pair_get (index);
823   if (!lip)
824     return WALK_CONTINUE;
825
826   ip_neighbor_walk (AF_IP4, lip->lip_phy_sw_if_index, ip_neighbor_mark_one, 0);
827   ip_neighbor_walk (AF_IP6, lip->lip_phy_sw_if_index, ip_neighbor_mark_one, 0);
828
829   return WALK_CONTINUE;
830 }
831
832 static void
833 lcp_router_neigh_sync_begin (void)
834 {
835   lcp_itf_pair_walk (lcp_router_neighbor_mark, 0);
836
837   LCP_ROUTER_INFO ("Begin synchronization of neighbors");
838 }
839
840 static void
841 lcp_router_neigh_sync_end (void)
842 {
843   ip_neighbor_sweep (AF_IP4);
844   ip_neighbor_sweep (AF_IP6);
845
846   LCP_ROUTER_INFO ("End synchronization of neighbors");
847 }
848
849 static lcp_router_table_t *
850 lcp_router_table_find (uint32_t id, fib_protocol_t fproto)
851 {
852   uword *p;
853
854   p = hash_get (lcp_router_table_db[fproto], id);
855
856   if (p)
857     return pool_elt_at_index (lcp_router_table_pool, p[0]);
858
859   return (NULL);
860 }
861
862 static uint32_t
863 lcp_router_table_k2f (uint32_t k)
864 {
865   // the kernel's table ID 255 is the default table
866   if (k == 255 || k == 254)
867     return 0;
868   return k;
869 }
870
871 static lcp_router_table_t *
872 lcp_router_table_add_or_lock (uint32_t id, fib_protocol_t fproto)
873 {
874   lcp_router_table_t *nlt;
875
876   id = lcp_router_table_k2f (id);
877   nlt = lcp_router_table_find (id, fproto);
878
879   if (NULL == nlt)
880     {
881       pool_get_zero (lcp_router_table_pool, nlt);
882
883       nlt->nlt_id = id;
884       nlt->nlt_proto = fproto;
885
886       nlt->nlt_fib_index = fib_table_find_or_create_and_lock (
887         nlt->nlt_proto, nlt->nlt_id, lcp_rt_fib_src);
888       nlt->nlt_mfib_index = mfib_table_find_or_create_and_lock (
889         nlt->nlt_proto, nlt->nlt_id, MFIB_SOURCE_PLUGIN_LOW);
890
891       hash_set (lcp_router_table_db[fproto], nlt->nlt_id,
892                 nlt - lcp_router_table_pool);
893
894       if (FIB_PROTOCOL_IP4 == fproto)
895         {
896           /* Set the all 1s address in this table to punt */
897           fib_table_entry_special_add (nlt->nlt_fib_index, &pfx_all1s,
898                                        lcp_rt_fib_src, FIB_ENTRY_FLAG_LOCAL);
899
900           const fib_route_path_t path = {
901             .frp_proto = DPO_PROTO_IP4,
902             .frp_addr = zero_addr,
903             .frp_sw_if_index = ~0,
904             .frp_fib_index = ~0,
905             .frp_weight = 1,
906             .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
907             .frp_flags = FIB_ROUTE_PATH_LOCAL,
908           };
909           int ii;
910
911           for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
912             {
913               mfib_table_entry_path_update (
914                 nlt->nlt_mfib_index, &ip4_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
915                 MFIB_ENTRY_FLAG_NONE, &path);
916             }
917         }
918       else if (FIB_PROTOCOL_IP6 == fproto)
919         {
920           const fib_route_path_t path = {
921             .frp_proto = DPO_PROTO_IP6,
922             .frp_addr = zero_addr,
923             .frp_sw_if_index = ~0,
924             .frp_fib_index = ~0,
925             .frp_weight = 1,
926             .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
927             .frp_flags = FIB_ROUTE_PATH_LOCAL,
928           };
929           int ii;
930
931           for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
932             {
933               mfib_table_entry_path_update (
934                 nlt->nlt_mfib_index, &ip6_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
935                 MFIB_ENTRY_FLAG_NONE, &path);
936             }
937         }
938     }
939
940   nlt->nlt_refs++;
941
942   return (nlt);
943 }
944
945 static void
946 lcp_router_table_unlock (lcp_router_table_t *nlt)
947 {
948   nlt->nlt_refs--;
949
950   if (0 == nlt->nlt_refs)
951     {
952       if (FIB_PROTOCOL_IP4 == nlt->nlt_proto)
953         {
954           /* Set the all 1s address in this table to punt */
955           fib_table_entry_special_remove (nlt->nlt_fib_index, &pfx_all1s,
956                                           lcp_rt_fib_src);
957         }
958
959       fib_table_unlock (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
960
961       hash_unset (lcp_router_table_db[nlt->nlt_proto], nlt->nlt_id);
962       pool_put (lcp_router_table_pool, nlt);
963     }
964 }
965
966 static void
967 lcp_router_route_mk_prefix (struct rtnl_route *r, fib_prefix_t *p)
968 {
969   const struct nl_addr *addr = rtnl_route_get_dst (r);
970
971   p->fp_len = nl_addr_get_prefixlen (addr);
972   p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_addr);
973 }
974
975 static void
976 lcp_router_route_mk_mprefix (struct rtnl_route *r, mfib_prefix_t *p)
977 {
978   const struct nl_addr *addr;
979
980   addr = rtnl_route_get_dst (r);
981
982   p->fp_len = nl_addr_get_prefixlen (addr);
983   p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_grp_addr);
984
985   addr = rtnl_route_get_src (r);
986   if (addr)
987     p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_src_addr);
988 }
989
990 typedef struct lcp_router_route_path_parse_t_
991 {
992   fib_route_path_t *paths;
993   fib_protocol_t route_proto;
994   bool is_mcast;
995   fib_route_path_flags_t type_flags;
996   u8 preference;
997 } lcp_router_route_path_parse_t;
998
999 static void
1000 lcp_router_route_path_parse (struct rtnl_nexthop *rnh, void *arg)
1001 {
1002   lcp_router_route_path_parse_t *ctx = arg;
1003   fib_route_path_t *path;
1004   u32 sw_if_index;
1005
1006   sw_if_index = lcp_router_intf_h2p (rtnl_route_nh_get_ifindex (rnh));
1007
1008   if (~0 != sw_if_index)
1009     {
1010       fib_protocol_t fproto;
1011       struct nl_addr *addr;
1012
1013       vec_add2 (ctx->paths, path, 1);
1014
1015       path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
1016       path->frp_sw_if_index = sw_if_index;
1017       path->frp_weight = rtnl_route_nh_get_weight (rnh);
1018       path->frp_preference = ctx->preference;
1019
1020       addr = rtnl_route_nh_get_gateway (rnh);
1021
1022       if (addr)
1023         fproto = lcp_router_mk_addr46 (rtnl_route_nh_get_gateway (rnh),
1024                                        &path->frp_addr);
1025       else
1026         fproto = ctx->route_proto;
1027
1028       path->frp_proto = fib_proto_to_dpo (fproto);
1029
1030       if (ctx->is_mcast)
1031         path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
1032
1033       LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
1034     }
1035 }
1036
1037 /*
1038  * blackhole, unreachable, prohibit will not have a next hop in an
1039  * RTM_NEWROUTE. Add a path for them.
1040  */
1041 static void
1042 lcp_router_route_path_add_special (struct rtnl_route *rr,
1043                                    lcp_router_route_path_parse_t *ctx)
1044 {
1045   fib_route_path_t *path;
1046
1047   if (rtnl_route_get_type (rr) < RTN_BLACKHOLE)
1048     return;
1049
1050   /* if it already has a path, it does not need us to add one */
1051   if (vec_len (ctx->paths) > 0)
1052     return;
1053
1054   vec_add2 (ctx->paths, path, 1);
1055
1056   path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
1057   path->frp_sw_if_index = ~0;
1058   path->frp_proto = fib_proto_to_dpo (ctx->route_proto);
1059   path->frp_preference = ctx->preference;
1060
1061   LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
1062 }
1063
1064 /*
1065  * Map of supported route types. Some types are omitted:
1066  * RTN_LOCAL - interface address addition creates these automatically
1067  * RTN_BROADCAST - same as RTN_LOCAL
1068  * RTN_UNSPEC, RTN_ANYCAST, RTN_THROW, RTN_NAT, RTN_XRESOLVE -
1069  *   There's not a VPP equivalent for these currently.
1070  */
1071 static const u8 lcp_router_route_type_valid[__RTN_MAX] = {
1072   [RTN_UNICAST] = 1,     [RTN_MULTICAST] = 1, [RTN_BLACKHOLE] = 1,
1073   [RTN_UNREACHABLE] = 1, [RTN_PROHIBIT] = 1,
1074 };
1075
1076 /* Map of fib entry flags by route type */
1077 static const fib_entry_flag_t lcp_router_route_type_feflags[__RTN_MAX] = {
1078   [RTN_LOCAL] = FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED,
1079   [RTN_BROADCAST] = FIB_ENTRY_FLAG_DROP | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT,
1080   [RTN_BLACKHOLE] = FIB_ENTRY_FLAG_DROP,
1081 };
1082
1083 /* Map of fib route path flags by route type */
1084 static const fib_route_path_flags_t
1085   lcp_router_route_type_frpflags[__RTN_MAX] = {
1086     [RTN_UNREACHABLE] = FIB_ROUTE_PATH_ICMP_UNREACH,
1087     [RTN_PROHIBIT] = FIB_ROUTE_PATH_ICMP_PROHIBIT,
1088     [RTN_BLACKHOLE] = FIB_ROUTE_PATH_DROP,
1089   };
1090
1091 static inline fib_source_t
1092 lcp_router_proto_fib_source (u8 rt_proto)
1093 {
1094   return (rt_proto <= RTPROT_STATIC) ? lcp_rt_fib_src : lcp_rt_fib_src_dynamic;
1095 }
1096
1097 static fib_entry_flag_t
1098 lcp_router_route_mk_entry_flags (uint8_t rtype, int table_id, uint8_t rproto)
1099 {
1100   fib_entry_flag_t fef = FIB_ENTRY_FLAG_NONE;
1101
1102   fef |= lcp_router_route_type_feflags[rtype];
1103   if ((rproto == RTPROT_KERNEL) || PREDICT_FALSE (255 == table_id))
1104     /* kernel proto is interface prefixes, 255 is linux's 'local' table */
1105     fef |= FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED;
1106
1107   return (fef);
1108 }
1109
1110 static void
1111 lcp_router_route_del (struct rtnl_route *rr)
1112 {
1113   fib_entry_flag_t entry_flags;
1114   uint32_t table_id;
1115   fib_prefix_t pfx;
1116   lcp_router_table_t *nlt;
1117   uint8_t rtype, rproto;
1118
1119   rtype = rtnl_route_get_type (rr);
1120   table_id = rtnl_route_get_table (rr);
1121   rproto = rtnl_route_get_protocol (rr);
1122
1123   /* skip unsupported route types and local table */
1124   if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
1125     return;
1126
1127   lcp_router_route_mk_prefix (rr, &pfx);
1128   entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
1129   nlt = lcp_router_table_find (lcp_router_table_k2f (table_id), pfx.fp_proto);
1130
1131   LCP_ROUTER_DBG ("route del: %d:%U %U", rtnl_route_get_table (rr),
1132                   format_fib_prefix, &pfx, format_fib_entry_flags,
1133                   entry_flags);
1134
1135   if (NULL == nlt)
1136     return;
1137
1138   lcp_router_route_path_parse_t np = {
1139     .route_proto = pfx.fp_proto,
1140     .type_flags = lcp_router_route_type_frpflags[rtype],
1141   };
1142
1143   rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
1144   lcp_router_route_path_add_special (rr, &np);
1145
1146   if (0 != vec_len (np.paths))
1147     {
1148       fib_source_t fib_src;
1149
1150       fib_src = lcp_router_proto_fib_source (rproto);
1151
1152       if (pfx.fp_proto == FIB_PROTOCOL_IP6)
1153         fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
1154       else
1155         fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
1156                                       np.paths);
1157     }
1158
1159   vec_free (np.paths);
1160
1161   lcp_router_table_unlock (nlt);
1162 }
1163
1164 static void
1165 lcp_router_route_add (struct rtnl_route *rr)
1166 {
1167   fib_entry_flag_t entry_flags;
1168   uint32_t table_id;
1169   fib_prefix_t pfx;
1170   lcp_router_table_t *nlt;
1171   uint8_t rtype, rproto;
1172
1173   rtype = rtnl_route_get_type (rr);
1174   table_id = rtnl_route_get_table (rr);
1175   rproto = rtnl_route_get_protocol (rr);
1176
1177   /* skip unsupported route types and local table */
1178   if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
1179     return;
1180
1181   lcp_router_route_mk_prefix (rr, &pfx);
1182   entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
1183
1184   nlt = lcp_router_table_add_or_lock (table_id, pfx.fp_proto);
1185   /* Skip any kernel routes and IPv6 LL or multicast routes */
1186   if (rproto == RTPROT_KERNEL ||
1187       (FIB_PROTOCOL_IP6 == pfx.fp_proto &&
1188        (ip6_address_is_multicast (&pfx.fp_addr.ip6) ||
1189         ip6_address_is_link_local_unicast (&pfx.fp_addr.ip6))))
1190     {
1191       LCP_ROUTER_DBG ("route skip: %d:%U %U", rtnl_route_get_table (rr),
1192                       format_fib_prefix, &pfx, format_fib_entry_flags,
1193                       entry_flags);
1194     }
1195   else
1196     {
1197       LCP_ROUTER_DBG ("route add: %d:%U %U", rtnl_route_get_table (rr),
1198                       format_fib_prefix, &pfx, format_fib_entry_flags,
1199                       entry_flags);
1200
1201       lcp_router_route_path_parse_t np = {
1202         .route_proto = pfx.fp_proto,
1203         .is_mcast = (rtype == RTN_MULTICAST),
1204         .type_flags = lcp_router_route_type_frpflags[rtype],
1205         .preference = (u8) rtnl_route_get_priority (rr),
1206       };
1207
1208       rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
1209       lcp_router_route_path_add_special (rr, &np);
1210
1211       if (0 != vec_len (np.paths))
1212         {
1213           if (rtype == RTN_MULTICAST)
1214             {
1215               /* it's not clear to me how linux expresses the RPF paramters
1216                * so we'll allow from all interfaces and hope for the best */
1217               mfib_prefix_t mpfx = {};
1218
1219               lcp_router_route_mk_mprefix (rr, &mpfx);
1220
1221               mfib_table_entry_update (
1222                 nlt->nlt_mfib_index, &mpfx, MFIB_SOURCE_PLUGIN_LOW,
1223                 MFIB_RPF_ID_NONE, MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF);
1224
1225               mfib_table_entry_paths_update (nlt->nlt_mfib_index, &mpfx,
1226                                              MFIB_SOURCE_PLUGIN_LOW,
1227                                              MFIB_ENTRY_FLAG_NONE, np.paths);
1228             }
1229           else
1230             {
1231               fib_source_t fib_src;
1232
1233               fib_src = lcp_router_proto_fib_source (rproto);
1234
1235               if (pfx.fp_proto == FIB_PROTOCOL_IP6)
1236                 fib_table_entry_path_add2 (nlt->nlt_fib_index, &pfx, fib_src,
1237                                            entry_flags, np.paths);
1238               else
1239                 fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
1240                                         entry_flags, np.paths);
1241             }
1242         }
1243       else
1244         LCP_ROUTER_DBG ("no paths for route add: %d:%U %U",
1245                         rtnl_route_get_table (rr), format_fib_prefix, &pfx,
1246                         format_fib_entry_flags, entry_flags);
1247       vec_free (np.paths);
1248     }
1249 }
1250
1251 static void
1252 lcp_router_route_sync_begin (void)
1253 {
1254   lcp_router_table_t *nlt;
1255
1256   pool_foreach (nlt, lcp_router_table_pool)
1257     {
1258       fib_table_mark (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
1259       fib_table_mark (nlt->nlt_fib_index, nlt->nlt_proto,
1260                       lcp_rt_fib_src_dynamic);
1261
1262       LCP_ROUTER_INFO ("Begin synchronization of %U routes in table %u",
1263                        format_fib_protocol, nlt->nlt_proto,
1264                        nlt->nlt_fib_index);
1265     }
1266 }
1267
1268 static void
1269 lcp_router_route_sync_end (void)
1270 {
1271   lcp_router_table_t *nlt;
1272
1273   pool_foreach (nlt, lcp_router_table_pool)
1274     {
1275       fib_table_sweep (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
1276       fib_table_sweep (nlt->nlt_fib_index, nlt->nlt_proto,
1277                        lcp_rt_fib_src_dynamic);
1278
1279       LCP_ROUTER_INFO ("End synchronization of %U routes in table %u",
1280                        format_fib_protocol, nlt->nlt_proto,
1281                        nlt->nlt_fib_index);
1282     }
1283 }
1284
1285 typedef struct lcp_router_table_flush_ctx_t_
1286 {
1287   fib_node_index_t *lrtf_entries;
1288   u32 *lrtf_sw_if_index_to_bool;
1289   fib_source_t lrtf_source;
1290 } lcp_router_table_flush_ctx_t;
1291
1292 static fib_table_walk_rc_t
1293 lcp_router_table_flush_cb (fib_node_index_t fib_entry_index, void *arg)
1294 {
1295   lcp_router_table_flush_ctx_t *ctx = arg;
1296   u32 sw_if_index;
1297
1298   sw_if_index = fib_entry_get_resolving_interface_for_source (
1299     fib_entry_index, ctx->lrtf_source);
1300
1301   if (sw_if_index < vec_len (ctx->lrtf_sw_if_index_to_bool) &&
1302       ctx->lrtf_sw_if_index_to_bool[sw_if_index])
1303     {
1304       vec_add1 (ctx->lrtf_entries, fib_entry_index);
1305     }
1306   return (FIB_TABLE_WALK_CONTINUE);
1307 }
1308
1309 static void
1310 lcp_router_table_flush (lcp_router_table_t *nlt, u32 *sw_if_index_to_bool,
1311                         fib_source_t source)
1312 {
1313   fib_node_index_t *fib_entry_index;
1314   lcp_router_table_flush_ctx_t ctx = {
1315     .lrtf_entries = NULL,
1316     .lrtf_sw_if_index_to_bool = sw_if_index_to_bool,
1317     .lrtf_source = source,
1318   };
1319
1320   LCP_ROUTER_DBG (
1321     "Flush table: proto %U, fib-index %u, max sw_if_index %u, source %U",
1322     format_fib_protocol, nlt->nlt_proto, nlt->nlt_fib_index,
1323     vec_len (sw_if_index_to_bool) - 1, format_fib_source, source);
1324
1325   fib_table_walk (nlt->nlt_fib_index, nlt->nlt_proto,
1326                   lcp_router_table_flush_cb, &ctx);
1327
1328   LCP_ROUTER_DBG ("Flush table: entries number to delete %u",
1329                   vec_len (ctx.lrtf_entries));
1330
1331   vec_foreach (fib_entry_index, ctx.lrtf_entries)
1332     {
1333       fib_table_entry_delete_index (*fib_entry_index, source);
1334       lcp_router_table_unlock (nlt);
1335     }
1336
1337   vec_free (ctx.lrtf_entries);
1338 }
1339
1340 const nl_vft_t lcp_router_vft = {
1341   .nvl_rt_link_add = { .is_mp_safe = 0, .cb = lcp_router_link_add },
1342   .nvl_rt_link_del = { .is_mp_safe = 0, .cb = lcp_router_link_del },
1343   .nvl_rt_link_sync_begin = { .is_mp_safe = 0,
1344                               .cb = lcp_router_link_sync_begin },
1345   .nvl_rt_link_sync_end = { .is_mp_safe = 0, .cb = lcp_router_link_sync_end },
1346   .nvl_rt_addr_add = { .is_mp_safe = 0, .cb = lcp_router_link_addr_add },
1347   .nvl_rt_addr_del = { .is_mp_safe = 0, .cb = lcp_router_link_addr_del },
1348   .nvl_rt_addr_sync_begin = { .is_mp_safe = 0,
1349                               .cb = lcp_router_link_addr_sync_begin },
1350   .nvl_rt_addr_sync_end = { .is_mp_safe = 0,
1351                             .cb = lcp_router_link_addr_sync_end },
1352   .nvl_rt_neigh_add = { .is_mp_safe = 0, .cb = lcp_router_neigh_add },
1353   .nvl_rt_neigh_del = { .is_mp_safe = 0, .cb = lcp_router_neigh_del },
1354   .nvl_rt_neigh_sync_begin = { .is_mp_safe = 0,
1355                                .cb = lcp_router_neigh_sync_begin },
1356   .nvl_rt_neigh_sync_end = { .is_mp_safe = 0,
1357                              .cb = lcp_router_neigh_sync_end },
1358   .nvl_rt_route_add = { .is_mp_safe = 1, .cb = lcp_router_route_add },
1359   .nvl_rt_route_del = { .is_mp_safe = 1, .cb = lcp_router_route_del },
1360   .nvl_rt_route_sync_begin = { .is_mp_safe = 0,
1361                                .cb = lcp_router_route_sync_begin },
1362   .nvl_rt_route_sync_end = { .is_mp_safe = 0,
1363                              .cb = lcp_router_route_sync_end },
1364 };
1365
1366 static clib_error_t *
1367 lcp_router_init (vlib_main_t *vm)
1368 {
1369   lcp_router_logger = vlib_log_register_class ("linux-cp", "router");
1370
1371   nl_register_vft (&lcp_router_vft);
1372
1373   /*
1374    * allocate 2 route sources. The low priority source will be for
1375    * dynamic routes. If a dynamic route daemon (FRR) tries to remove its
1376    * route, it will use the low priority source to ensure it will not
1377    * remove static routes which were added with the higher priority source.
1378    */
1379   lcp_rt_fib_src =
1380     fib_source_allocate ("lcp-rt", FIB_SOURCE_PRIORITY_HI, FIB_SOURCE_BH_API);
1381
1382   lcp_rt_fib_src_dynamic = fib_source_allocate (
1383     "lcp-rt-dynamic", FIB_SOURCE_PRIORITY_HI + 1, FIB_SOURCE_BH_API);
1384
1385   return (NULL);
1386 }
1387
1388 VLIB_INIT_FUNCTION (lcp_router_init) = {
1389   .runs_before = VLIB_INITS ("lcp_nl_init"),
1390 };
1391
1392 /*
1393  * fd.io coding-style-patch-verification: ON
1394  *
1395  * Local Variables:
1396  * eval: (c-set-style "gnu")
1397  * End:
1398  */