2 * Copyright (c) 2020 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.
20 #include <sys/socket.h>
23 #include <linux-cp/lcp_interface.h>
24 #include <netlink/route/link/vlan.h>
26 #include <vnet/plugin/plugin.h>
27 #include <vnet/plugin/plugin.h>
29 #include <vnet/ip/ip_punt_drop.h>
30 #include <vnet/fib/fib_table.h>
31 #include <vnet/adj/adj_mcast.h>
32 #include <vnet/udp/udp.h>
33 #include <vnet/tcp/tcp.h>
34 #include <vnet/devices/tap/tap.h>
35 #include <vnet/devices/virtio/virtio.h>
36 #include <vnet/devices/netlink.h>
37 #include <vlibapi/api_helper_macros.h>
38 #include <vnet/ipsec/ipsec_punt.h>
40 static vlib_log_class_t lcp_itf_pair_logger;
45 lcp_itf_pair_t *lcp_itf_pair_pool;
48 lcp_itf_num_pairs (void)
50 return pool_elts (lcp_itf_pair_pool);
54 * DBs of interface-pair objects:
55 * - key'd by VIF (linux ID)
56 * - key'd by VPP's physical interface
57 * - number of shared uses of VPP's tap/host interface
59 static uword *lip_db_by_vif;
60 index_t *lip_db_by_phy;
64 * vector of virtual function table
66 static lcp_itf_pair_vft_t *lcp_itf_vfts = NULL;
69 lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
71 vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
74 #define LCP_ITF_PAIR_DBG(...) \
75 vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
77 #define LCP_ITF_PAIR_INFO(...) \
78 vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
81 format_lcp_itf_pair (u8 *s, va_list *args)
83 vnet_main_t *vnm = vnet_get_main ();
84 lcp_itf_pair_t *lip = va_arg (*args, lcp_itf_pair_t *);
85 vnet_sw_interface_t *swif_phy;
86 vnet_sw_interface_t *swif_host;
88 s = format (s, "itf-pair: [%d]", lip - lcp_itf_pair_pool);
90 swif_phy = vnet_get_sw_interface_or_null (vnm, lip->lip_phy_sw_if_index);
92 s = format (s, " <no-phy-if>");
94 s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_phy);
96 swif_host = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
98 s = format (s, " <no-host-if>");
100 s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_host);
102 s = format (s, " %v %d type %s", lip->lip_host_name, lip->lip_vif_index,
103 (lip->lip_host_type == LCP_ITF_HOST_TAP) ? "tap" : "tun");
105 if (lip->lip_namespace)
106 s = format (s, " netns %s", lip->lip_namespace);
112 lcp_itf_pair_walk_show_cb (index_t api, void *ctx)
117 lip = lcp_itf_pair_get (api);
121 vm = vlib_get_main ();
122 vlib_cli_output (vm, "%U\n", format_lcp_itf_pair, lip);
124 return WALK_CONTINUE;
128 lcp_itf_pair_show (u32 phy_sw_if_index)
134 vm = vlib_get_main ();
135 ns = lcp_get_default_ns ();
136 vlib_cli_output (vm, "lcp default netns '%s'\n",
137 ns ? (char *) ns : "<unset>");
139 if (phy_sw_if_index == ~0)
141 lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
145 api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
146 if (api != INDEX_INVALID)
147 lcp_itf_pair_walk_show_cb (api, 0);
152 lcp_itf_pair_get (u32 index)
154 return pool_elt_at_index (lcp_itf_pair_pool, index);
158 lcp_itf_pair_find_by_vif (u32 vif_index)
162 p = hash_get (lip_db_by_vif, vif_index);
167 return INDEX_INVALID;
171 lcp_itf_pair_add_sub (u32 vif, u8 *host_if_name, u32 sub_sw_if_index,
172 u32 phy_sw_if_index, u8 *ns)
176 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (phy_sw_if_index));
178 return lcp_itf_pair_add (lip->lip_host_sw_if_index, sub_sw_if_index,
179 host_if_name, vif, lip->lip_host_type, ns);
182 const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
183 [LCP_ITF_HOST_TAP] = {
184 [AF_IP4] = "linux-cp-xc-ip4",
185 [AF_IP6] = "linux-cp-xc-ip6",
187 [LCP_ITF_HOST_TUN] = {
188 [AF_IP4] = "linux-cp-xc-l3-ip4",
189 [AF_IP6] = "linux-cp-xc-l3-ip6",
193 const fib_route_path_flags_t lcp_itf_route_path_flags[N_LCP_ITF_HOST] = {
194 [LCP_ITF_HOST_TAP] = FIB_ROUTE_PATH_DVR,
195 [LCP_ITF_HOST_TUN] = FIB_ROUTE_PATH_FLAG_NONE,
199 lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
201 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
202 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
206 lcp_itf_set_adjs (lcp_itf_pair_t *lip)
208 if (lip->lip_host_type == LCP_ITF_HOST_TUN)
210 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_nbr_add_or_lock (
211 FIB_PROTOCOL_IP4, VNET_LINK_IP4, &zero_addr, lip->lip_phy_sw_if_index);
212 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_nbr_add_or_lock (
213 FIB_PROTOCOL_IP6, VNET_LINK_IP6, &zero_addr, lip->lip_phy_sw_if_index);
217 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_mcast_add_or_lock (
218 FIB_PROTOCOL_IP4, VNET_LINK_IP4, lip->lip_phy_sw_if_index);
219 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_mcast_add_or_lock (
220 FIB_PROTOCOL_IP6, VNET_LINK_IP6, lip->lip_phy_sw_if_index);
225 adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
227 lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
231 lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
232 u32 host_index, lip_host_type_t host_type, u8 *ns)
237 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
239 LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%v",
240 format_vnet_sw_if_index_name, vnet_get_main (),
241 host_sw_if_index, format_vnet_sw_if_index_name,
242 vnet_get_main (), phy_sw_if_index, host_name, host_index,
245 if (lipi != INDEX_INVALID)
246 return VNET_API_ERROR_VALUE_EXIST;
251 pool_get (lcp_itf_pair_pool, lip);
253 lipi = lip - lcp_itf_pair_pool;
255 vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
256 vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
257 lip_db_by_phy[phy_sw_if_index] = lipi;
258 lip_db_by_host[host_sw_if_index] = lipi;
259 hash_set (lip_db_by_vif, host_index, lipi);
261 lip->lip_host_sw_if_index = host_sw_if_index;
262 lip->lip_phy_sw_if_index = phy_sw_if_index;
263 lip->lip_host_name = vec_dup (host_name);
264 lip->lip_host_type = host_type;
265 lip->lip_vif_index = host_index;
266 lip->lip_namespace = vec_dup (ns);
268 if (lip->lip_host_sw_if_index == ~0)
272 * First use of this host interface.
273 * Enable the x-connect feature on the host to send
274 * all packets to the phy.
276 ip_address_family_t af;
278 FOR_EACH_IP_ADDRESS_FAMILY (af)
279 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
280 lcp_itf_l3_feat_names[lip->lip_host_type][af],
281 lip->lip_host_sw_if_index, 1, NULL, 0);
284 * Configure passive punt to the host interface.
286 fib_route_path_t *rpaths = NULL, rpath = {
287 .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
288 .frp_proto = DPO_PROTO_IP4,
289 .frp_sw_if_index = lip->lip_host_sw_if_index,
294 vec_add1 (rpaths, rpath);
296 ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
298 rpaths[0].frp_proto = DPO_PROTO_IP6;
300 ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
304 lcp_itf_set_adjs (lip);
306 /* enable ARP feature node for broadcast interfaces */
307 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
309 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
310 lip->lip_phy_sw_if_index, 1, NULL, 0);
311 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
312 lip->lip_host_sw_if_index, 1, NULL, 0);
316 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1, NULL,
318 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1, NULL,
322 /* invoke registered callbacks for pair addition */
323 lcp_itf_pair_vft_t *vft;
325 vec_foreach (vft, lcp_itf_vfts)
327 if (vft->pair_add_fn)
328 vft->pair_add_fn (lip);
331 /* set timestamp when pair entered service */
332 lip->lip_create_ts = vlib_time_now (vlib_get_main ());
337 static clib_error_t *
338 lcp_netlink_add_link_vlan (int parent, u32 vlan, const char *name)
340 struct rtnl_link *link;
344 sk = nl_socket_alloc ();
345 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
346 return clib_error_return (NULL, "Unable to connect socket: %d", err);
348 link = rtnl_link_vlan_alloc ();
350 rtnl_link_set_link (link, parent);
351 rtnl_link_set_name (link, name);
353 rtnl_link_vlan_set_id (link, vlan);
355 if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
356 return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
358 rtnl_link_put (link);
364 static clib_error_t *
365 lcp_netlink_del_link (const char *name)
367 struct rtnl_link *link;
371 sk = nl_socket_alloc ();
372 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
373 return clib_error_return (NULL, "Unable to connect socket: %d", err);
375 link = rtnl_link_alloc ();
376 rtnl_link_set_name (link, name);
378 if ((err = rtnl_link_delete (sk, link)) < 0)
379 return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
381 rtnl_link_put (link);
388 lcp_itf_pair_del (u32 phy_sw_if_index)
390 ip_address_family_t af;
393 lcp_itf_pair_vft_t *vft;
395 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
397 if (lipi == INDEX_INVALID)
398 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
400 lip = lcp_itf_pair_get (lipi);
402 LCP_ITF_PAIR_INFO ("pair delete: {%U, %U, %s}", format_vnet_sw_if_index_name,
403 vnet_get_main (), lip->lip_phy_sw_if_index,
404 format_vnet_sw_if_index_name, vnet_get_main (),
405 lip->lip_host_sw_if_index, lip->lip_host_name);
407 /* invoke registered callbacks for pair deletion */
408 vec_foreach (vft, lcp_itf_vfts)
410 if (vft->pair_del_fn)
411 vft->pair_del_fn (lip);
414 FOR_EACH_IP_ADDRESS_FAMILY (af)
415 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
416 lcp_itf_l3_feat_names[lip->lip_host_type][af],
417 lip->lip_host_sw_if_index, 0, NULL, 0);
419 lcp_itf_unset_adjs (lip);
421 ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
422 ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
424 /* disable ARP feature node for broadcast interfaces */
425 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
427 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
428 lip->lip_phy_sw_if_index, 0, NULL, 0);
429 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
430 lip->lip_host_sw_if_index, 0, NULL, 0);
434 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0, NULL,
436 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0, NULL,
440 lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
441 lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
442 hash_unset (lip_db_by_vif, lip->lip_vif_index);
444 vec_free (lip->lip_host_name);
445 vec_free (lip->lip_namespace);
446 pool_put (lcp_itf_pair_pool, lip);
452 lcp_itf_pair_delete_by_index (index_t lipi)
454 u32 host_sw_if_index;
458 lip = lcp_itf_pair_get (lipi);
460 host_name = vec_dup (lip->lip_host_name);
461 host_sw_if_index = lip->lip_host_sw_if_index;
463 lcp_itf_pair_del (lip->lip_phy_sw_if_index);
465 if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
467 lcp_netlink_del_link ((const char *) host_name);
468 vnet_delete_sub_interface (host_sw_if_index);
471 tap_delete_if (vlib_get_main (), host_sw_if_index);
473 vec_free (host_name);
477 lcp_itf_pair_delete (u32 phy_sw_if_index)
481 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
483 if (lipi == INDEX_INVALID)
484 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
486 lcp_itf_pair_delete_by_index (lipi);
492 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
496 pool_foreach_index (api, lcp_itf_pair_pool)
503 typedef struct lcp_itf_pair_names_t_
508 u32 lipn_phy_sw_if_index;
509 } lcp_itf_pair_names_t;
511 static lcp_itf_pair_names_t *lipn_names;
513 static clib_error_t *
514 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
520 host = phy = ns = default_ns = NULL;
522 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
524 vec_reset_length (host);
526 if (unformat (input, "pair %s %s %s", &phy, &host, &ns))
528 lcp_itf_pair_names_t *lipn;
530 if (vec_len (ns) > LCP_NS_LEN)
532 return clib_error_return (0,
533 "linux-cp IF namespace must"
534 " be less than %d characters",
538 vec_add2 (lipn_names, lipn, 1);
540 lipn->lipn_host_name = vec_dup (host);
541 lipn->lipn_phy_name = vec_dup (phy);
542 lipn->lipn_namespace = vec_dup (ns);
544 else if (unformat (input, "pair %v %v", &phy, &host))
546 lcp_itf_pair_names_t *lipn;
548 vec_add2 (lipn_names, lipn, 1);
550 lipn->lipn_host_name = vec_dup (host);
551 lipn->lipn_phy_name = vec_dup (phy);
552 lipn->lipn_namespace = 0;
554 else if (unformat (input, "default netns %v", &default_ns))
556 vec_add1 (default_ns, 0);
557 if (lcp_set_default_ns (default_ns) < 0)
559 return clib_error_return (0,
560 "linux-cp default namespace must"
561 " be less than %d characters",
565 else if (unformat (input, "interface-auto-create"))
566 lcp_set_auto_intf (1 /* is_auto */);
568 return clib_error_return (0, "interfaces not found");
573 vec_free (default_ns);
578 VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
581 * Returns 1 if the tap name is valid.
582 * Returns 0 if the tap name is invalid.
585 lcp_validate_if_name (u8 *name)
591 len = clib_strnlen (p, IFNAMSIZ);
618 lcp_itf_get_ns_fd (char *ns_name)
620 char ns_path[256] = "/proc/self/ns/net";
623 snprintf (ns_path, sizeof (ns_path) - 1, "/var/run/netns/%s", ns_name);
625 return open (ns_path, O_RDONLY);
629 lcp_itf_set_vif_link_state (u32 vif_index, u8 up, u8 *ns)
631 int curr_ns_fd, vif_ns_fd;
633 curr_ns_fd = vif_ns_fd = -1;
639 curr_ns_fd = open ("/proc/self/ns/net", O_RDONLY);
640 ns_path = format (0, "/var/run/netns/%s%c", (char *) ns, 0);
641 vif_ns_fd = open ((char *) ns_path, O_RDONLY);
643 setns (vif_ns_fd, CLONE_NEWNET);
646 vnet_netlink_set_link_state (vif_index, up);
651 if (curr_ns_fd != -1)
653 setns (curr_ns_fd, CLONE_NEWNET);
659 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
660 lip_host_type_t host_if_type, u8 *ns,
661 u32 *host_sw_if_indexp)
665 u32 vif_index = 0, host_sw_if_index;
666 const vnet_sw_interface_t *sw;
667 const vnet_hw_interface_t *hw;
669 if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
670 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
672 if (!lcp_validate_if_name (host_if_name))
673 return VNET_API_ERROR_INVALID_ARGUMENT;
675 vnm = vnet_get_main ();
676 sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
677 hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
680 * Use interface-specific netns if supplied.
681 * Otherwise, use default netns if defined.
682 * Otherwise ignore a netns and use the OS default.
684 if (ns == 0 || ns[0] == 0)
685 ns = lcp_get_default_ns ();
687 /* sub interfaces do not need a tap created */
688 if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
690 const lcp_itf_pair_t *lip;
691 int orig_ns_fd, ns_fd;
696 * Find the parent tap by finding the pair from the parent phy
698 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (sw->sup_sw_if_index));
699 vlan = sw->sub.eth.outer_vlan_id;
702 * see if the requested host interface has already been created
704 orig_ns_fd = ns_fd = -1;
707 if (ns && ns[0] != 0)
709 orig_ns_fd = lcp_itf_get_ns_fd (NULL);
710 ns_fd = lcp_itf_get_ns_fd ((char *) ns);
711 if (orig_ns_fd == -1 || ns_fd == -1)
714 setns (ns_fd, CLONE_NEWNET);
717 vif_index = if_nametoindex ((const char *) host_if_name);
722 * no existing host interface, create it now
724 err = lcp_netlink_add_link_vlan (lip->lip_vif_index, vlan,
725 (const char *) host_if_name);
727 if (!err && -1 != ns_fd)
728 err = vnet_netlink_set_link_netns (vif_index, ns_fd, NULL);
731 vif_index = if_nametoindex ((char *) host_if_name);
735 * create a sub-interface on the tap
737 if (!err && vnet_create_sub_interface (lip->lip_host_sw_if_index,
738 sw->sub.id, sw->sub.eth.raw_flags,
739 sw->sub.eth.inner_vlan_id, vlan,
741 LCP_ITF_PAIR_INFO ("failed create vlan: %d on %U", vlan,
742 format_vnet_sw_if_index_name, vnet_get_main (),
743 lip->lip_host_sw_if_index);
746 if (orig_ns_fd != -1)
748 setns (orig_ns_fd, CLONE_NEWNET);
755 return VNET_API_ERROR_INVALID_ARGUMENT;
759 tap_create_if_args_t args = {
760 .num_rx_queues = clib_max (1, vlib_num_workers ()),
761 .id = hw->hw_if_index,
765 .host_if_name = host_if_name,
768 ethernet_interface_t *ei;
770 if (host_if_type == LCP_ITF_HOST_TUN)
771 args.tap_flags |= TAP_FLAG_TUN;
774 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
775 mac_address_copy (&args.host_mac_addr, &ei->address.mac);
778 if (sw->mtu[VNET_MTU_L3])
780 args.host_mtu_set = 1;
781 args.host_mtu_size = sw->mtu[VNET_MTU_L3];
784 if (ns && ns[0] != 0)
785 args.host_namespace = ns;
787 vm = vlib_get_main ();
788 tap_create_if (vm, &args);
796 * get the hw and ethernet of the tap
798 hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
801 * Set the interface down on the host side.
802 * This controls whether the host can RX/TX.
804 virtio_main_t *mm = &virtio_main;
805 virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
807 lcp_itf_set_vif_link_state (vif->ifindex, 0 /* down */,
808 args.host_namespace);
811 * Leave the TAP permanently up on the VPP side.
812 * This TAP will be shared by many sub-interface.
813 * Therefore we can't use it to manage admin state.
814 * force the tap in promiscuous mode.
816 if (host_if_type == LCP_ITF_HOST_TAP)
818 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
819 ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
822 vif_index = vif->ifindex;
823 host_sw_if_index = args.sw_if_index;
828 LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
829 format_vnet_sw_if_index_name, vnet_get_main (),
830 phy_sw_if_index, format_vnet_sw_if_index_name,
831 vnet_get_main (), host_sw_if_index, host_if_name);
835 vnet_sw_interface_admin_up (vnm, host_sw_if_index);
836 lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
839 LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
840 vnet_get_main (), phy_sw_if_index,
841 format_vnet_sw_if_index_name, vnet_get_main (),
842 host_sw_if_index, host_if_name);
844 if (host_sw_if_indexp)
845 *host_sw_if_indexp = host_sw_if_index;
851 lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
855 lip = lcp_itf_pair_get (lipi);
857 lip->lip_flags |= LIP_FLAG_STALE;
859 return (WALK_CONTINUE);
863 lcp_itf_pair_replace_begin (void)
865 lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
870 typedef struct lcp_itf_pair_sweep_ctx_t_
873 } lcp_itf_pair_sweep_ctx_t;
876 lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
878 lcp_itf_pair_sweep_ctx_t *ctx = arg;
881 lip = lcp_itf_pair_get (lipi);
883 if (lip->lip_flags & LIP_FLAG_STALE)
884 vec_add1 (ctx->indicies, lipi);
886 return (WALK_CONTINUE);
890 lcp_itf_pair_replace_end (void)
892 lcp_itf_pair_sweep_ctx_t ctx = {
897 lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
899 vec_foreach (lipi, ctx.indicies)
900 lcp_itf_pair_delete_by_index (*lipi);
902 vec_free (ctx.indicies);
907 lcp_itf_pair_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
910 uword *event_data = 0;
915 vlib_process_wait_for_event (vm);
917 vlib_process_get_events (vm, &event_data);
919 vec_foreach (lipn_index, event_data)
921 lcp_itf_pair_names_t *lipn;
923 lipn = &lipn_names[*lipn_index];
924 lcp_itf_pair_create (lipn->lipn_phy_sw_if_index,
925 lipn->lipn_host_name, LCP_ITF_HOST_TAP,
926 lipn->lipn_namespace, NULL);
929 vec_reset_length (event_data);
935 VLIB_REGISTER_NODE (lcp_itf_pair_process_node, static) = {
936 .function = lcp_itf_pair_process,
937 .name = "linux-cp-itf-process",
938 .type = VLIB_NODE_TYPE_PROCESS,
941 static clib_error_t *
942 lcp_itf_phy_add (vnet_main_t *vnm, u32 sw_if_index, u32 is_create)
944 lcp_itf_pair_names_t *lipn;
945 vlib_main_t *vm = vlib_get_main ();
946 vnet_hw_interface_t *hw;
948 if (!is_create || vnet_sw_interface_is_sub (vnm, sw_if_index))
951 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
953 vec_foreach (lipn, lipn_names)
955 if (!vec_cmp (hw->name, lipn->lipn_phy_name))
957 lipn->lipn_phy_sw_if_index = sw_if_index;
959 vlib_process_signal_event (vm, lcp_itf_pair_process_node.index, 0,
968 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_phy_add);
970 static clib_error_t *
971 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
973 vnet_hw_interface_t *hi;
974 vnet_sw_interface_t *si;
978 hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
982 lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
983 if (lipi == INDEX_INVALID)
986 lip = lcp_itf_pair_get (lipi);
987 si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
991 if (!lcp_main.test_mode)
993 tap_set_carrier (si->hw_if_index,
994 (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
996 if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
998 tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1005 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1007 static clib_error_t *
1008 lcp_itf_pair_init (vlib_main_t *vm)
1010 vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1013 vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1016 /* punt all unknown ports */
1017 udp_punt_unknown (vm, 0, 1);
1018 udp_punt_unknown (vm, 1, 1);
1019 tcp_punt_unknown (vm, 0, 1);
1020 tcp_punt_unknown (vm, 1, 1);
1022 lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1027 VLIB_INIT_FUNCTION (lcp_itf_pair_init) = {
1028 .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1032 * fd.io coding-style-patch-verification: ON
1035 * eval: (c-set-style "gnu")