linux-cp: Linux Control Plane Netlink Listener
[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->ts > lip->lip_create_ts)
137     return 0;
138
139   LCP_ROUTER_INFO ("Early message received for %U",
140                    format_vnet_sw_if_index_name, vnet_get_main (),
141                    lip->lip_phy_sw_if_index);
142   return -1;
143 }
144
145 static void
146 lcp_router_link_del (struct rtnl_link *rl, void *ctx)
147 {
148   index_t lipi;
149
150   if (!lcp_auto_subint ())
151     return;
152
153   lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
154
155   if (INDEX_INVALID != lipi)
156     {
157       lcp_itf_pair_t *lip;
158
159       lip = lcp_itf_pair_get (lipi);
160
161       if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
162         return;
163
164       LCP_ROUTER_INFO ("delete link: %s - %U", rtnl_link_get_type (rl),
165                        format_vnet_sw_if_index_name, vnet_get_main (),
166                        lip->lip_phy_sw_if_index);
167       lcp_itf_pair_delete (lip->lip_phy_sw_if_index);
168
169       if (rtnl_link_is_vlan (rl))
170         {
171           LCP_ROUTER_INFO ("delete vlan: %s -> %U", rtnl_link_get_name (rl),
172                            format_vnet_sw_if_index_name, vnet_get_main (),
173                            lip->lip_phy_sw_if_index);
174           vnet_delete_sub_interface (lip->lip_phy_sw_if_index);
175           vnet_delete_sub_interface (lip->lip_host_sw_if_index);
176         }
177     }
178   else
179     LCP_ROUTER_INFO ("ignore link del: %s - %s", rtnl_link_get_type (rl),
180                      rtnl_link_get_name (rl));
181 }
182
183 static void
184 lcp_router_ip4_mroutes_add_del (u32 sw_if_index, u8 is_add)
185 {
186   const fib_route_path_t path = {
187     .frp_proto = DPO_PROTO_IP4,
188     .frp_addr = zero_addr,
189     .frp_sw_if_index = sw_if_index,
190     .frp_fib_index = ~0,
191     .frp_weight = 1,
192     .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
193   };
194   u32 mfib_index;
195   int ii;
196
197   mfib_index =
198     mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
199
200   for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
201     {
202       if (is_add)
203         {
204           mfib_table_entry_path_update (mfib_index, &ip4_specials[ii],
205                                         MFIB_SOURCE_PLUGIN_LOW,
206                                         MFIB_ENTRY_FLAG_NONE, &path);
207         }
208       else
209         {
210           mfib_table_entry_path_remove (mfib_index, &ip4_specials[ii],
211                                         MFIB_SOURCE_PLUGIN_LOW, &path);
212         }
213     }
214 }
215
216 static void
217 lcp_router_ip6_mroutes_add_del (u32 sw_if_index, u8 is_add)
218 {
219   const fib_route_path_t path = {
220     .frp_proto = DPO_PROTO_IP6,
221     .frp_addr = zero_addr,
222     .frp_sw_if_index = sw_if_index,
223     .frp_fib_index = ~0,
224     .frp_weight = 1,
225     .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
226   };
227   u32 mfib_index;
228   int ii;
229
230   mfib_index =
231     mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
232
233   for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
234     {
235       if (is_add)
236         {
237           mfib_table_entry_path_update (mfib_index, &ip6_specials[ii],
238                                         MFIB_SOURCE_PLUGIN_LOW,
239                                         MFIB_ENTRY_FLAG_NONE, &path);
240         }
241       else
242         {
243           mfib_table_entry_path_remove (mfib_index, &ip6_specials[ii],
244                                         MFIB_SOURCE_PLUGIN_LOW, &path);
245         }
246     }
247 }
248
249 static void
250 lcp_router_link_mtu (struct rtnl_link *rl, u32 sw_if_index)
251 {
252   vnet_main_t *vnm = vnet_get_main ();
253   u32 mtu;
254   vnet_sw_interface_t *sw;
255   vnet_hw_interface_t *hw;
256
257   mtu = rtnl_link_get_mtu (rl);
258   if (!mtu)
259     return;
260
261   sw = vnet_get_sw_interface (vnm, sw_if_index);
262   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
263
264   /* If HW interface, try to change hw link */
265   if ((sw->type == sw->sup_sw_if_index) &&
266       (hw->hw_class_index == ethernet_hw_interface_class.index))
267     vnet_hw_interface_set_mtu (vnm, hw->hw_if_index, mtu);
268   else
269     vnet_sw_interface_set_mtu (vnm, sw->sw_if_index, mtu);
270 }
271
272 static void
273 lcp_router_link_addr (struct rtnl_link *rl, lcp_itf_pair_t *lip)
274 {
275   vnet_main_t *vnm = vnet_get_main ();
276   struct nl_addr *mac_addr;
277   vnet_sw_interface_t *sw;
278   vnet_hw_interface_t *hw;
279   void *mac_addr_bytes;
280
281   mac_addr = rtnl_link_get_addr (rl);
282   if (!mac_addr || (nl_addr_get_family (mac_addr) != AF_LLC))
283     return;
284
285   sw = vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index);
286
287   /* can only change address on hw interface */
288   if (sw->sw_if_index != sw->sup_sw_if_index)
289     return;
290
291   hw = vnet_get_sup_hw_interface (vnm, lip->lip_phy_sw_if_index);
292   if (!vec_len (hw->hw_address))
293     return;
294
295   mac_addr_bytes = nl_addr_get_binary_addr (mac_addr);
296   if (clib_memcmp (mac_addr_bytes, hw->hw_address, nl_addr_get_len (mac_addr)))
297     vnet_hw_interface_change_mac_address (vnm, hw->hw_if_index,
298                                           mac_addr_bytes);
299
300   /* mcast adjacencies need to be updated */
301   vnet_update_adjacency_for_sw_interface (vnm, lip->lip_phy_sw_if_index,
302                                           lip->lip_phy_adjs.adj_index[AF_IP4]);
303   vnet_update_adjacency_for_sw_interface (vnm, lip->lip_phy_sw_if_index,
304                                           lip->lip_phy_adjs.adj_index[AF_IP6]);
305 }
306
307 static void
308 lcp_router_link_add (struct rtnl_link *rl, void *ctx)
309 {
310   index_t lipi;
311   int up;
312   vnet_main_t *vnm = vnet_get_main ();
313
314   lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
315   up = IFF_UP & rtnl_link_get_flags (rl);
316
317   if (INDEX_INVALID != lipi)
318     {
319       lcp_itf_pair_t *lip;
320
321       lip = lcp_itf_pair_get (lipi);
322       if (!vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index))
323         return;
324
325       if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
326         return;
327
328       if (up)
329         {
330           vnet_sw_interface_admin_up (vnet_get_main (),
331                                       lip->lip_phy_sw_if_index);
332         }
333       else
334         {
335           vnet_sw_interface_admin_down (vnet_get_main (),
336                                         lip->lip_phy_sw_if_index);
337         }
338       LCP_ROUTER_DBG ("link: %s (%d) -> %U/%U %s", rtnl_link_get_name (rl),
339                       rtnl_link_get_ifindex (rl), format_vnet_sw_if_index_name,
340                       vnm, lip->lip_phy_sw_if_index,
341                       format_vnet_sw_if_index_name, vnm,
342                       lip->lip_host_sw_if_index, (up ? "up" : "down"));
343
344       lcp_router_link_mtu (rl, lip->lip_phy_sw_if_index);
345       lcp_router_link_addr (rl, lip);
346     }
347   else if (lcp_auto_subint () && rtnl_link_is_vlan (rl))
348     {
349       /* Find the pair based on the parent VIF */
350       lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_link (rl));
351
352       if (INDEX_INVALID != lipi)
353         {
354           u32 sub_phy_sw_if_index, sub_host_sw_if_index;
355           const lcp_itf_pair_t *lip;
356           int vlan;
357           u8 *ns = 0; /* FIXME */
358
359           lip = lcp_itf_pair_get (lipi);
360
361           vlan = rtnl_link_vlan_get_id (rl);
362
363           /* create the vlan interface on the parent phy */
364           if (vnet_create_sub_interface (lip->lip_phy_sw_if_index, vlan, 18, 0,
365                                          vlan, &sub_phy_sw_if_index))
366             {
367               LCP_ROUTER_INFO ("failed create phy vlan: %s on %U",
368                                rtnl_link_get_name (rl),
369                                format_vnet_sw_if_index_name, vnet_get_main (),
370                                lip->lip_phy_sw_if_index);
371               return;
372             }
373           /* create the vlan interface on the parent host */
374           if (vnet_create_sub_interface (lip->lip_host_sw_if_index, vlan, 18,
375                                          0, vlan, &sub_host_sw_if_index))
376             {
377               LCP_ROUTER_INFO ("failed create vlan: %s on %U",
378                                rtnl_link_get_name (rl),
379                                format_vnet_sw_if_index_name, vnet_get_main (),
380                                lip->lip_host_sw_if_index);
381               return;
382             }
383
384           char *if_name;
385           u8 *if_namev = 0;
386
387           LCP_ROUTER_INFO (
388             "create vlan: %s -> (%U, %U) : (%U, %U)", rtnl_link_get_name (rl),
389             format_vnet_sw_if_index_name, vnet_get_main (),
390             lip->lip_phy_sw_if_index, format_vnet_sw_if_index_name,
391             vnet_get_main (), sub_phy_sw_if_index,
392             format_vnet_sw_if_index_name, vnet_get_main (),
393             lip->lip_host_sw_if_index, format_vnet_sw_if_index_name,
394             vnet_get_main (), sub_host_sw_if_index);
395
396           if ((if_name = rtnl_link_get_name (rl)) != NULL)
397             vec_validate_init_c_string (if_namev, if_name,
398                                         strnlen (if_name, IFNAMSIZ));
399           lcp_itf_pair_add (sub_host_sw_if_index, sub_phy_sw_if_index,
400                             if_namev, rtnl_link_get_ifindex (rl),
401                             lip->lip_host_type, ns);
402           if (up)
403             vnet_sw_interface_admin_up (vnet_get_main (), sub_phy_sw_if_index);
404           vnet_sw_interface_admin_up (vnet_get_main (), sub_host_sw_if_index);
405
406           vec_free (if_namev);
407         }
408       else
409         {
410           LCP_ROUTER_INFO ("ignore parent-link add: %s - %s",
411                            rtnl_link_get_type (rl), rtnl_link_get_name (rl));
412         }
413     }
414   else
415     LCP_ROUTER_INFO ("ignore link add: %s - %s", rtnl_link_get_type (rl),
416                      rtnl_link_get_name (rl));
417 }
418
419 static fib_protocol_t
420 lcp_router_proto_k2f (uint32_t k)
421 {
422   if (AF_INET6 == k)
423     return (FIB_PROTOCOL_IP6);
424   return (FIB_PROTOCOL_IP4);
425 }
426
427 static void
428 lcp_router_mk_addr (const struct nl_addr *rna, ip_address_t *ia)
429 {
430   fib_protocol_t fproto;
431
432   ip_address_reset (ia);
433   fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
434
435   ip_address_set (ia, nl_addr_get_binary_addr (rna),
436                   FIB_PROTOCOL_IP4 == fproto ? AF_IP4 : AF_IP6);
437 }
438
439 static fib_protocol_t
440 lcp_router_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
441 {
442   fib_protocol_t fproto;
443
444   fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
445   ip46_address_reset (ia);
446   if (FIB_PROTOCOL_IP4 == fproto)
447     memcpy (&ia->ip4, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
448   else
449     memcpy (&ia->ip6, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
450
451   return (fproto);
452 }
453
454 static void
455 lcp_router_link_addr_add_del (struct rtnl_addr *rla, int is_del)
456 {
457   u32 sw_if_index;
458
459   sw_if_index = lcp_router_intf_h2p (rtnl_addr_get_ifindex (rla));
460
461   if (~0 != sw_if_index)
462     {
463       ip_address_t nh;
464
465       lcp_router_mk_addr (rtnl_addr_get_local (rla), &nh);
466
467       if (AF_IP4 == ip_addr_version (&nh))
468         {
469           ip4_add_del_interface_address (
470             vlib_get_main (), sw_if_index, &ip_addr_v4 (&nh),
471             rtnl_addr_get_prefixlen (rla), is_del);
472           lcp_router_ip4_mroutes_add_del (sw_if_index, !is_del);
473         }
474       else if (AF_IP6 == ip_addr_version (&nh))
475         {
476           if (ip6_address_is_link_local_unicast (&ip_addr_v6 (&nh)))
477             if (is_del)
478               ip6_link_disable (sw_if_index);
479             else
480               {
481                 ip6_link_enable (sw_if_index, NULL);
482                 ip6_link_set_local_address (sw_if_index, &ip_addr_v6 (&nh));
483               }
484           else
485             ip6_add_del_interface_address (
486               vlib_get_main (), sw_if_index, &ip_addr_v6 (&nh),
487               rtnl_addr_get_prefixlen (rla), is_del);
488           lcp_router_ip6_mroutes_add_del (sw_if_index, !is_del);
489         }
490
491       LCP_ROUTER_DBG ("link-addr: %U %U/%d", format_vnet_sw_if_index_name,
492                       vnet_get_main (), sw_if_index, format_ip_address, &nh,
493                       rtnl_addr_get_prefixlen (rla));
494     }
495 }
496
497 static void
498 lcp_router_link_addr_del (struct rtnl_addr *la)
499 {
500   lcp_router_link_addr_add_del (la, 1);
501 }
502
503 static void
504 lcp_router_link_addr_add (struct rtnl_addr *la)
505 {
506   lcp_router_link_addr_add_del (la, 0);
507 }
508
509 static void
510 lcp_router_mk_mac_addr (const struct nl_addr *rna, mac_address_t *mac)
511 {
512   mac_address_from_bytes (mac, nl_addr_get_binary_addr (rna));
513 }
514
515 static void
516 lcp_router_neigh_del (struct rtnl_neigh *rn)
517 {
518   u32 sw_if_index;
519
520   sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
521
522   if (~0 != sw_if_index)
523     {
524       ip_address_t nh;
525       int rv;
526
527       lcp_router_mk_addr (rtnl_neigh_get_dst (rn), &nh);
528
529       rv = ip_neighbor_del (&nh, sw_if_index);
530
531       if (rv)
532         {
533           LCP_ROUTER_ERROR (
534             "Failed to delete neighbor: %U %U", format_ip_address, &nh,
535             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
536         }
537       else
538         {
539           LCP_ROUTER_DBG ("neighbor del: %U %U", format_ip_address, &nh,
540                           format_vnet_sw_if_index_name, vnet_get_main (),
541                           sw_if_index);
542         }
543     }
544   else
545     LCP_ROUTER_INFO ("ignore neighbour del on: %d",
546                      rtnl_neigh_get_ifindex (rn));
547 }
548
549 #ifndef NUD_VALID
550 #define NUD_VALID                                                             \
551   (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE |        \
552    NUD_DELAY)
553 #endif
554
555 static void
556 lcp_router_neigh_add (struct rtnl_neigh *rn)
557 {
558   u32 sw_if_index;
559
560   sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
561
562   if (~0 != sw_if_index)
563     {
564       struct nl_addr *ll;
565       ip_address_t nh;
566       int state;
567
568       lcp_router_mk_addr (rtnl_neigh_get_dst (rn), &nh);
569       ll = rtnl_neigh_get_lladdr (rn);
570       state = rtnl_neigh_get_state (rn);
571
572       if (ll && (state & NUD_VALID))
573         {
574           mac_address_t mac;
575           ip_neighbor_flags_t flags;
576           int rv;
577
578           lcp_router_mk_mac_addr (ll, &mac);
579
580           if (state & (NUD_NOARP | NUD_PERMANENT))
581             flags = IP_NEIGHBOR_FLAG_STATIC;
582           else
583             flags = IP_NEIGHBOR_FLAG_DYNAMIC;
584
585           rv = ip_neighbor_add (&nh, &mac, sw_if_index, flags, NULL);
586
587           if (rv)
588             {
589               LCP_ROUTER_ERROR (
590                 "Failed to create neighbor: %U %U", format_ip_address, &nh,
591                 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
592             }
593           else
594             {
595               LCP_ROUTER_DBG ("neighbor add: %U %U", format_ip_address, &nh,
596                               format_vnet_sw_if_index_name, vnet_get_main (),
597                               sw_if_index);
598             }
599         }
600       else
601         /* It's a delete */
602         lcp_router_neigh_del (rn);
603     }
604   else
605     LCP_ROUTER_INFO ("ignore neighbour add on: %d",
606                      rtnl_neigh_get_ifindex (rn));
607 }
608
609 static lcp_router_table_t *
610 lcp_router_table_find (uint32_t id, fib_protocol_t fproto)
611 {
612   uword *p;
613
614   p = hash_get (lcp_router_table_db[fproto], id);
615
616   if (p)
617     return pool_elt_at_index (lcp_router_table_pool, p[0]);
618
619   return (NULL);
620 }
621
622 static uint32_t
623 lcp_router_table_k2f (uint32_t k)
624 {
625   // the kernel's table ID 255 is the default table
626   if (k == 255 || k == 254)
627     return 0;
628   return k;
629 }
630
631 static lcp_router_table_t *
632 lcp_router_table_add_or_lock (uint32_t id, fib_protocol_t fproto)
633 {
634   lcp_router_table_t *nlt;
635
636   id = lcp_router_table_k2f (id);
637   nlt = lcp_router_table_find (id, fproto);
638
639   if (NULL == nlt)
640     {
641       pool_get_zero (lcp_router_table_pool, nlt);
642
643       nlt->nlt_id = id;
644       nlt->nlt_proto = fproto;
645
646       nlt->nlt_fib_index = fib_table_find_or_create_and_lock (
647         nlt->nlt_proto, nlt->nlt_id, lcp_rt_fib_src);
648       nlt->nlt_mfib_index = mfib_table_find_or_create_and_lock (
649         nlt->nlt_proto, nlt->nlt_id, MFIB_SOURCE_PLUGIN_LOW);
650
651       hash_set (lcp_router_table_db[fproto], nlt->nlt_id,
652                 nlt - lcp_router_table_pool);
653
654       if (FIB_PROTOCOL_IP4 == fproto)
655         {
656           /* Set the all 1s address in this table to punt */
657           fib_table_entry_special_add (nlt->nlt_fib_index, &pfx_all1s,
658                                        lcp_rt_fib_src, FIB_ENTRY_FLAG_LOCAL);
659
660           const fib_route_path_t path = {
661             .frp_proto = DPO_PROTO_IP4,
662             .frp_addr = zero_addr,
663             .frp_sw_if_index = ~0,
664             .frp_fib_index = ~0,
665             .frp_weight = 1,
666             .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
667             .frp_flags = FIB_ROUTE_PATH_LOCAL,
668           };
669           int ii;
670
671           for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
672             {
673               mfib_table_entry_path_update (
674                 nlt->nlt_mfib_index, &ip4_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
675                 MFIB_ENTRY_FLAG_NONE, &path);
676             }
677         }
678       else if (FIB_PROTOCOL_IP6 == fproto)
679         {
680           const fib_route_path_t path = {
681             .frp_proto = DPO_PROTO_IP6,
682             .frp_addr = zero_addr,
683             .frp_sw_if_index = ~0,
684             .frp_fib_index = ~0,
685             .frp_weight = 1,
686             .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
687             .frp_flags = FIB_ROUTE_PATH_LOCAL,
688           };
689           int ii;
690
691           for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
692             {
693               mfib_table_entry_path_update (
694                 nlt->nlt_mfib_index, &ip6_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
695                 MFIB_ENTRY_FLAG_NONE, &path);
696             }
697         }
698     }
699
700   nlt->nlt_refs++;
701
702   return (nlt);
703 }
704
705 static void
706 lcp_router_table_unlock (lcp_router_table_t *nlt)
707 {
708   nlt->nlt_refs--;
709
710   if (0 == nlt->nlt_refs)
711     {
712       if (FIB_PROTOCOL_IP4 == nlt->nlt_proto)
713         {
714           /* Set the all 1s address in this table to punt */
715           fib_table_entry_special_remove (nlt->nlt_fib_index, &pfx_all1s,
716                                           lcp_rt_fib_src);
717         }
718
719       fib_table_unlock (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
720
721       hash_unset (lcp_router_table_db[nlt->nlt_proto], nlt->nlt_id);
722       pool_put (lcp_router_table_pool, nlt);
723     }
724 }
725
726 static void
727 lcp_router_route_mk_prefix (struct rtnl_route *r, fib_prefix_t *p)
728 {
729   const struct nl_addr *addr = rtnl_route_get_dst (r);
730
731   p->fp_len = nl_addr_get_prefixlen (addr);
732   p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_addr);
733 }
734
735 static void
736 lcp_router_route_mk_mprefix (struct rtnl_route *r, mfib_prefix_t *p)
737 {
738   const struct nl_addr *addr;
739
740   addr = rtnl_route_get_dst (r);
741
742   p->fp_len = nl_addr_get_prefixlen (addr);
743   p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_grp_addr);
744
745   addr = rtnl_route_get_src (r);
746   if (addr)
747     p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_src_addr);
748 }
749
750 typedef struct lcp_router_route_path_parse_t_
751 {
752   fib_route_path_t *paths;
753   fib_protocol_t route_proto;
754   bool is_mcast;
755   fib_route_path_flags_t type_flags;
756   u8 preference;
757 } lcp_router_route_path_parse_t;
758
759 static void
760 lcp_router_route_path_parse (struct rtnl_nexthop *rnh, void *arg)
761 {
762   lcp_router_route_path_parse_t *ctx = arg;
763   fib_route_path_t *path;
764   u32 sw_if_index;
765
766   sw_if_index = lcp_router_intf_h2p (rtnl_route_nh_get_ifindex (rnh));
767
768   if (~0 != sw_if_index)
769     {
770       fib_protocol_t fproto;
771       struct nl_addr *addr;
772
773       vec_add2 (ctx->paths, path, 1);
774
775       path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
776       path->frp_sw_if_index = sw_if_index;
777       path->frp_weight = rtnl_route_nh_get_weight (rnh);
778       path->frp_preference = ctx->preference;
779
780       addr = rtnl_route_nh_get_gateway (rnh);
781
782       if (addr)
783         fproto = lcp_router_mk_addr46 (rtnl_route_nh_get_gateway (rnh),
784                                        &path->frp_addr);
785       else
786         fproto = ctx->route_proto;
787
788       path->frp_proto = fib_proto_to_dpo (fproto);
789
790       if (ctx->is_mcast)
791         path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
792
793       LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
794     }
795 }
796
797 /*
798  * blackhole, unreachable, prohibit will not have a next hop in an
799  * RTM_NEWROUTE. Add a path for them.
800  */
801 static void
802 lcp_router_route_path_add_special (struct rtnl_route *rr,
803                                    lcp_router_route_path_parse_t *ctx)
804 {
805   fib_route_path_t *path;
806
807   if (rtnl_route_get_type (rr) < RTN_BLACKHOLE)
808     return;
809
810   /* if it already has a path, it does not need us to add one */
811   if (vec_len (ctx->paths) > 0)
812     return;
813
814   vec_add2 (ctx->paths, path, 1);
815
816   path->frp_flags = FIB_ROUTE_PATH_FLAG_NONE | ctx->type_flags;
817   path->frp_sw_if_index = ~0;
818   path->frp_proto = fib_proto_to_dpo (ctx->route_proto);
819   path->frp_preference = ctx->preference;
820
821   LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
822 }
823
824 /*
825  * Map of supported route types. Some types are omitted:
826  * RTN_LOCAL - interface address addition creates these automatically
827  * RTN_BROADCAST - same as RTN_LOCAL
828  * RTN_UNSPEC, RTN_ANYCAST, RTN_THROW, RTN_NAT, RTN_XRESOLVE -
829  *   There's not a VPP equivalent for these currently.
830  */
831 static const u8 lcp_router_route_type_valid[__RTN_MAX] = {
832   [RTN_UNICAST] = 1,     [RTN_MULTICAST] = 1, [RTN_BLACKHOLE] = 1,
833   [RTN_UNREACHABLE] = 1, [RTN_PROHIBIT] = 1,
834 };
835
836 /* Map of fib entry flags by route type */
837 static const fib_entry_flag_t lcp_router_route_type_feflags[__RTN_MAX] = {
838   [RTN_LOCAL] = FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED,
839   [RTN_BROADCAST] = FIB_ENTRY_FLAG_DROP | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT,
840   [RTN_BLACKHOLE] = FIB_ENTRY_FLAG_DROP,
841 };
842
843 /* Map of fib route path flags by route type */
844 static const fib_route_path_flags_t
845   lcp_router_route_type_frpflags[__RTN_MAX] = {
846     [RTN_UNREACHABLE] = FIB_ROUTE_PATH_ICMP_UNREACH,
847     [RTN_PROHIBIT] = FIB_ROUTE_PATH_ICMP_PROHIBIT,
848     [RTN_BLACKHOLE] = FIB_ROUTE_PATH_DROP,
849   };
850
851 static inline fib_source_t
852 lcp_router_proto_fib_source (u8 rt_proto)
853 {
854   return (rt_proto <= RTPROT_STATIC) ? lcp_rt_fib_src : lcp_rt_fib_src_dynamic;
855 }
856
857 static fib_entry_flag_t
858 lcp_router_route_mk_entry_flags (uint8_t rtype, int table_id, uint8_t rproto)
859 {
860   fib_entry_flag_t fef = FIB_ENTRY_FLAG_NONE;
861
862   fef |= lcp_router_route_type_feflags[rtype];
863   if ((rproto == RTPROT_KERNEL) || PREDICT_FALSE (255 == table_id))
864     /* kernel proto is interface prefixes, 255 is linux's 'local' table */
865     fef |= FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED;
866
867   return (fef);
868 }
869
870 static void
871 lcp_router_route_del (struct rtnl_route *rr)
872 {
873   fib_entry_flag_t entry_flags;
874   uint32_t table_id;
875   fib_prefix_t pfx;
876   lcp_router_table_t *nlt;
877   uint8_t rtype, rproto;
878
879   rtype = rtnl_route_get_type (rr);
880   table_id = rtnl_route_get_table (rr);
881   rproto = rtnl_route_get_protocol (rr);
882
883   /* skip unsupported route types and local table */
884   if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
885     return;
886
887   lcp_router_route_mk_prefix (rr, &pfx);
888   entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
889   nlt = lcp_router_table_find (lcp_router_table_k2f (table_id), pfx.fp_proto);
890
891   LCP_ROUTER_DBG ("route del: %d:%U %U", rtnl_route_get_table (rr),
892                   format_fib_prefix, &pfx, format_fib_entry_flags,
893                   entry_flags);
894
895   if (NULL == nlt)
896     return;
897
898   lcp_router_route_path_parse_t np = {
899     .route_proto = pfx.fp_proto,
900     .type_flags = lcp_router_route_type_frpflags[rtype],
901   };
902
903   rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
904   lcp_router_route_path_add_special (rr, &np);
905
906   if (0 != vec_len (np.paths))
907     {
908       fib_source_t fib_src;
909
910       fib_src = lcp_router_proto_fib_source (rproto);
911
912       if (pfx.fp_proto == FIB_PROTOCOL_IP6)
913         fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
914       else
915         fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
916                                       np.paths);
917     }
918
919   vec_free (np.paths);
920
921   lcp_router_table_unlock (nlt);
922 }
923
924 static void
925 lcp_router_route_add (struct rtnl_route *rr)
926 {
927   fib_entry_flag_t entry_flags;
928   uint32_t table_id;
929   fib_prefix_t pfx;
930   lcp_router_table_t *nlt;
931   uint8_t rtype, rproto;
932
933   rtype = rtnl_route_get_type (rr);
934   table_id = rtnl_route_get_table (rr);
935   rproto = rtnl_route_get_protocol (rr);
936
937   /* skip unsupported route types and local table */
938   if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
939     return;
940
941   lcp_router_route_mk_prefix (rr, &pfx);
942   entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
943
944   /* link local IPv6 */
945   if (FIB_PROTOCOL_IP6 == pfx.fp_proto &&
946       (ip6_address_is_multicast (&pfx.fp_addr.ip6) ||
947        ip6_address_is_link_local_unicast (&pfx.fp_addr.ip6)))
948     {
949       LCP_ROUTER_DBG ("route skip: %d:%U %U", rtnl_route_get_table (rr),
950                       format_fib_prefix, &pfx, format_fib_entry_flags,
951                       entry_flags);
952     }
953   else
954     {
955       LCP_ROUTER_DBG ("route add: %d:%U %U", rtnl_route_get_table (rr),
956                       format_fib_prefix, &pfx, format_fib_entry_flags,
957                       entry_flags);
958
959       lcp_router_route_path_parse_t np = {
960         .route_proto = pfx.fp_proto,
961         .is_mcast = (rtype == RTN_MULTICAST),
962         .type_flags = lcp_router_route_type_frpflags[rtype],
963         .preference = (u8) rtnl_route_get_priority (rr),
964       };
965
966       rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
967       lcp_router_route_path_add_special (rr, &np);
968
969       if (0 != vec_len (np.paths))
970         {
971           nlt = lcp_router_table_add_or_lock (table_id, pfx.fp_proto);
972           if (rtype == RTN_MULTICAST)
973             {
974               /* it's not clear to me how linux expresses the RPF paramters
975                * so we'll allow from all interfaces and hope for the best */
976               mfib_prefix_t mpfx = {};
977
978               lcp_router_route_mk_mprefix (rr, &mpfx);
979
980               mfib_table_entry_update (
981                 nlt->nlt_mfib_index, &mpfx, MFIB_SOURCE_PLUGIN_LOW,
982                 MFIB_RPF_ID_NONE, MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF);
983
984               mfib_table_entry_paths_update (nlt->nlt_mfib_index, &mpfx,
985                                              MFIB_SOURCE_PLUGIN_LOW,
986                                              MFIB_ENTRY_FLAG_NONE, np.paths);
987             }
988           else
989             {
990               fib_source_t fib_src;
991
992               fib_src = lcp_router_proto_fib_source (rproto);
993
994               if (pfx.fp_proto == FIB_PROTOCOL_IP6)
995                 fib_table_entry_path_add2 (nlt->nlt_fib_index, &pfx, fib_src,
996                                            entry_flags, np.paths);
997               else
998                 fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
999                                         entry_flags, np.paths);
1000             }
1001         }
1002       else
1003         LCP_ROUTER_DBG ("no paths for route add: %d:%U %U",
1004                         rtnl_route_get_table (rr), format_fib_prefix, &pfx,
1005                         format_fib_entry_flags, entry_flags);
1006       vec_free (np.paths);
1007     }
1008 }
1009
1010 const nl_vft_t lcp_router_vft = {
1011   .nvl_rt_link_add = { .is_mp_safe = 0, .cb = lcp_router_link_add },
1012   .nvl_rt_link_del = { .is_mp_safe = 0, .cb = lcp_router_link_del },
1013   .nvl_rt_addr_add = { .is_mp_safe = 0, .cb = lcp_router_link_addr_add },
1014   .nvl_rt_addr_del = { .is_mp_safe = 0, .cb = lcp_router_link_addr_del },
1015   .nvl_rt_neigh_add = { .is_mp_safe = 0, .cb = lcp_router_neigh_add },
1016   .nvl_rt_neigh_del = { .is_mp_safe = 0, .cb = lcp_router_neigh_del },
1017   .nvl_rt_route_add = { .is_mp_safe = 1, .cb = lcp_router_route_add },
1018   .nvl_rt_route_del = { .is_mp_safe = 1, .cb = lcp_router_route_del },
1019 };
1020
1021 static clib_error_t *
1022 lcp_router_init (vlib_main_t *vm)
1023 {
1024   lcp_router_logger = vlib_log_register_class ("linux-cp", "router");
1025
1026   nl_register_vft (&lcp_router_vft);
1027
1028   /*
1029    * allocate 2 route sources. The low priority source will be for
1030    * dynamic routes. If a dynamic route daemon (FRR) tries to remove its
1031    * route, it will use the low priority source to ensure it will not
1032    * remove static routes which were added with the higher priority source.
1033    */
1034   lcp_rt_fib_src =
1035     fib_source_allocate ("lcp-rt", FIB_SOURCE_PRIORITY_HI, FIB_SOURCE_BH_API);
1036
1037   lcp_rt_fib_src_dynamic = fib_source_allocate (
1038     "lcp-rt-dynamic", FIB_SOURCE_PRIORITY_HI + 1, FIB_SOURCE_BH_API);
1039
1040   return (NULL);
1041 }
1042
1043 VLIB_INIT_FUNCTION (lcp_router_init) = {
1044   .runs_before = VLIB_INITS ("lcp_nl_init"),
1045 };
1046
1047 /*
1048  * fd.io coding-style-patch-verification: ON
1049  *
1050  * Local Variables:
1051  * eval: (c-set-style "gnu")
1052  * End:
1053  */