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>
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>
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>
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>
39 typedef struct lcp_router_table_t_
42 fib_protocol_t nlt_proto;
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;
52 const static fib_prefix_t pfx_all1s = {
58 .fp_proto = FIB_PROTOCOL_IP4,
62 static fib_source_t lcp_rt_fib_src;
63 static fib_source_t lcp_rt_fib_src_dynamic;
65 #define LCP_ROUTER_DBG(...) vlib_log_debug (lcp_router_logger, __VA_ARGS__);
67 #define LCP_ROUTER_INFO(...) vlib_log_notice (lcp_router_logger, __VA_ARGS__);
69 #define LCP_ROUTER_ERROR(...) vlib_log_err (lcp_router_logger, __VA_ARGS__);
71 static const mfib_prefix_t ip4_specials[] = {
72 /* ALL prefixes are in network order */
74 /* (*,224.0.0.0)/24 - all local subnet */
76 .ip4.data_u32 = 0x000000e0,
79 .fp_proto = FIB_PROTOCOL_IP4,
83 static const mfib_prefix_t ip6_specials[] = {
84 /* ALL prefixes are in network order */
86 /* (*,ff00::)/8 - all local subnet */
88 .ip6.as_u64[0] = 0x00000000000000ff,
91 .fp_proto = FIB_PROTOCOL_IP6,
95 /* VIF to PHY DB of managed interfaces */
96 static uword *lcp_routing_itf_db;
99 lcp_router_intf_h2p (u32 host)
106 * first check the linux side created interface (i.e. vlans, tunnels etc)
108 p = hash_get (lcp_routing_itf_db, host);
114 * then check the paired phys
116 lipi = lcp_itf_pair_find_by_vif (host);
118 if (INDEX_INVALID == lipi)
121 lip = lcp_itf_pair_get (lipi);
123 return lip->lip_phy_sw_if_index;
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.
134 lcp_router_lip_ts_check (nl_msg_info_t *msg_info, lcp_itf_pair_t *lip)
136 if (msg_info->ts > lip->lip_create_ts)
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);
146 lcp_router_link_del (struct rtnl_link *rl, void *ctx)
150 if (!lcp_auto_subint ())
153 lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
155 if (INDEX_INVALID != lipi)
159 lip = lcp_itf_pair_get (lipi);
161 if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
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);
169 if (rtnl_link_is_vlan (rl))
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);
179 LCP_ROUTER_INFO ("ignore link del: %s - %s", rtnl_link_get_type (rl),
180 rtnl_link_get_name (rl));
184 lcp_router_ip4_mroutes_add_del (u32 sw_if_index, u8 is_add)
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,
192 .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
198 mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
200 for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
204 mfib_table_entry_path_update (mfib_index, &ip4_specials[ii],
205 MFIB_SOURCE_PLUGIN_LOW,
206 MFIB_ENTRY_FLAG_NONE, &path);
210 mfib_table_entry_path_remove (mfib_index, &ip4_specials[ii],
211 MFIB_SOURCE_PLUGIN_LOW, &path);
217 lcp_router_ip6_mroutes_add_del (u32 sw_if_index, u8 is_add)
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,
225 .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
231 mfib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
233 for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
237 mfib_table_entry_path_update (mfib_index, &ip6_specials[ii],
238 MFIB_SOURCE_PLUGIN_LOW,
239 MFIB_ENTRY_FLAG_NONE, &path);
243 mfib_table_entry_path_remove (mfib_index, &ip6_specials[ii],
244 MFIB_SOURCE_PLUGIN_LOW, &path);
250 lcp_router_link_mtu (struct rtnl_link *rl, u32 sw_if_index)
252 vnet_main_t *vnm = vnet_get_main ();
254 vnet_sw_interface_t *sw;
255 vnet_hw_interface_t *hw;
257 mtu = rtnl_link_get_mtu (rl);
261 sw = vnet_get_sw_interface (vnm, sw_if_index);
262 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
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);
269 vnet_sw_interface_set_mtu (vnm, sw->sw_if_index, mtu);
273 lcp_router_link_addr (struct rtnl_link *rl, lcp_itf_pair_t *lip)
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;
281 mac_addr = rtnl_link_get_addr (rl);
282 if (!mac_addr || (nl_addr_get_family (mac_addr) != AF_LLC))
285 sw = vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index);
287 /* can only change address on hw interface */
288 if (sw->sw_if_index != sw->sup_sw_if_index)
291 hw = vnet_get_sup_hw_interface (vnm, lip->lip_phy_sw_if_index);
292 if (!vec_len (hw->hw_address))
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,
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]);
308 lcp_router_link_add (struct rtnl_link *rl, void *ctx)
312 vnet_main_t *vnm = vnet_get_main ();
314 lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_ifindex (rl));
315 up = IFF_UP & rtnl_link_get_flags (rl);
317 if (INDEX_INVALID != lipi)
321 lip = lcp_itf_pair_get (lipi);
322 if (!vnet_get_sw_interface (vnm, lip->lip_phy_sw_if_index))
325 if (lcp_router_lip_ts_check ((nl_msg_info_t *) ctx, lip))
330 vnet_sw_interface_admin_up (vnet_get_main (),
331 lip->lip_phy_sw_if_index);
335 vnet_sw_interface_admin_down (vnet_get_main (),
336 lip->lip_phy_sw_if_index);
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"));
344 lcp_router_link_mtu (rl, lip->lip_phy_sw_if_index);
345 lcp_router_link_addr (rl, lip);
347 else if (lcp_auto_subint () && rtnl_link_is_vlan (rl))
349 /* Find the pair based on the parent VIF */
350 lipi = lcp_itf_pair_find_by_vif (rtnl_link_get_link (rl));
352 if (INDEX_INVALID != lipi)
354 u32 sub_phy_sw_if_index, sub_host_sw_if_index;
355 const lcp_itf_pair_t *lip;
357 u8 *ns = 0; /* FIXME */
359 lip = lcp_itf_pair_get (lipi);
361 vlan = rtnl_link_vlan_get_id (rl);
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))
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);
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))
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);
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);
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);
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);
410 LCP_ROUTER_INFO ("ignore parent-link add: %s - %s",
411 rtnl_link_get_type (rl), rtnl_link_get_name (rl));
415 LCP_ROUTER_INFO ("ignore link add: %s - %s", rtnl_link_get_type (rl),
416 rtnl_link_get_name (rl));
419 static fib_protocol_t
420 lcp_router_proto_k2f (uint32_t k)
423 return (FIB_PROTOCOL_IP6);
424 return (FIB_PROTOCOL_IP4);
428 lcp_router_mk_addr (const struct nl_addr *rna, ip_address_t *ia)
430 fib_protocol_t fproto;
432 ip_address_reset (ia);
433 fproto = lcp_router_proto_k2f (nl_addr_get_family (rna));
435 ip_address_set (ia, nl_addr_get_binary_addr (rna),
436 FIB_PROTOCOL_IP4 == fproto ? AF_IP4 : AF_IP6);
439 static fib_protocol_t
440 lcp_router_mk_addr46 (const struct nl_addr *rna, ip46_address_t *ia)
442 fib_protocol_t fproto;
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));
449 memcpy (&ia->ip6, nl_addr_get_binary_addr (rna), nl_addr_get_len (rna));
455 lcp_router_link_addr_add_del (struct rtnl_addr *rla, int is_del)
459 sw_if_index = lcp_router_intf_h2p (rtnl_addr_get_ifindex (rla));
461 if (~0 != sw_if_index)
465 lcp_router_mk_addr (rtnl_addr_get_local (rla), &nh);
467 if (AF_IP4 == ip_addr_version (&nh))
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);
474 else if (AF_IP6 == ip_addr_version (&nh))
476 if (ip6_address_is_link_local_unicast (&ip_addr_v6 (&nh)))
478 ip6_link_disable (sw_if_index);
481 ip6_link_enable (sw_if_index, NULL);
482 ip6_link_set_local_address (sw_if_index, &ip_addr_v6 (&nh));
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);
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));
498 lcp_router_link_addr_del (struct rtnl_addr *la)
500 lcp_router_link_addr_add_del (la, 1);
504 lcp_router_link_addr_add (struct rtnl_addr *la)
506 lcp_router_link_addr_add_del (la, 0);
510 lcp_router_mk_mac_addr (const struct nl_addr *rna, mac_address_t *mac)
512 mac_address_from_bytes (mac, nl_addr_get_binary_addr (rna));
516 lcp_router_neigh_del (struct rtnl_neigh *rn)
520 sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
522 if (~0 != sw_if_index)
527 lcp_router_mk_addr (rtnl_neigh_get_dst (rn), &nh);
529 rv = ip_neighbor_del (&nh, sw_if_index);
534 "Failed to delete neighbor: %U %U", format_ip_address, &nh,
535 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
539 LCP_ROUTER_DBG ("neighbor del: %U %U", format_ip_address, &nh,
540 format_vnet_sw_if_index_name, vnet_get_main (),
545 LCP_ROUTER_INFO ("ignore neighbour del on: %d",
546 rtnl_neigh_get_ifindex (rn));
551 (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE | \
556 lcp_router_neigh_add (struct rtnl_neigh *rn)
560 sw_if_index = lcp_router_intf_h2p (rtnl_neigh_get_ifindex (rn));
562 if (~0 != sw_if_index)
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);
572 if (ll && (state & NUD_VALID))
575 ip_neighbor_flags_t flags;
578 lcp_router_mk_mac_addr (ll, &mac);
580 if (state & (NUD_NOARP | NUD_PERMANENT))
581 flags = IP_NEIGHBOR_FLAG_STATIC;
583 flags = IP_NEIGHBOR_FLAG_DYNAMIC;
585 rv = ip_neighbor_add (&nh, &mac, sw_if_index, flags, NULL);
590 "Failed to create neighbor: %U %U", format_ip_address, &nh,
591 format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
595 LCP_ROUTER_DBG ("neighbor add: %U %U", format_ip_address, &nh,
596 format_vnet_sw_if_index_name, vnet_get_main (),
602 lcp_router_neigh_del (rn);
605 LCP_ROUTER_INFO ("ignore neighbour add on: %d",
606 rtnl_neigh_get_ifindex (rn));
609 static lcp_router_table_t *
610 lcp_router_table_find (uint32_t id, fib_protocol_t fproto)
614 p = hash_get (lcp_router_table_db[fproto], id);
617 return pool_elt_at_index (lcp_router_table_pool, p[0]);
623 lcp_router_table_k2f (uint32_t k)
625 // the kernel's table ID 255 is the default table
626 if (k == 255 || k == 254)
631 static lcp_router_table_t *
632 lcp_router_table_add_or_lock (uint32_t id, fib_protocol_t fproto)
634 lcp_router_table_t *nlt;
636 id = lcp_router_table_k2f (id);
637 nlt = lcp_router_table_find (id, fproto);
641 pool_get_zero (lcp_router_table_pool, nlt);
644 nlt->nlt_proto = fproto;
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);
651 hash_set (lcp_router_table_db[fproto], nlt->nlt_id,
652 nlt - lcp_router_table_pool);
654 if (FIB_PROTOCOL_IP4 == fproto)
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);
660 const fib_route_path_t path = {
661 .frp_proto = DPO_PROTO_IP4,
662 .frp_addr = zero_addr,
663 .frp_sw_if_index = ~0,
666 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
667 .frp_flags = FIB_ROUTE_PATH_LOCAL,
671 for (ii = 0; ii < ARRAY_LEN (ip4_specials); ii++)
673 mfib_table_entry_path_update (
674 nlt->nlt_mfib_index, &ip4_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
675 MFIB_ENTRY_FLAG_NONE, &path);
678 else if (FIB_PROTOCOL_IP6 == fproto)
680 const fib_route_path_t path = {
681 .frp_proto = DPO_PROTO_IP6,
682 .frp_addr = zero_addr,
683 .frp_sw_if_index = ~0,
686 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
687 .frp_flags = FIB_ROUTE_PATH_LOCAL,
691 for (ii = 0; ii < ARRAY_LEN (ip6_specials); ii++)
693 mfib_table_entry_path_update (
694 nlt->nlt_mfib_index, &ip6_specials[ii], MFIB_SOURCE_PLUGIN_LOW,
695 MFIB_ENTRY_FLAG_NONE, &path);
706 lcp_router_table_unlock (lcp_router_table_t *nlt)
710 if (0 == nlt->nlt_refs)
712 if (FIB_PROTOCOL_IP4 == nlt->nlt_proto)
714 /* Set the all 1s address in this table to punt */
715 fib_table_entry_special_remove (nlt->nlt_fib_index, &pfx_all1s,
719 fib_table_unlock (nlt->nlt_fib_index, nlt->nlt_proto, lcp_rt_fib_src);
721 hash_unset (lcp_router_table_db[nlt->nlt_proto], nlt->nlt_id);
722 pool_put (lcp_router_table_pool, nlt);
727 lcp_router_route_mk_prefix (struct rtnl_route *r, fib_prefix_t *p)
729 const struct nl_addr *addr = rtnl_route_get_dst (r);
731 p->fp_len = nl_addr_get_prefixlen (addr);
732 p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_addr);
736 lcp_router_route_mk_mprefix (struct rtnl_route *r, mfib_prefix_t *p)
738 const struct nl_addr *addr;
740 addr = rtnl_route_get_dst (r);
742 p->fp_len = nl_addr_get_prefixlen (addr);
743 p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_grp_addr);
745 addr = rtnl_route_get_src (r);
747 p->fp_proto = lcp_router_mk_addr46 (addr, &p->fp_src_addr);
750 typedef struct lcp_router_route_path_parse_t_
752 fib_route_path_t *paths;
753 fib_protocol_t route_proto;
755 fib_route_path_flags_t type_flags;
757 } lcp_router_route_path_parse_t;
760 lcp_router_route_path_parse (struct rtnl_nexthop *rnh, void *arg)
762 lcp_router_route_path_parse_t *ctx = arg;
763 fib_route_path_t *path;
766 sw_if_index = lcp_router_intf_h2p (rtnl_route_nh_get_ifindex (rnh));
768 if (~0 != sw_if_index)
770 fib_protocol_t fproto;
771 struct nl_addr *addr;
773 vec_add2 (ctx->paths, path, 1);
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;
780 addr = rtnl_route_nh_get_gateway (rnh);
783 fproto = lcp_router_mk_addr46 (rtnl_route_nh_get_gateway (rnh),
786 fproto = ctx->route_proto;
788 path->frp_proto = fib_proto_to_dpo (fproto);
791 path->frp_mitf_flags = MFIB_ITF_FLAG_FORWARD;
793 LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
798 * blackhole, unreachable, prohibit will not have a next hop in an
799 * RTM_NEWROUTE. Add a path for them.
802 lcp_router_route_path_add_special (struct rtnl_route *rr,
803 lcp_router_route_path_parse_t *ctx)
805 fib_route_path_t *path;
807 if (rtnl_route_get_type (rr) < RTN_BLACKHOLE)
810 /* if it already has a path, it does not need us to add one */
811 if (vec_len (ctx->paths) > 0)
814 vec_add2 (ctx->paths, path, 1);
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;
821 LCP_ROUTER_DBG (" path:[%U]", format_fib_route_path, path);
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.
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,
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,
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,
851 static inline fib_source_t
852 lcp_router_proto_fib_source (u8 rt_proto)
854 return (rt_proto <= RTPROT_STATIC) ? lcp_rt_fib_src : lcp_rt_fib_src_dynamic;
857 static fib_entry_flag_t
858 lcp_router_route_mk_entry_flags (uint8_t rtype, int table_id, uint8_t rproto)
860 fib_entry_flag_t fef = FIB_ENTRY_FLAG_NONE;
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;
871 lcp_router_route_del (struct rtnl_route *rr)
873 fib_entry_flag_t entry_flags;
876 lcp_router_table_t *nlt;
877 uint8_t rtype, rproto;
879 rtype = rtnl_route_get_type (rr);
880 table_id = rtnl_route_get_table (rr);
881 rproto = rtnl_route_get_protocol (rr);
883 /* skip unsupported route types and local table */
884 if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
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);
891 LCP_ROUTER_DBG ("route del: %d:%U %U", rtnl_route_get_table (rr),
892 format_fib_prefix, &pfx, format_fib_entry_flags,
898 lcp_router_route_path_parse_t np = {
899 .route_proto = pfx.fp_proto,
900 .type_flags = lcp_router_route_type_frpflags[rtype],
903 rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
904 lcp_router_route_path_add_special (rr, &np);
906 if (0 != vec_len (np.paths))
908 fib_source_t fib_src;
910 fib_src = lcp_router_proto_fib_source (rproto);
912 if (pfx.fp_proto == FIB_PROTOCOL_IP6)
913 fib_table_entry_delete (nlt->nlt_fib_index, &pfx, fib_src);
915 fib_table_entry_path_remove2 (nlt->nlt_fib_index, &pfx, fib_src,
921 lcp_router_table_unlock (nlt);
925 lcp_router_route_add (struct rtnl_route *rr)
927 fib_entry_flag_t entry_flags;
930 lcp_router_table_t *nlt;
931 uint8_t rtype, rproto;
933 rtype = rtnl_route_get_type (rr);
934 table_id = rtnl_route_get_table (rr);
935 rproto = rtnl_route_get_protocol (rr);
937 /* skip unsupported route types and local table */
938 if (!lcp_router_route_type_valid[rtype] || (table_id == 255))
941 lcp_router_route_mk_prefix (rr, &pfx);
942 entry_flags = lcp_router_route_mk_entry_flags (rtype, table_id, rproto);
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)))
949 LCP_ROUTER_DBG ("route skip: %d:%U %U", rtnl_route_get_table (rr),
950 format_fib_prefix, &pfx, format_fib_entry_flags,
955 LCP_ROUTER_DBG ("route add: %d:%U %U", rtnl_route_get_table (rr),
956 format_fib_prefix, &pfx, format_fib_entry_flags,
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),
966 rtnl_route_foreach_nexthop (rr, lcp_router_route_path_parse, &np);
967 lcp_router_route_path_add_special (rr, &np);
969 if (0 != vec_len (np.paths))
971 nlt = lcp_router_table_add_or_lock (table_id, pfx.fp_proto);
972 if (rtype == RTN_MULTICAST)
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 = {};
978 lcp_router_route_mk_mprefix (rr, &mpfx);
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);
984 mfib_table_entry_paths_update (nlt->nlt_mfib_index, &mpfx,
985 MFIB_SOURCE_PLUGIN_LOW,
986 MFIB_ENTRY_FLAG_NONE, np.paths);
990 fib_source_t fib_src;
992 fib_src = lcp_router_proto_fib_source (rproto);
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);
998 fib_table_entry_update (nlt->nlt_fib_index, &pfx, fib_src,
999 entry_flags, np.paths);
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);
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 },
1021 static clib_error_t *
1022 lcp_router_init (vlib_main_t *vm)
1024 lcp_router_logger = vlib_log_register_class ("linux-cp", "router");
1026 nl_register_vft (&lcp_router_vft);
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.
1035 fib_source_allocate ("lcp-rt", FIB_SOURCE_PRIORITY_HI, FIB_SOURCE_BH_API);
1037 lcp_rt_fib_src_dynamic = fib_source_allocate (
1038 "lcp-rt-dynamic", FIB_SOURCE_PRIORITY_HI + 1, FIB_SOURCE_BH_API);
1043 VLIB_INIT_FUNCTION (lcp_router_init) = {
1044 .runs_before = VLIB_INITS ("lcp_nl_init"),
1048 * fd.io coding-style-patch-verification: ON
1051 * eval: (c-set-style "gnu")