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.
19 #include <sys/socket.h>
22 #include <linux-cp/lcp_interface.h>
23 #include <netlink/route/link/vlan.h>
24 #include <linux/if_ether.h>
26 #include <vnet/plugin/plugin.h>
27 #include <vnet/plugin/plugin.h>
29 #include <vppinfra/linux/netns.h>
31 #include <vnet/ip/ip_punt_drop.h>
32 #include <vnet/fib/fib_table.h>
33 #include <vnet/adj/adj_mcast.h>
34 #include <vnet/udp/udp.h>
35 #include <vnet/tcp/tcp.h>
36 #include <vnet/devices/tap/tap.h>
37 #include <vnet/devices/virtio/virtio.h>
38 #include <vnet/devices/netlink.h>
39 #include <vlibapi/api_helper_macros.h>
40 #include <vnet/ipsec/ipsec_punt.h>
42 static vlib_log_class_t lcp_itf_pair_logger;
47 lcp_itf_pair_t *lcp_itf_pair_pool = NULL;
50 lcp_itf_num_pairs (void)
52 return pool_elts (lcp_itf_pair_pool);
56 * DBs of interface-pair objects:
57 * - key'd by VIF (linux ID)
58 * - key'd by VPP's physical interface
59 * - number of shared uses of VPP's tap/host interface
61 static uword *lip_db_by_vif;
62 index_t *lip_db_by_phy;
66 * vector of virtual function table
68 static lcp_itf_pair_vft_t *lcp_itf_vfts = NULL;
71 lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
73 vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
76 #define LCP_ITF_PAIR_DBG(...) \
77 vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
79 #define LCP_ITF_PAIR_INFO(...) \
80 vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
82 #define LCP_ITF_PAIR_ERR(...) vlib_log_err (lcp_itf_pair_logger, __VA_ARGS__);
85 format_lcp_itf_pair (u8 *s, va_list *args)
87 vnet_main_t *vnm = vnet_get_main ();
88 lcp_itf_pair_t *lip = va_arg (*args, lcp_itf_pair_t *);
89 vnet_sw_interface_t *swif_phy;
90 vnet_sw_interface_t *swif_host;
92 s = format (s, "itf-pair: [%d]", lip - lcp_itf_pair_pool);
94 swif_phy = vnet_get_sw_interface_or_null (vnm, lip->lip_phy_sw_if_index);
96 s = format (s, " <no-phy-if>");
98 s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_phy);
100 swif_host = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
102 s = format (s, " <no-host-if>");
104 s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_host);
106 s = format (s, " %v %d type %s", lip->lip_host_name, lip->lip_vif_index,
107 (lip->lip_host_type == LCP_ITF_HOST_TAP) ? "tap" : "tun");
109 if (lip->lip_namespace)
110 s = format (s, " netns %s", lip->lip_namespace);
116 lcp_itf_pair_walk_show_cb (index_t api, void *ctx)
121 lip = lcp_itf_pair_get (api);
125 vm = vlib_get_main ();
126 vlib_cli_output (vm, "%U\n", format_lcp_itf_pair, lip);
128 return WALK_CONTINUE;
132 lcp_itf_pair_show (u32 phy_sw_if_index)
138 vm = vlib_get_main ();
139 ns = lcp_get_default_ns ();
140 vlib_cli_output (vm, "lcp default netns '%s'\n",
141 ns ? (char *) ns : "<unset>");
143 if (phy_sw_if_index == ~0)
145 lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
149 api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
150 if (api != INDEX_INVALID)
151 lcp_itf_pair_walk_show_cb (api, 0);
156 lcp_itf_pair_get (u32 index)
158 if (!lcp_itf_pair_pool)
161 return pool_elt_at_index (lcp_itf_pair_pool, index);
165 lcp_itf_pair_find_by_vif (u32 vif_index)
169 p = hash_get (lip_db_by_vif, vif_index);
174 return INDEX_INVALID;
178 lcp_itf_pair_add_sub (u32 vif, u8 *host_if_name, u32 sub_sw_if_index,
179 u32 phy_sw_if_index, u8 *ns)
183 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (phy_sw_if_index));
186 LCP_ITF_PAIR_DBG ("lcp_itf_pair_add_sub: can't find LCP of parent %U",
187 format_vnet_sw_if_index_name, vnet_get_main (),
189 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
192 return lcp_itf_pair_add (lip->lip_host_sw_if_index, sub_sw_if_index,
193 host_if_name, vif, lip->lip_host_type, ns);
196 const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
197 [LCP_ITF_HOST_TAP] = {
198 [AF_IP4] = "linux-cp-xc-ip4",
199 [AF_IP6] = "linux-cp-xc-ip6",
201 [LCP_ITF_HOST_TUN] = {
202 [AF_IP4] = "linux-cp-xc-l3-ip4",
203 [AF_IP6] = "linux-cp-xc-l3-ip6",
207 const fib_route_path_flags_t lcp_itf_route_path_flags[N_LCP_ITF_HOST] = {
208 [LCP_ITF_HOST_TAP] = FIB_ROUTE_PATH_DVR,
209 [LCP_ITF_HOST_TUN] = FIB_ROUTE_PATH_FLAG_NONE,
213 lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
215 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
216 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
220 lcp_itf_set_adjs (lcp_itf_pair_t *lip)
222 if (lip->lip_host_type == LCP_ITF_HOST_TUN)
224 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_nbr_add_or_lock (
225 FIB_PROTOCOL_IP4, VNET_LINK_IP4, &zero_addr, lip->lip_phy_sw_if_index);
226 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_nbr_add_or_lock (
227 FIB_PROTOCOL_IP6, VNET_LINK_IP6, &zero_addr, lip->lip_phy_sw_if_index);
231 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_mcast_add_or_lock (
232 FIB_PROTOCOL_IP4, VNET_LINK_IP4, lip->lip_phy_sw_if_index);
233 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_mcast_add_or_lock (
234 FIB_PROTOCOL_IP6, VNET_LINK_IP6, lip->lip_phy_sw_if_index);
239 adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
241 lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
245 lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
246 u32 host_index, lip_host_type_t host_type, u8 *ns)
251 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
253 LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%s",
254 format_vnet_sw_if_index_name, vnet_get_main (),
255 host_sw_if_index, format_vnet_sw_if_index_name,
256 vnet_get_main (), phy_sw_if_index, host_name, host_index,
259 if (lipi != INDEX_INVALID)
260 return VNET_API_ERROR_VALUE_EXIST;
265 pool_get (lcp_itf_pair_pool, lip);
267 lipi = lip - lcp_itf_pair_pool;
269 vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
270 vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
271 lip_db_by_phy[phy_sw_if_index] = lipi;
272 lip_db_by_host[host_sw_if_index] = lipi;
273 hash_set (lip_db_by_vif, host_index, lipi);
275 lip->lip_host_sw_if_index = host_sw_if_index;
276 lip->lip_phy_sw_if_index = phy_sw_if_index;
277 lip->lip_host_name = vec_dup (host_name);
278 lip->lip_host_type = host_type;
279 lip->lip_vif_index = host_index;
280 lip->lip_namespace = vec_dup (ns);
282 if (lip->lip_host_sw_if_index == ~0)
286 * First use of this host interface.
287 * Enable the x-connect feature on the host to send
288 * all packets to the phy.
290 ip_address_family_t af;
292 FOR_EACH_IP_ADDRESS_FAMILY (af)
293 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
294 lcp_itf_l3_feat_names[lip->lip_host_type][af],
295 lip->lip_host_sw_if_index, 1, NULL, 0);
298 * Configure passive punt to the host interface.
300 fib_route_path_t *rpaths = NULL, rpath = {
301 .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
302 .frp_proto = DPO_PROTO_IP4,
303 .frp_sw_if_index = lip->lip_host_sw_if_index,
308 vec_add1 (rpaths, rpath);
310 ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
312 rpaths[0].frp_proto = DPO_PROTO_IP6;
314 ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
318 lcp_itf_set_adjs (lip);
320 /* enable ARP feature node for broadcast interfaces */
321 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
323 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
324 lip->lip_phy_sw_if_index, 1, NULL, 0);
325 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
326 lip->lip_host_sw_if_index, 1, NULL, 0);
330 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1, NULL,
332 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1, NULL,
336 /* invoke registered callbacks for pair addition */
337 lcp_itf_pair_vft_t *vft;
339 vec_foreach (vft, lcp_itf_vfts)
341 if (vft->pair_add_fn)
342 vft->pair_add_fn (lip);
345 /* set timestamp when pair entered service */
346 lip->lip_create_ts = vlib_time_now (vlib_get_main ());
351 static clib_error_t *
352 lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name)
354 struct rtnl_link *link;
358 sk = nl_socket_alloc ();
359 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
361 LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: connect error: %s",
363 return clib_error_return (NULL, "Unable to connect socket: %d", err);
366 link = rtnl_link_vlan_alloc ();
368 rtnl_link_set_link (link, parent);
369 rtnl_link_set_name (link, name);
370 rtnl_link_vlan_set_id (link, vlan);
371 rtnl_link_vlan_set_protocol (link, htons (proto));
373 if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
375 LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: link add error: %s",
377 return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
380 rtnl_link_put (link);
386 static clib_error_t *
387 lcp_netlink_del_link (const char *name)
389 struct rtnl_link *link;
393 sk = nl_socket_alloc ();
394 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
395 return clib_error_return (NULL, "Unable to connect socket: %d", err);
397 link = rtnl_link_alloc ();
398 rtnl_link_set_name (link, name);
400 if ((err = rtnl_link_delete (sk, link)) < 0)
401 return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
403 rtnl_link_put (link);
410 lcp_itf_pair_del (u32 phy_sw_if_index)
412 ip_address_family_t af;
415 lcp_itf_pair_vft_t *vft;
417 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
419 if (lipi == INDEX_INVALID)
420 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
422 lip = lcp_itf_pair_get (lipi);
424 LCP_ITF_PAIR_INFO ("pair delete: {%U, %U, %s}", format_vnet_sw_if_index_name,
425 vnet_get_main (), lip->lip_phy_sw_if_index,
426 format_vnet_sw_if_index_name, vnet_get_main (),
427 lip->lip_host_sw_if_index, lip->lip_host_name);
429 /* invoke registered callbacks for pair deletion */
430 vec_foreach (vft, lcp_itf_vfts)
432 if (vft->pair_del_fn)
433 vft->pair_del_fn (lip);
436 FOR_EACH_IP_ADDRESS_FAMILY (af)
437 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
438 lcp_itf_l3_feat_names[lip->lip_host_type][af],
439 lip->lip_host_sw_if_index, 0, NULL, 0);
441 lcp_itf_unset_adjs (lip);
443 ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
444 ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
446 /* disable ARP feature node for broadcast interfaces */
447 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
449 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
450 lip->lip_phy_sw_if_index, 0, NULL, 0);
451 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
452 lip->lip_host_sw_if_index, 0, NULL, 0);
456 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0, NULL,
458 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0, NULL,
462 lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
463 lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
464 hash_unset (lip_db_by_vif, lip->lip_vif_index);
466 vec_free (lip->lip_host_name);
467 vec_free (lip->lip_namespace);
468 pool_put (lcp_itf_pair_pool, lip);
474 lcp_itf_pair_delete_by_index (index_t lipi)
476 u32 host_sw_if_index;
480 lip = lcp_itf_pair_get (lipi);
482 host_name = vec_dup (lip->lip_host_name);
483 host_sw_if_index = lip->lip_host_sw_if_index;
485 lcp_itf_pair_del (lip->lip_phy_sw_if_index);
487 if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
489 lcp_netlink_del_link ((const char *) host_name);
490 vnet_delete_sub_interface (host_sw_if_index);
493 tap_delete_if (vlib_get_main (), host_sw_if_index);
495 vec_free (host_name);
499 lcp_itf_pair_delete (u32 phy_sw_if_index)
503 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
505 if (lipi == INDEX_INVALID)
506 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
508 lcp_itf_pair_delete_by_index (lipi);
514 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
518 pool_foreach_index (api, lcp_itf_pair_pool)
525 typedef struct lcp_itf_pair_names_t_
530 u32 lipn_phy_sw_if_index;
531 } lcp_itf_pair_names_t;
533 static lcp_itf_pair_names_t *lipn_names;
535 static clib_error_t *
536 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
542 host = phy = ns = default_ns = NULL;
544 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
546 vec_reset_length (host);
548 if (unformat (input, "pair %s %s %s", &phy, &host, &ns))
550 lcp_itf_pair_names_t *lipn;
552 if (vec_len (ns) > LCP_NS_LEN)
554 return clib_error_return (0,
555 "linux-cp namespace must"
556 " be less than %d characters",
560 vec_add2 (lipn_names, lipn, 1);
562 lipn->lipn_host_name = vec_dup (host);
563 lipn->lipn_phy_name = vec_dup (phy);
564 lipn->lipn_namespace = vec_dup (ns);
566 else if (unformat (input, "pair %v %v", &phy, &host))
568 lcp_itf_pair_names_t *lipn;
570 vec_add2 (lipn_names, lipn, 1);
572 lipn->lipn_host_name = vec_dup (host);
573 lipn->lipn_phy_name = vec_dup (phy);
574 lipn->lipn_namespace = 0;
576 else if (unformat (input, "default netns %v", &default_ns))
578 vec_add1 (default_ns, 0);
579 if (lcp_set_default_ns (default_ns) < 0)
581 return clib_error_return (0,
582 "linux-cp default namespace must"
583 " be less than %d characters",
587 else if (unformat (input, "interface-auto-create"))
588 lcp_set_auto_intf (1 /* is_auto */);
590 return clib_error_return (0, "interfaces not found");
595 vec_free (default_ns);
600 VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
603 * Returns 1 if the tap name is valid.
604 * Returns 0 if the tap name is invalid.
607 lcp_validate_if_name (u8 *name)
613 len = clib_strnlen (p, IFNAMSIZ);
640 lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
642 int curr_ns_fd, vif_ns_fd;
647 curr_ns_fd = vif_ns_fd = -1;
649 if (lip->lip_namespace)
651 curr_ns_fd = clib_netns_open (NULL /* self */);
652 vif_ns_fd = clib_netns_open (lip->lip_namespace);
654 clib_setns (vif_ns_fd);
657 vnet_netlink_set_link_state (lip->lip_vif_index, state);
662 if (curr_ns_fd != -1)
664 clib_setns (curr_ns_fd);
676 u32 matched_sw_if_index;
680 lcp_itf_pair_find_walk (vnet_main_t *vnm, u32 sw_if_index, void *arg)
682 lcp_itf_match_t *match = arg;
683 const vnet_sw_interface_t *sw;
685 sw = vnet_get_sw_interface (vnm, sw_if_index);
686 if (sw && (sw->sub.eth.inner_vlan_id == 0) &&
687 (sw->sub.eth.outer_vlan_id == match->vlan) &&
688 (sw->sub.eth.flags.dot1ad == match->dot1ad))
690 LCP_ITF_PAIR_DBG ("find_walk: found match outer %d dot1ad %d "
691 "inner-dot1q %d: interface %U",
692 sw->sub.eth.outer_vlan_id, sw->sub.eth.flags.dot1ad,
693 sw->sub.eth.inner_vlan_id,
694 format_vnet_sw_if_index_name, vnet_get_main (),
696 match->matched_sw_if_index = sw->sw_if_index;
700 return WALK_CONTINUE;
703 /* Return the index of the sub-int on the phy that has the given vlan and
707 lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
709 lcp_itf_match_t match;
710 const vnet_hw_interface_t *hw;
713 match.dot1ad = dot1ad;
714 match.matched_sw_if_index = INDEX_INVALID;
715 hw = vnet_get_sup_hw_interface (vnet_get_main (), sup_if_index);
717 vnet_hw_interface_walk_sw (vnet_get_main (), hw->hw_if_index,
718 lcp_itf_pair_find_walk, &match);
720 if (match.matched_sw_if_index >= vec_len (lip_db_by_phy))
721 return INDEX_INVALID;
723 return lip_db_by_phy[match.matched_sw_if_index];
727 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
728 lip_host_type_t host_if_type, u8 *ns,
729 u32 *host_sw_if_indexp)
733 u32 vif_index = 0, host_sw_if_index;
734 const vnet_sw_interface_t *sw;
735 const vnet_hw_interface_t *hw;
736 const lcp_itf_pair_t *lip;
738 if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
740 LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
741 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
744 if (!lcp_validate_if_name (host_if_name))
746 LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
748 return VNET_API_ERROR_INVALID_ARGUMENT;
751 vnm = vnet_get_main ();
752 sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
753 hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
756 LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
757 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
761 * Use interface-specific netns if supplied.
762 * Otherwise, use netns if defined, otherwise use the OS default.
764 if (ns == 0 || ns[0] == 0)
765 ns = lcp_get_default_ns ();
767 /* sub interfaces do not need a tap created */
768 if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
770 index_t parent_if_index;
771 int orig_ns_fd, ns_fd;
773 u16 outer_vlan, inner_vlan;
774 u16 outer_proto, inner_proto;
776 u32 parent_vif_index;
778 // TODO(pim) replace with vnet_sw_interface_supports_addressing()
779 if (sw->type == VNET_SW_INTERFACE_TYPE_SUB &&
780 sw->sub.eth.flags.exact_match == 0)
782 LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
783 "sub-interface without exact-match set");
784 return VNET_API_ERROR_INVALID_ARGUMENT;
787 outer_vlan = sw->sub.eth.outer_vlan_id;
788 inner_vlan = sw->sub.eth.inner_vlan_id;
789 outer_proto = inner_proto = ETH_P_8021Q;
790 if (1 == sw->sub.eth.flags.dot1ad)
791 outer_proto = ETH_P_8021AD;
793 LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
794 sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
795 inner_vlan, format_vnet_sw_if_index_name, vnm,
798 parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
799 if (INDEX_INVALID == parent_if_index)
801 LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
802 format_vnet_sw_if_index_name, vnet_get_main (),
803 sw->sup_sw_if_index);
804 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
806 lip = lcp_itf_pair_get (parent_if_index);
809 LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
810 "sub-interface without an LCP on the parent");
811 return VNET_API_ERROR_INVALID_ARGUMENT;
813 LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
814 parent_vif_index = lip->lip_vif_index;
817 * see if the requested host interface has already been created
819 orig_ns_fd = ns_fd = -1;
822 if (ns && ns[0] != 0)
824 orig_ns_fd = clib_netns_open (NULL /* self */);
825 ns_fd = clib_netns_open (ns);
826 if (orig_ns_fd == -1 || ns_fd == -1)
832 vif_index = if_nametoindex ((const char *) host_if_name);
837 * no existing host interface, create it now
841 * Find the parent tap:
842 * - if this is an outer VLAN, use the pair from the parent phy
843 * - if this is an inner VLAN, find the pair from the outer sub-int,
848 index_t linux_parent_if_index;
849 const lcp_itf_pair_t *llip;
853 linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
854 hw->sw_if_index, sw->sub.eth.outer_vlan_id,
855 sw->sub.eth.flags.dot1ad);
856 if (INDEX_INVALID == linux_parent_if_index ||
857 !(llip = lcp_itf_pair_get (linux_parent_if_index)))
860 "pair_create: can't find LCP for outer vlan %d "
863 outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
864 format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
865 err = clib_error_return (0, "parent pair not found");
869 LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
870 format_lcp_itf_pair, llip);
871 parent_vif_index = llip->lip_vif_index;
879 err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
880 (const char *) host_if_name);
883 LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
884 "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
885 "04x,vlan:%u) name:'%s'",
886 outer_proto, outer_vlan, inner_proto,
887 inner_vlan, host_if_name);
891 vif_index = if_nametoindex ((char *) host_if_name);
895 * create a sub-interface on the tap
898 vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
899 sw->sub.eth.raw_flags, inner_vlan,
900 outer_vlan, &host_sw_if_index))
903 "pair_create: failed to create tap subint: %d.%d on %U",
904 outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
905 lip->lip_host_sw_if_index);
906 err = clib_error_return (
907 0, "failed to create tap subinti: %d.%d. on %U", outer_vlan,
908 inner_vlan, format_vnet_sw_if_index_name, vnm,
909 lip->lip_host_sw_if_index);
913 if (orig_ns_fd != -1)
915 clib_setns (orig_ns_fd);
922 return VNET_API_ERROR_INVALID_ARGUMENT;
926 tap_create_if_args_t args = {
927 .num_rx_queues = clib_max (1, vlib_num_workers ()),
928 .id = hw->hw_if_index,
932 .host_if_name = host_if_name,
935 ethernet_interface_t *ei;
937 if (host_if_type == LCP_ITF_HOST_TUN)
938 args.tap_flags |= TAP_FLAG_TUN;
941 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
942 mac_address_copy (&args.host_mac_addr, &ei->address.mac);
945 if (sw->mtu[VNET_MTU_L3])
947 args.host_mtu_set = 1;
948 args.host_mtu_size = sw->mtu[VNET_MTU_L3];
951 if (ns && ns[0] != 0)
952 args.host_namespace = ns;
954 vm = vlib_get_main ();
955 tap_create_if (vm, &args);
959 LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
965 * The TAP interface does copy forward the host MTU based on the VPP
966 * interface's L3 MTU, but it should also ensure that the VPP tap
967 * interface has an MTU that is greater-or-equal to those. Considering
968 * users can set the interfaces at runtime (set interface mtu packet ...)
969 * ensure that the tap MTU is large enough, taking the VPP interface L3
970 * if it's set, and otherwise a sensible default.
972 if (sw->mtu[VNET_MTU_L3])
973 vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
974 sw->mtu[VNET_MTU_L3]);
976 vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
977 ETHERNET_MAX_PACKET_BYTES);
980 * get the hw and ethernet of the tap
982 hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
983 virtio_main_t *mm = &virtio_main;
984 virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
987 * Leave the TAP permanently up on the VPP side.
988 * This TAP will be shared by many sub-interface.
989 * Therefore we can't use it to manage admin state.
990 * force the tap in promiscuous mode.
992 if (host_if_type == LCP_ITF_HOST_TAP)
994 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
995 ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
998 vif_index = vif->ifindex;
999 host_sw_if_index = args.sw_if_index;
1004 LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
1005 format_vnet_sw_if_index_name, vnet_get_main (),
1006 phy_sw_if_index, format_vnet_sw_if_index_name,
1007 vnet_get_main (), host_sw_if_index, host_if_name);
1011 LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
1012 vnet_get_main (), phy_sw_if_index,
1013 format_vnet_sw_if_index_name, vnet_get_main (),
1014 host_sw_if_index, host_if_name);
1015 lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
1019 * Copy the link state from VPP into the host side.
1020 * The TAP is shared by many interfaces, always keep it up.
1021 * This controls whether the host can RX/TX.
1024 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
1025 LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
1026 format_lcp_itf_pair, lip, sw->flags, hw->flags);
1027 vnet_sw_interface_admin_up (vnm, host_sw_if_index);
1028 lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1030 if (host_sw_if_indexp)
1031 *host_sw_if_indexp = host_sw_if_index;
1037 lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
1039 lcp_itf_pair_t *lip;
1041 lip = lcp_itf_pair_get (lipi);
1043 lip->lip_flags |= LIP_FLAG_STALE;
1045 return (WALK_CONTINUE);
1049 lcp_itf_pair_replace_begin (void)
1051 lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
1056 typedef struct lcp_itf_pair_sweep_ctx_t_
1059 } lcp_itf_pair_sweep_ctx_t;
1062 lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
1064 lcp_itf_pair_sweep_ctx_t *ctx = arg;
1065 lcp_itf_pair_t *lip;
1067 lip = lcp_itf_pair_get (lipi);
1069 if (lip->lip_flags & LIP_FLAG_STALE)
1070 vec_add1 (ctx->indicies, lipi);
1072 return (WALK_CONTINUE);
1076 lcp_itf_pair_replace_end (void)
1078 lcp_itf_pair_sweep_ctx_t ctx = {
1083 lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
1085 vec_foreach (lipi, ctx.indicies)
1086 lcp_itf_pair_delete_by_index (*lipi);
1088 vec_free (ctx.indicies);
1093 lcp_itf_pair_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
1096 uword *event_data = 0;
1101 vlib_process_wait_for_event (vm);
1103 vlib_process_get_events (vm, &event_data);
1105 vec_foreach (lipn_index, event_data)
1107 lcp_itf_pair_names_t *lipn;
1109 lipn = &lipn_names[*lipn_index];
1110 lcp_itf_pair_create (lipn->lipn_phy_sw_if_index,
1111 lipn->lipn_host_name, LCP_ITF_HOST_TAP,
1112 lipn->lipn_namespace, NULL);
1115 vec_reset_length (event_data);
1121 VLIB_REGISTER_NODE (lcp_itf_pair_process_node, static) = {
1122 .function = lcp_itf_pair_process,
1123 .name = "linux-cp-itf-process",
1124 .type = VLIB_NODE_TYPE_PROCESS,
1127 static clib_error_t *
1128 lcp_itf_phy_add (vnet_main_t *vnm, u32 sw_if_index, u32 is_create)
1130 lcp_itf_pair_names_t *lipn;
1131 vlib_main_t *vm = vlib_get_main ();
1132 vnet_hw_interface_t *hw;
1134 if (!is_create || vnet_sw_interface_is_sub (vnm, sw_if_index))
1137 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1139 vec_foreach (lipn, lipn_names)
1141 if (!vec_cmp (hw->name, lipn->lipn_phy_name))
1143 lipn->lipn_phy_sw_if_index = sw_if_index;
1145 vlib_process_signal_event (vm, lcp_itf_pair_process_node.index, 0,
1154 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_phy_add);
1156 static clib_error_t *
1157 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1159 vnet_hw_interface_t *hi;
1160 vnet_sw_interface_t *si;
1162 lcp_itf_pair_t *lip;
1164 hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
1168 lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
1169 if (lipi == INDEX_INVALID)
1172 lip = lcp_itf_pair_get (lipi);
1173 si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
1177 if (!lcp_main.test_mode)
1179 tap_set_carrier (si->hw_if_index,
1180 (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
1182 if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1184 tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1191 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1193 static clib_error_t *
1194 lcp_itf_pair_init (vlib_main_t *vm)
1196 vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1199 vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1202 /* punt all unknown ports */
1203 udp_punt_unknown (vm, 0, 1);
1204 udp_punt_unknown (vm, 1, 1);
1205 tcp_punt_unknown (vm, 0, 1);
1206 tcp_punt_unknown (vm, 1, 1);
1208 lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1213 VLIB_INIT_FUNCTION (lcp_itf_pair_init) = {
1214 .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1218 * fd.io coding-style-patch-verification: ON
1221 * eval: (c-set-style "gnu")