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