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