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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <sys/socket.h>
18 #include <linux/mpls.h>
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>
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>
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>
41 typedef struct lcp_router_table_t_
44 fib_protocol_t nlt_proto;
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;
54 const static fib_prefix_t pfx_all1s = {
60 .fp_proto = FIB_PROTOCOL_IP4,
64 static fib_source_t lcp_rt_fib_src;
65 static fib_source_t lcp_rt_fib_src_dynamic;
67 #define LCP_ROUTER_DBG(...) vlib_log_debug (lcp_router_logger, __VA_ARGS__);
69 #define LCP_ROUTER_INFO(...) vlib_log_notice (lcp_router_logger, __VA_ARGS__);
71 #define LCP_ROUTER_ERROR(...) vlib_log_err (lcp_router_logger, __VA_ARGS__);
73 static const mfib_prefix_t ip4_specials[] = {
74 /* ALL prefixes are in network order */
76 /* (*,224.0.0.0)/24 - all local subnet */
78 .ip4.data_u32 = 0x000000e0,
81 .fp_proto = FIB_PROTOCOL_IP4,
85 static const mfib_prefix_t ip6_specials[] = {
86 /* ALL prefixes are in network order */
88 /* (*,ff00::)/8 - all local subnet */
90 .ip6.as_u64[0] = 0x00000000000000ff,
93 .fp_proto = FIB_PROTOCOL_IP6,
97 /* VIF to PHY DB of managed interfaces */
98 static uword *lcp_routing_itf_db;
101 lcp_router_intf_h2p (u32 host)
108 * first check the linux side created interface (i.e. vlans, tunnels etc)
110 p = hash_get (lcp_routing_itf_db, host);
116 * then check the paired phys
118 lipi = lcp_itf_pair_find_by_vif (host);
120 if (INDEX_INVALID == lipi)
123 lip = lcp_itf_pair_get (lipi);
125 return lip->lip_phy_sw_if_index;
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.
136 lcp_router_lip_ts_check (nl_msg_info_t *msg_info, lcp_itf_pair_t *lip)
141 if (msg_info->ts > lip->lip_create_ts)
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);
151 lcp_router_link_del (struct rtnl_link *rl, void *ctx)
155 if (!lcp_auto_subint ())
158 lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
160 if (INDEX_INVALID != lipi)
164 lip = lcp_itf_pair_get (lipi);
166 if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
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);
174 if (rtnl_link_is_vlan (rl))
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);
184 LCP_ROUTER_INFO ("ignore link del: %s - %s", rtnl_link_get_type (rl),
185 rtnl_link_get_name (rl));
189 lcp_router_ip4_mroutes_add_del (u32 sw_if_index, u8 is_add)
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,
197 .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
203 mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
205 for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
209 mfib_table_entry_path_update (mfib_index, &ip4_specials[ii],
210 MFIB_SOURCE_PLUGIN_LOW,
211 MFIB_ENTRY_FLAG_NONE, &path);
215 mfib_table_entry_path_remove (mfib_index, &ip4_specials[ii],
216 MFIB_SOURCE_PLUGIN_LOW, &path);
222 lcp_router_ip6_mroutes_add_del (u32 sw_if_index, u8 is_add)
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,
230 .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
236 mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
238 for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
242 mfib_table_entry_path_update (mfib_index, &ip6_specials[ii],
243 MFIB_SOURCE_PLUGIN_LOW,
244 MFIB_ENTRY_FLAG_NONE, &path);
248 mfib_table_entry_path_remove (mfib_index, &ip6_specials[ii],
249 MFIB_SOURCE_PLUGIN_LOW, &path);
255 lcp_router_link_mtu (struct rtnl_link *rl, u32 sw_if_index)
257 vnet_main_t *vnm = vnet_get_main ();
259 vnet_sw_interface_t *sw;
260 vnet_hw_interface_t *hw;
262 mtu = rtnl_link_get_mtu (rl);
266 sw = vnet_get_sw_interface (vnm, sw_if_index);
267 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
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);
274 vnet_sw_interface_set_mtu (vnm, sw->sw_if_index, mtu);
278 lcp_router_link_addr_adj_upd_cb (vnet_main_t *vnm, u32 sw_if_index, void *arg)
282 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (sw_if_index));
285 return WALK_CONTINUE;
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]);
293 return WALK_CONTINUE;
297 lcp_router_link_addr (struct rtnl_link *rl, lcp_itf_pair_t *lip)
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;
305 mac_addr = rtnl_link_get_addr (rl);
306 if (!mac_addr || (nl_addr_get_family (mac_addr) != AF_LLC))
309 sw = vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index);
311 /* can only change address on hw interface */
312 if (sw->sw_if_index != sw->sup_sw_if_index)
315 hw = vnet_get_sup_hw_interface (vnm, lip->lip_phy_sw_if_index);
316 if (!vec_len (hw->hw_address))
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,
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);
329 static void lcp_router_table_flush (lcp_router_table_t *nlt,
330 u32 *sw_if_index_to_bool,
331 fib_source_t source);
334 lcp_router_link_add (struct rtnl_link *rl, void *ctx)
338 vnet_main_t *vnm = vnet_get_main ();
340 lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
341 up = IFF_UP & rtnl_link_get_flags (rl);
343 if (INDEX_INVALID != lipi)
349 lip = lcp_itf_pair_get (lipi);
350 if (!vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index))
353 if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
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);
362 vnet_sw_interface_admin_up (vnet_get_main (),
363 lip->lip_phy_sw_if_index);
365 else if (sw_if_up && !up)
367 vnet_sw_interface_admin_down (vnet_get_main (),
368 lip->lip_phy_sw_if_index);
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.
379 lcp_router_table_t *nlt;
381 fib_index = fib_table_get_index_for_sw_if_index (
382 FIB_PROTOCOL_IP4, lip->lip_phy_sw_if_index);
384 pool_foreach (nlt, lcp_router_table_pool)
386 if (fib_index == nlt->nlt_fib_index &&
387 FIB_PROTOCOL_IP4 == nlt->nlt_proto)
389 u32 *sw_if_index_to_bool = NULL;
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;
395 lcp_router_table_flush (nlt, sw_if_index_to_bool,
397 lcp_router_table_flush (nlt, sw_if_index_to_bool,
398 lcp_rt_fib_src_dynamic);
400 vec_free (sw_if_index_to_bool);
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"));
412 lcp_router_link_mtu (rl, lip->lip_phy_sw_if_index);
413 lcp_router_link_addr (rl, lip);
415 else if (lcp_auto_subint () && rtnl_link_is_vlan (rl))
417 /* Find the pair based on the parent VIF */
418 lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_link (rl));
420 if (INDEX_INVALID != lipi)
422 u32 sub_phy_sw_if_index, sub_host_sw_if_index;
423 const lcp_itf_pair_t *lip;
425 u8 *ns = 0; /* FIXME */
427 lip = lcp_itf_pair_get (lipi);
429 vlan = rtnl_link_vlan_get_id (rl);
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))
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);
442 /* pool could grow during the previous operation */
443 lip = lcp_itf_pair_get (lipi);
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))
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);
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);
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);
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);
482 LCP_ROUTER_INFO ("ignore parent-link add: %s - %s",
483 rtnl_link_get_type (rl), rtnl_link_get_name (rl));
487 LCP_ROUTER_INFO ("ignore link add: %s - %s", rtnl_link_get_type (rl),
488 rtnl_link_get_name (rl));
492 lcp_router_link_sync_begin (void)
494 LCP_ROUTER_INFO ("Begin synchronization of interface configurations");
498 lcp_router_link_sync_end (void)
500 LCP_ROUTER_INFO ("End synchronization of interface configurations");
503 static clib_error_t *
504 lcp_router_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
506 vnet_hw_interface_t *hi;
509 hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
513 lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
514 if (lipi == INDEX_INVALID)
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
521 * - Nexthop API: the kernel removes the next-hop objects and the routes
522 * which reference them.
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
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
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 ()))
538 u32 **fib_index_to_sw_if_index_to_bool = NULL;
540 lcp_router_table_t *nlt;
542 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
545 vec_validate_init_empty (fib_index_to_sw_if_index_to_bool, fib_index,
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;
551 /* clang-format off */
552 hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
554 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
556 vec_validate_init_empty (fib_index_to_sw_if_index_to_bool, fib_index,
558 vec_validate_init_empty (fib_index_to_sw_if_index_to_bool[fib_index],
560 fib_index_to_sw_if_index_to_bool[fib_index][sw_if_index] = true;
562 /* clang-format on */
564 vec_foreach_index (fib_index, fib_index_to_sw_if_index_to_bool)
566 u32 *sw_if_index_to_bool;
568 sw_if_index_to_bool = fib_index_to_sw_if_index_to_bool[fib_index];
569 if (NULL == sw_if_index_to_bool)
572 pool_foreach (nlt, lcp_router_table_pool)
574 if (fib_index == nlt->nlt_fib_index &&
575 FIB_PROTOCOL_IP4 == nlt->nlt_proto)
577 if (lcp_get_del_static_on_link_down ())
578 lcp_router_table_flush (nlt, sw_if_index_to_bool,
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);
587 vec_free (sw_if_index_to_bool);
590 vec_free (fib_index_to_sw_if_index_to_bool);
596 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_router_link_up_down);
598 static fib_protocol_t
599 lcp_router_proto_k2f (uint32_t k)
604 return FIB_PROTOCOL_IP6;
606 return FIB_PROTOCOL_IP4;
608 return FIB_PROTOCOL_MPLS;
611 return FIB_PROTOCOL_NONE;
616 lcp_router_mk_addr (const struct nl_addr *rna, ip_address_t *ia)
618 fib_protocol_t fproto;
620 ip_address_reset (ia);
621 fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
622 ASSERT (FIB_PROTOCOL_MPLS != fproto);
624 ip_address_set (ia, nl_addr_get_binary_addr (rna),
625 FIB_PROTOCOL_IP4 == fproto ? AF_IP4 : AF_IP6);
628 static fib_protocol_t
629 lcp_router_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
631 fib_protocol_t fproto;
633 fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
634 ASSERT (FIB_PROTOCOL_MPLS != fproto);
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));
640 memcpy (&ia->ip6, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
646 lcp_router_link_addr_add_del (struct rtnl_addr *rla, int is_del)
650 sw_if_index = lcp_router_intf_h2p (rtnl_addr_get_ifindex (rla));
652 if (~0 != sw_if_index)
656 lcp_router_mk_addr (rtnl_addr_get_local (rla), &nh);
658 if (AF_IP4 == ip_addr_version (&nh))
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);
665 else if (AF_IP6 == ip_addr_version (&nh))
667 if (ip6_address_is_link_local_unicast (&ip_addr_v6 (&nh)))
669 ip6_link_disable (sw_if_index);
672 ip6_link_enable (sw_if_index, NULL);
673 ip6_link_set_local_address (sw_if_index, &ip_addr_v6 (&nh));
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);
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));
689 lcp_router_link_addr_del (struct rtnl_addr *la)
691 lcp_router_link_addr_add_del (la, 1);
695 lcp_router_link_addr_add (struct rtnl_addr *la)
697 lcp_router_link_addr_add_del (la, 0);
701 lcp_router_address_mark (index_t index, void *ctx)
703 vnet_main_t *vnm = vnet_get_main ();
705 lcp_itf_pair_t *lip = lcp_itf_pair_get (index);
707 return WALK_CONTINUE;
709 ip_interface_address_mark_one_interface (
710 vnm, vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index), 0);
712 return WALK_CONTINUE;
716 lcp_router_link_addr_sync_begin (void)
718 lcp_itf_pair_walk (lcp_router_address_mark, 0);
720 LCP_ROUTER_INFO ("Begin synchronization of interface addresses");
724 lcp_router_link_addr_sync_end (void)
726 ip_interface_address_sweep ();
728 LCP_ROUTER_INFO ("End synchronization of interface addresses");
732 lcp_router_mk_mac_addr (const struct nl_addr *rna, mac_address_t *mac)
734 mac_address_from_bytes (mac, nl_addr_get_binary_addr (rna));
738 lcp_router_neigh_del (struct rtnl_neigh *rn)
742 sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
744 if (~0 != sw_if_index)
750 if ((rna = rtnl_neigh_get_dst (rn)) == NULL)
752 lcp_router_mk_addr (rna, &nh);
754 if (ip46_address_is_multicast (&ip_addr_46 (&nh)))
756 LCP_ROUTER_DBG ("ignore neighbor del: %U %U", format_ip_address, &nh,
757 format_vnet_sw_if_index_name, vnet_get_main (),
762 rv = ip_neighbor_del (&nh, sw_if_index);
767 "Failed to delete neighbor: %U %U", format_ip_address, &nh,
768 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
772 LCP_ROUTER_DBG ("neighbor del: %U %U", format_ip_address, &nh,
773 format_vnet_sw_if_index_name, vnet_get_main (),
778 LCP_ROUTER_INFO ("ignore neighbour del on: %d",
779 rtnl_neigh_get_ifindex (rn));
784 (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE | \
789 lcp_router_neigh_add (struct rtnl_neigh *rn)
793 sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
795 if (~0 != sw_if_index)
802 if ((rna = rtnl_neigh_get_dst (rn)) == NULL)
804 lcp_router_mk_addr (rna, &nh);
806 if (ip46_address_is_multicast (&ip_addr_46 (&nh)))
808 LCP_ROUTER_DBG ("ignore neighbor add: %U %U", format_ip_address, &nh,
809 format_vnet_sw_if_index_name, vnet_get_main (),
814 ll = rtnl_neigh_get_lladdr (rn);
815 state = rtnl_neigh_get_state (rn);
817 if (ll && (state & NUD_VALID))
820 ip_neighbor_flags_t flags;
823 lcp_router_mk_mac_addr (ll, &mac);
825 if (state & (NUD_NOARP | NUD_PERMANENT))
826 flags = IP_NEIGHBOR_FLAG_STATIC;
828 flags = IP_NEIGHBOR_FLAG_DYNAMIC;
830 rv = ip_neighbor_add (&nh, &mac, sw_if_index, flags, NULL);
835 "Failed to create neighbor: %U %U", format_ip_address, &nh,
836 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
840 LCP_ROUTER_DBG ("neighbor add: %U %U", format_ip_address, &nh,
841 format_vnet_sw_if_index_name, vnet_get_main (),
847 lcp_router_neigh_del (rn);
850 LCP_ROUTER_INFO ("ignore neighbour add on: %d",
851 rtnl_neigh_get_ifindex (rn));
855 lcp_router_neighbor_mark (index_t index, void *ctx)
857 lcp_itf_pair_t *lip = lcp_itf_pair_get (index);
859 return WALK_CONTINUE;
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);
864 return WALK_CONTINUE;
868 lcp_router_neigh_sync_begin (void)
870 lcp_itf_pair_walk (lcp_router_neighbor_mark, 0);
872 LCP_ROUTER_INFO ("Begin synchronization of neighbors");
876 lcp_router_neigh_sync_end (void)
878 ip_neighbor_sweep (AF_IP4);
879 ip_neighbor_sweep (AF_IP6);
881 LCP_ROUTER_INFO ("End synchronization of neighbors");
884 static lcp_router_table_t *
885 lcp_router_table_find (uint32_t id, fib_protocol_t fproto)
889 p = hash_get (lcp_router_table_db[fproto], id);
892 return pool_elt_at_index (lcp_router_table_pool, p[0]);
898 lcp_router_table_k2f (uint32_t k)
900 // the kernel's table ID 255 is the default table
901 if (k == 255 || k == 254)
906 static lcp_router_table_t *
907 lcp_router_table_add_or_lock (uint32_t id, fib_protocol_t fproto)
909 lcp_router_table_t *nlt;
911 id = lcp_router_table_k2f (id);
912 nlt = lcp_router_table_find (id, fproto);
916 pool_get_zero (lcp_router_table_pool, nlt);
919 nlt->nlt_proto = fproto;
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);
926 hash_set (lcp_router_table_db[fproto], nlt->nlt_id,
927 nlt - lcp_router_table_pool);
929 if (FIB_PROTOCOL_IP4 == fproto)
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);
935 const fib_route_path_t path = {
936 .frp_proto = DPO_PROTO_IP4,
937 .frp_addr = zero_addr,
938 .frp_sw_if_index = ~0,
941 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
942 .frp_flags = FIB_ROUTE_PATH_LOCAL,
946 for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
948 mfib_table_entry_path_update (
949 nlt->nlt_mfib_index, &ip4_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
950 MFIB_ENTRY_FLAG_NONE, &path);
953 else if (FIB_PROTOCOL_IP6 == fproto)
955 const fib_route_path_t path = {
956 .frp_proto = DPO_PROTO_IP6,
957 .frp_addr = zero_addr,
958 .frp_sw_if_index = ~0,
961 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
962 .frp_flags = FIB_ROUTE_PATH_LOCAL,
966 for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
968 mfib_table_entry_path_update (
969 nlt->nlt_mfib_index, &ip6_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
970 MFIB_ENTRY_FLAG_NONE, &path);
981 lcp_router_table_unlock (lcp_router_table_t *nlt)
985 if (0 == nlt->nlt_refs)
987 if (FIB_PROTOCOL_IP4 == nlt->nlt_proto)
989 /* Set the all 1s address in this table to punt */
990 fib_table_entry_special_remove (nlt->nlt_fib_index, &pfx_all1s,
994 fib_table_unlock (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
996 hash_unset (lcp_router_table_db[nlt->nlt_proto], nlt->nlt_id);
997 pool_put (lcp_router_table_pool, nlt);
1002 lcp_router_route_mk_prefix (struct rtnl_route *r, fib_prefix_t *p)
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;
1010 p->fp_proto = lcp_router_proto_k2f (nl_addr_get_family (addr));
1012 switch (p->fp_proto)
1014 case FIB_PROTOCOL_MPLS:
1015 entry = ntohl (*baddr);
1016 p->fp_label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
1018 p->fp_eos = MPLS_NON_EOS;
1020 case FIB_PROTOCOL_IP4:
1021 ip46_address_reset (paddr);
1022 memcpy (&paddr->ip4, baddr, blen);
1024 case FIB_PROTOCOL_IP6:
1025 memcpy (&paddr->ip6, baddr, blen);
1029 p->fp_len = nl_addr_get_prefixlen (addr);
1033 lcp_router_route_mk_mprefix (struct rtnl_route *r, mfib_prefix_t *p)
1035 const struct nl_addr *addr;
1037 addr = rtnl_route_get_dst (r);
1039 p->fp_len = nl_addr_get_prefixlen (addr);
1040 p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_grp_addr);
1042 addr = rtnl_route_get_src (r);
1044 p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_src_addr);
1048 lcp_router_mpls_nladdr_to_path (fib_route_path_t *path, struct nl_addr *addr)
1053 struct mpls_label *stack = nl_addr_get_binary_addr (addr);
1056 int label_count = 0;
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;
1065 fib_mpls_label_t fml = {
1070 vec_add1 (path->frp_label_stack, fml);
1072 if (entry & MPLS_LS_S_MASK)
1078 typedef struct lcp_router_route_path_parse_t_
1080 fib_route_path_t *paths;
1081 fib_protocol_t route_proto;
1083 fib_route_path_flags_t type_flags;
1085 } lcp_router_route_path_parse_t;
1088 lcp_router_route_path_parse (struct rtnl_nexthop *rnh, void *arg)
1090 lcp_router_route_path_parse_t *ctx = arg;
1091 fib_route_path_t *path;
1093 int label_count = 0;
1095 sw_if_index = lcp_router_intf_h2p (rtnl_route_nh_get_ifindex (rnh));
1097 if (~0 != sw_if_index)
1099 fib_protocol_t fproto;
1100 struct nl_addr *addr;
1102 vec_add2 (ctx->paths, path, 1);
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;
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.
1114 path->frp_weight = clib_max (1, rtnl_route_nh_get_weight (rnh));
1116 addr = rtnl_route_nh_get_gateway (rnh);
1118 addr = rtnl_route_nh_get_via (rnh);
1121 fproto = lcp_router_mk_addr46 (addr, &path->frp_addr);
1123 fproto = ctx->route_proto;
1125 path->frp_proto = fib_proto_to_dpo (fproto);
1127 if (ctx->route_proto == FIB_PROTOCOL_MPLS)
1129 addr = rtnl_route_nh_get_newdst (rnh);
1130 label_count = lcp_router_mpls_nladdr_to_path (path, addr);
1133 LCP_ROUTER_DBG (" is label swap to %u",
1134 path->frp_label_stack[0].fml_value);
1138 fib_mpls_label_t fml = {
1139 .fml_value = MPLS_LABEL_POP,
1141 vec_add1 (path->frp_label_stack, fml);
1142 LCP_ROUTER_DBG (" is label pop");
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);
1150 LCP_ROUTER_DBG (" has encap mpls, %d labels", label_count);
1154 path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
1156 LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
1161 * blackhole, unreachable, prohibit will not have a next hop in an
1162 * RTM_NEWROUTE. Add a path for them.
1165 lcp_router_route_path_add_special (struct rtnl_route *rr,
1166 lcp_router_route_path_parse_t *ctx)
1168 fib_route_path_t *path;
1170 if (rtnl_route_get_type (rr) < RTN_BLACKHOLE)
1173 /* if it already has a path, it does not need us to add one */
1174 if (vec_len (ctx->paths) > 0)
1177 vec_add2 (ctx->paths, path, 1);
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;
1184 LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
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.
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,
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,
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,
1214 static inline fib_source_t
1215 lcp_router_proto_fib_source (u8 rt_proto)
1217 return (rt_proto <= RTPROT_STATIC) ? lcp_rt_fib_src : lcp_rt_fib_src_dynamic;
1220 static fib_entry_flag_t
1221 lcp_router_route_mk_entry_flags (uint8_t rtype, int table_id, uint8_t rproto)
1223 fib_entry_flag_t fef = FIB_ENTRY_FLAG_NONE;
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;
1234 lcp_router_route_del (struct rtnl_route *rr)
1236 fib_entry_flag_t entry_flags;
1239 lcp_router_table_t *nlt;
1240 uint8_t rtype, rproto;
1242 rtype = rtnl_route_get_type (rr);
1243 table_id = rtnl_route_get_table (rr);
1244 rproto = rtnl_route_get_protocol (rr);
1246 /* skip unsupported route types and local table */
1247 if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
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);
1254 LCP_ROUTER_DBG ("route del: %d:%U %U", rtnl_route_get_table (rr),
1255 format_fib_prefix, &pfx, format_fib_entry_flags,
1261 lcp_router_route_path_parse_t np = {
1262 .route_proto = pfx.fp_proto,
1263 .type_flags = lcp_router_route_type_frpflags[rtype],
1266 rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
1267 lcp_router_route_path_add_special (rr, &np);
1269 if (0 != vec_len (np.paths))
1271 fib_source_t fib_src;
1273 fib_src = lcp_router_proto_fib_source (rproto);
1275 switch (pfx.fp_proto)
1277 case FIB_PROTOCOL_IP6:
1278 fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
1280 case FIB_PROTOCOL_MPLS:
1281 fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
1283 /* delete the EOS route in addition to NEOS - fallthrough */
1284 pfx.fp_eos = MPLS_EOS;
1286 fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
1291 vec_free (np.paths);
1293 lcp_router_table_unlock (nlt);
1296 static fib_route_path_t *
1297 lcp_router_fib_route_path_dup (fib_route_path_t *old)
1300 fib_route_path_t *p;
1302 fib_route_path_t *new = vec_dup (old);
1306 for (idx = 0; idx < vec_len (new); idx++)
1309 if (p->frp_label_stack)
1310 p->frp_label_stack = vec_dup (p->frp_label_stack);
1317 lcp_router_route_add (struct rtnl_route *rr, int is_replace)
1319 fib_entry_flag_t entry_flags;
1322 lcp_router_table_t *nlt;
1323 uint8_t rtype, rproto;
1325 rtype = rtnl_route_get_type (rr);
1326 table_id = rtnl_route_get_table (rr);
1327 rproto = rtnl_route_get_protocol (rr);
1329 /* skip unsupported route types and local table */
1330 if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
1333 lcp_router_route_mk_prefix (rr, &pfx);
1334 entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
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))))
1343 LCP_ROUTER_DBG ("route skip: %d:%U %U", rtnl_route_get_table (rr),
1344 format_fib_prefix, &pfx, format_fib_entry_flags,
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);
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),
1359 rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
1360 lcp_router_route_path_add_special (rr, &np);
1362 if (0 != vec_len (np.paths))
1364 if (rtype == RTN_MULTICAST)
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 = {};
1370 lcp_router_route_mk_mprefix (rr, &mpfx);
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);
1376 mfib_table_entry_paths_update (nlt->nlt_mfib_index, &mpfx,
1377 MFIB_SOURCE_PLUGIN_LOW,
1378 MFIB_ENTRY_FLAG_NONE, np.paths);
1382 fib_source_t fib_src;
1383 const fib_route_path_t *rpath;
1385 vec_foreach (rpath, np.paths)
1387 if (fib_route_path_is_attached (rpath))
1389 entry_flags |= FIB_ENTRY_FLAG_ATTACHED;
1394 fib_src = lcp_router_proto_fib_source (rproto);
1396 if (pfx.fp_proto == FIB_PROTOCOL_MPLS)
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);
1402 fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
1403 entry_flags, pathdup);
1405 fib_table_entry_path_add2 (nlt->nlt_fib_index, &pfx, fib_src,
1406 entry_flags, pathdup);
1409 /* install EOS route in addition to NEOS */
1410 pfx.fp_eos = MPLS_EOS;
1411 pfx.fp_payload_proto = np.paths[0].frp_proto;
1415 fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
1416 entry_flags, np.paths);
1418 fib_table_entry_path_add2 (nlt->nlt_fib_index, &pfx, fib_src,
1419 entry_flags, np.paths);
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);
1428 vec_free (np.paths);
1432 lcp_router_route_sync_begin (void)
1434 lcp_router_table_t *nlt;
1436 pool_foreach (nlt, lcp_router_table_pool)
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);
1442 LCP_ROUTER_INFO ("Begin synchronization of %U routes in table %u",
1443 format_fib_protocol, nlt->nlt_proto,
1444 nlt->nlt_fib_index);
1449 lcp_router_route_sync_end (void)
1451 lcp_router_table_t *nlt;
1453 pool_foreach (nlt, lcp_router_table_pool)
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);
1459 LCP_ROUTER_INFO ("End synchronization of %U routes in table %u",
1460 format_fib_protocol, nlt->nlt_proto,
1461 nlt->nlt_fib_index);
1465 typedef struct lcp_router_table_flush_ctx_t_
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;
1472 static fib_table_walk_rc_t
1473 lcp_router_table_flush_cb (fib_node_index_t fib_entry_index, void *arg)
1475 lcp_router_table_flush_ctx_t *ctx = arg;
1478 sw_if_index = fib_entry_get_resolving_interface_for_source (
1479 fib_entry_index, ctx->lrtf_source);
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])
1484 vec_add1 (ctx->lrtf_entries, fib_entry_index);
1486 return (FIB_TABLE_WALK_CONTINUE);
1490 lcp_router_table_flush (lcp_router_table_t *nlt, u32 *sw_if_index_to_bool,
1491 fib_source_t source)
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,
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);
1505 fib_table_walk (nlt->nlt_fib_index, nlt->nlt_proto,
1506 lcp_router_table_flush_cb, &ctx);
1508 LCP_ROUTER_DBG ("Flush table: entries number to delete %u",
1509 vec_len (ctx.lrtf_entries));
1511 vec_foreach (fib_entry_index, ctx.lrtf_entries)
1513 fib_table_entry_delete_index (*fib_entry_index, source);
1514 lcp_router_table_unlock (nlt);
1517 vec_free (ctx.lrtf_entries);
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 },
1546 static clib_error_t *
1547 lcp_router_init (vlib_main_t *vm)
1549 lcp_router_logger = vlib_log_register_class ("linux-cp", "router");
1551 nl_register_vft (&lcp_router_vft);
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.
1560 fib_source_allocate ("lcp-rt", FIB_SOURCE_PRIORITY_HI, FIB_SOURCE_BH_API);
1562 lcp_rt_fib_src_dynamic = fib_source_allocate (
1563 "lcp-rt-dynamic", FIB_SOURCE_PRIORITY_HI + 1, FIB_SOURCE_BH_API);
1568 VLIB_INIT_FUNCTION (lcp_router_init) = {
1569 .runs_before = VLIB_INITS ("lcp_nl_init"),
1573 * fd.io coding-style-patch-verification: ON
1576 * eval: (c-set-style "gnu")