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 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);
77 format_lcp_itf_pair (u8 *s, va_list *args)
79 vnet_main_t *vnm = vnet_get_main ();
80 lcp_itf_pair_t *lip = va_arg (*args, lcp_itf_pair_t *);
81 vnet_sw_interface_t *swif_phy;
82 vnet_sw_interface_t *swif_host;
84 s = format (s, "itf-pair: [%d]", lip - lcp_itf_pair_pool);
86 swif_phy = vnet_get_sw_interface_or_null (vnm, lip->lip_phy_sw_if_index);
88 s = format (s, " <no-phy-if>");
90 s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_phy);
92 swif_host = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
94 s = format (s, " <no-host-if>");
96 s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_host);
98 s = format (s, " %v %d type %s", lip->lip_host_name, lip->lip_vif_index,
99 (lip->lip_host_type == LCP_ITF_HOST_TAP) ? "tap" : "tun");
101 if (lip->lip_namespace)
102 s = format (s, " netns %s", lip->lip_namespace);
108 lcp_itf_pair_walk_show_cb (index_t api, void *ctx)
113 lip = lcp_itf_pair_get (api);
117 vm = vlib_get_main ();
118 vlib_cli_output (vm, "%U\n", format_lcp_itf_pair, lip);
120 return WALK_CONTINUE;
124 lcp_itf_pair_show (u32 phy_sw_if_index)
130 vm = vlib_get_main ();
131 ns = lcp_get_default_ns ();
132 vlib_cli_output (vm, "lcp default netns '%s'\n",
133 ns ? (char *) ns : "<unset>");
134 vlib_cli_output (vm, "lcp lcp-auto-subint %s\n",
135 lcp_auto_subint () ? "on" : "off");
136 vlib_cli_output (vm, "lcp lcp-sync %s\n", lcp_sync () ? "on" : "off");
138 if (phy_sw_if_index == ~0)
140 lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
144 api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
145 if (api != INDEX_INVALID)
146 lcp_itf_pair_walk_show_cb (api, 0);
151 lcp_itf_pair_get (u32 index)
153 if (!lcp_itf_pair_pool)
155 if (index == INDEX_INVALID)
158 return pool_elt_at_index (lcp_itf_pair_pool, index);
162 lcp_itf_pair_find_by_vif (u32 vif_index)
166 p = hash_get (lip_db_by_vif, vif_index);
171 return INDEX_INVALID;
174 const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
175 [LCP_ITF_HOST_TAP] = {
176 [AF_IP4] = "linux-cp-xc-ip4",
177 [AF_IP6] = "linux-cp-xc-ip6",
179 [LCP_ITF_HOST_TUN] = {
180 [AF_IP4] = "linux-cp-xc-l3-ip4",
181 [AF_IP6] = "linux-cp-xc-l3-ip6",
185 const fib_route_path_flags_t lcp_itf_route_path_flags[N_LCP_ITF_HOST] = {
186 [LCP_ITF_HOST_TAP] = FIB_ROUTE_PATH_DVR,
187 [LCP_ITF_HOST_TUN] = FIB_ROUTE_PATH_FLAG_NONE,
191 lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
193 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
194 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
198 lcp_itf_set_adjs (lcp_itf_pair_t *lip)
200 if (lip->lip_host_type == LCP_ITF_HOST_TUN)
202 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_nbr_add_or_lock (
203 FIB_PROTOCOL_IP4, VNET_LINK_IP4, &zero_addr, lip->lip_phy_sw_if_index);
204 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_nbr_add_or_lock (
205 FIB_PROTOCOL_IP6, VNET_LINK_IP6, &zero_addr, lip->lip_phy_sw_if_index);
209 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_mcast_add_or_lock (
210 FIB_PROTOCOL_IP4, VNET_LINK_IP4, lip->lip_phy_sw_if_index);
211 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_mcast_add_or_lock (
212 FIB_PROTOCOL_IP6, VNET_LINK_IP6, lip->lip_phy_sw_if_index);
217 adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
219 lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
223 lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
224 u32 host_index, lip_host_type_t host_type, u8 *ns)
229 if (host_sw_if_index == ~0)
231 LCP_ITF_PAIR_ERR ("pair_add: Cannot add LIP - invalid host");
232 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
235 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
237 if (lipi != INDEX_INVALID)
238 return VNET_API_ERROR_VALUE_EXIST;
240 LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%s",
241 format_vnet_sw_if_index_name, vnet_get_main (),
242 host_sw_if_index, format_vnet_sw_if_index_name,
243 vnet_get_main (), phy_sw_if_index, host_name, host_index,
249 pool_get (lcp_itf_pair_pool, lip);
251 lipi = lip - lcp_itf_pair_pool;
253 vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
254 vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
255 lip_db_by_phy[phy_sw_if_index] = lipi;
256 lip_db_by_host[host_sw_if_index] = lipi;
257 hash_set (lip_db_by_vif, host_index, lipi);
259 lip->lip_host_sw_if_index = host_sw_if_index;
260 lip->lip_phy_sw_if_index = phy_sw_if_index;
261 lip->lip_host_name = vec_dup (host_name);
262 lip->lip_host_type = host_type;
263 lip->lip_vif_index = host_index;
264 lip->lip_namespace = vec_dup (ns);
267 * First use of this host interface.
268 * Enable the x-connect feature on the host to send
269 * all packets to the phy.
271 ip_address_family_t af;
273 FOR_EACH_IP_ADDRESS_FAMILY (af)
274 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
275 lcp_itf_l3_feat_names[lip->lip_host_type][af],
276 lip->lip_host_sw_if_index, 1, NULL, 0);
279 * Configure passive punt to the host interface.
281 fib_route_path_t *rpaths = NULL, rpath = {
282 .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
283 .frp_proto = DPO_PROTO_IP4,
284 .frp_sw_if_index = lip->lip_host_sw_if_index,
289 vec_add1 (rpaths, rpath);
291 ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
293 rpaths[0].frp_proto = DPO_PROTO_IP6;
295 ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
299 lcp_itf_set_adjs (lip);
301 /* enable ARP feature node for broadcast interfaces */
302 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
304 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
305 lip->lip_phy_sw_if_index, 1, NULL, 0);
306 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
307 lip->lip_host_sw_if_index, 1, NULL, 0);
311 if (hash_elts (lip_db_by_vif) == 1)
313 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1,
315 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1,
320 /* invoke registered callbacks for pair addition */
321 lcp_itf_pair_vft_t *vft;
323 vec_foreach (vft, lcp_itf_vfts)
325 if (vft->pair_add_fn)
326 vft->pair_add_fn (lip);
329 /* set timestamp when pair entered service */
330 lip->lip_create_ts = vlib_time_now (vlib_get_main ());
335 static clib_error_t *
336 lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name)
338 struct rtnl_link *link;
342 sk = nl_socket_alloc ();
343 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
345 LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: connect error: %s",
347 return clib_error_return (NULL, "Unable to connect socket: %d", err);
350 link = rtnl_link_vlan_alloc ();
352 rtnl_link_set_link (link, parent);
353 rtnl_link_set_name (link, name);
354 rtnl_link_vlan_set_id (link, vlan);
355 rtnl_link_vlan_set_protocol (link, htons (proto));
357 if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
359 LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: link add error: %s",
361 return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
364 rtnl_link_put (link);
370 static clib_error_t *
371 lcp_netlink_del_link (const char *name)
373 struct rtnl_link *link;
377 sk = nl_socket_alloc ();
378 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
379 return clib_error_return (NULL, "Unable to connect socket: %d", err);
381 link = rtnl_link_alloc ();
382 rtnl_link_set_name (link, name);
384 if ((err = rtnl_link_delete (sk, link)) < 0)
385 return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
387 rtnl_link_put (link);
394 lcp_itf_pair_del (u32 phy_sw_if_index)
396 ip_address_family_t af;
399 lcp_itf_pair_vft_t *vft;
401 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
403 if (lipi == INDEX_INVALID)
404 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
406 lip = lcp_itf_pair_get (lipi);
408 LCP_ITF_PAIR_NOTICE (
409 "pair_del: host:%U phy:%U host_if:%s vif:%d ns:%s",
410 format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_host_sw_if_index,
411 format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_phy_sw_if_index,
412 lip->lip_host_name, lip->lip_vif_index, lip->lip_namespace);
414 /* invoke registered callbacks for pair deletion */
415 vec_foreach (vft, lcp_itf_vfts)
417 if (vft->pair_del_fn)
418 vft->pair_del_fn (lip);
421 FOR_EACH_IP_ADDRESS_FAMILY (af)
422 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
423 lcp_itf_l3_feat_names[lip->lip_host_type][af],
424 lip->lip_host_sw_if_index, 0, NULL, 0);
426 lcp_itf_unset_adjs (lip);
428 ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
429 ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
431 /* disable ARP feature node for broadcast interfaces */
432 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
434 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
435 lip->lip_phy_sw_if_index, 0, NULL, 0);
436 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
437 lip->lip_host_sw_if_index, 0, NULL, 0);
441 if (hash_elts (lip_db_by_vif) == 1)
443 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0,
445 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0,
449 lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
450 lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
451 hash_unset (lip_db_by_vif, lip->lip_vif_index);
453 vec_free (lip->lip_host_name);
454 vec_free (lip->lip_namespace);
455 pool_put (lcp_itf_pair_pool, lip);
461 lcp_itf_pair_delete_by_index (index_t lipi)
463 u32 host_sw_if_index;
467 lip = lcp_itf_pair_get (lipi);
469 host_name = vec_dup (lip->lip_host_name);
470 host_sw_if_index = lip->lip_host_sw_if_index;
471 ns = vec_dup (lip->lip_namespace);
473 lcp_itf_pair_del (lip->lip_phy_sw_if_index);
475 if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
481 curr_ns_fd = clib_netns_open (NULL /* self */);
482 vif_ns_fd = clib_netns_open ((u8 *) ns);
484 clib_setns (vif_ns_fd);
487 lcp_netlink_del_link ((const char *) host_name);
491 if (curr_ns_fd != -1)
493 clib_setns (curr_ns_fd);
497 vnet_delete_sub_interface (host_sw_if_index);
500 tap_delete_if (vlib_get_main (), host_sw_if_index);
502 vec_free (host_name);
507 lcp_itf_pair_delete (u32 phy_sw_if_index)
511 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
513 if (lipi == INDEX_INVALID)
514 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
516 lcp_itf_pair_delete_by_index (lipi);
522 * lcp_itf_interface_add_del
524 * Registered to receive interface Add and delete notifications
526 static clib_error_t *
527 lcp_itf_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
530 /* remove any interface pair we have for this interface */
531 lcp_itf_pair_delete (sw_if_index);
536 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_interface_add_del);
539 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
543 pool_foreach_index (api, lcp_itf_pair_pool)
550 static clib_error_t *
551 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
557 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
559 if (unformat (input, "default netns %v", &default_ns))
561 vec_add1 (default_ns, 0);
562 if (lcp_set_default_ns (default_ns) < 0)
564 return clib_error_return (0,
565 "linux-cp default namespace must"
566 " be less than %d characters",
570 else if (unformat (input, "lcp-auto-subint"))
571 lcp_set_auto_subint (1 /* is_auto */);
572 else if (unformat (input, "lcp-sync"))
573 lcp_set_sync (1 /* is_auto */);
575 return clib_error_return (0, "interfaces not found");
578 vec_free (default_ns);
583 VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
586 * Returns 1 if the tap name is valid.
587 * Returns 0 if the tap name is invalid.
590 lcp_validate_if_name (u8 *name)
596 len = clib_strnlen (p, IFNAMSIZ);
623 lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
625 int curr_ns_fd, vif_ns_fd;
630 curr_ns_fd = vif_ns_fd = -1;
632 if (lip->lip_namespace)
634 curr_ns_fd = clib_netns_open (NULL /* self */);
635 vif_ns_fd = clib_netns_open (lip->lip_namespace);
637 clib_setns (vif_ns_fd);
640 /* Set the same link state on the netlink interface
642 vnet_netlink_set_link_state (lip->lip_vif_index, state);
647 if (curr_ns_fd != -1)
649 clib_setns (curr_ns_fd);
657 lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip)
659 ip4_main_t *im4 = &ip4_main;
660 ip6_main_t *im6 = &ip6_main;
661 ip_lookup_main_t *lm4 = &im4->lookup_main;
662 ip_lookup_main_t *lm6 = &im6->lookup_main;
663 ip_interface_address_t *ia = 0;
670 if (lip->lip_namespace)
672 curr_ns_fd = clib_netns_open (NULL /* self */);
673 vif_ns_fd = clib_netns_open (lip->lip_namespace);
675 clib_setns (vif_ns_fd);
678 /* Sync any IP4 addressing info into LCP */
679 foreach_ip_interface_address (
680 lm4, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
681 ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia);
682 LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip4 %U/%d",
683 format_lcp_itf_pair, lip, format_ip4_address, r4,
685 vnet_netlink_add_ip4_addr (lip->lip_vif_index, r4, ia->address_length);
688 /* Sync any IP6 addressing info into LCP */
689 foreach_ip_interface_address (
690 lm6, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
691 ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia);
692 LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip6 %U/%d",
693 format_lcp_itf_pair, lip, format_ip6_address, r6,
695 vnet_netlink_add_ip6_addr (lip->lip_vif_index, r6, ia->address_length);
701 if (curr_ns_fd != -1)
703 clib_setns (curr_ns_fd);
713 u32 matched_sw_if_index;
717 lcp_itf_pair_find_walk (vnet_main_t *vnm, u32 sw_if_index, void *arg)
719 lcp_itf_match_t *match = arg;
720 const vnet_sw_interface_t *sw;
722 sw = vnet_get_sw_interface (vnm, sw_if_index);
723 if (sw && (sw->sub.eth.inner_vlan_id == 0) &&
724 (sw->sub.eth.outer_vlan_id == match->vlan) &&
725 (sw->sub.eth.flags.dot1ad == match->dot1ad))
727 LCP_ITF_PAIR_DBG ("find_walk: found match outer %d dot1ad %d "
728 "inner-dot1q %d: interface %U",
729 sw->sub.eth.outer_vlan_id, sw->sub.eth.flags.dot1ad,
730 sw->sub.eth.inner_vlan_id,
731 format_vnet_sw_if_index_name, vnet_get_main (),
733 match->matched_sw_if_index = sw->sw_if_index;
737 return WALK_CONTINUE;
740 /* Return the index of the sub-int on the phy that has the given vlan and
744 lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
746 lcp_itf_match_t match;
747 const vnet_hw_interface_t *hw;
750 match.dot1ad = dot1ad;
751 match.matched_sw_if_index = INDEX_INVALID;
752 hw = vnet_get_sup_hw_interface (vnet_get_main (), sup_if_index);
754 vnet_hw_interface_walk_sw (vnet_get_main (), hw->hw_if_index,
755 lcp_itf_pair_find_walk, &match);
757 if (match.matched_sw_if_index >= vec_len (lip_db_by_phy))
758 return INDEX_INVALID;
760 return lip_db_by_phy[match.matched_sw_if_index];
763 static clib_error_t *lcp_itf_pair_link_up_down (vnet_main_t *vnm,
764 u32 hw_if_index, u32 flags);
767 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
768 lip_host_type_t host_if_type, u8 *ns,
769 u32 *host_sw_if_indexp)
773 u32 vif_index = 0, host_sw_if_index;
774 const vnet_sw_interface_t *sw;
775 const vnet_hw_interface_t *hw;
776 const lcp_itf_pair_t *lip;
778 if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
780 LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
781 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
784 if (!lcp_validate_if_name (host_if_name))
786 LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
788 return VNET_API_ERROR_INVALID_ARGUMENT;
791 vnm = vnet_get_main ();
792 sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
793 hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
796 LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
797 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
801 * Use interface-specific netns if supplied.
802 * Otherwise, use netns if defined, otherwise use the OS default.
804 if (ns == 0 || ns[0] == 0)
805 ns = lcp_get_default_ns ();
807 /* sub interfaces do not need a tap created */
808 if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
810 index_t parent_if_index;
811 int orig_ns_fd, ns_fd;
813 u16 outer_vlan, inner_vlan;
814 u16 outer_proto, inner_proto;
816 u32 parent_vif_index;
818 err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index);
821 LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
822 "sub-interface without exact-match set");
823 return VNET_API_ERROR_INVALID_ARGUMENT;
826 outer_vlan = sw->sub.eth.outer_vlan_id;
827 inner_vlan = sw->sub.eth.inner_vlan_id;
828 outer_proto = inner_proto = ETH_P_8021Q;
829 if (1 == sw->sub.eth.flags.dot1ad)
830 outer_proto = ETH_P_8021AD;
832 LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
833 sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
834 inner_vlan, format_vnet_sw_if_index_name, vnm,
837 parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
838 if (INDEX_INVALID == parent_if_index)
840 LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
841 format_vnet_sw_if_index_name, vnet_get_main (),
842 sw->sup_sw_if_index);
843 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
845 lip = lcp_itf_pair_get (parent_if_index);
848 LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
849 "sub-interface without an LCP on the parent");
850 return VNET_API_ERROR_INVALID_ARGUMENT;
852 LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
853 parent_vif_index = lip->lip_vif_index;
856 * see if the requested host interface has already been created
858 orig_ns_fd = ns_fd = -1;
861 if (ns && ns[0] != 0)
863 orig_ns_fd = clib_netns_open (NULL /* self */);
864 ns_fd = clib_netns_open (ns);
865 if (orig_ns_fd == -1 || ns_fd == -1)
871 vif_index = if_nametoindex ((const char *) host_if_name);
876 * no existing host interface, create it now
880 * Find the parent tap:
881 * - if this is an outer VLAN, use the pair from the parent phy
882 * - if this is an inner VLAN, find the pair from the outer sub-int,
887 index_t linux_parent_if_index;
888 const lcp_itf_pair_t *llip;
892 linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
893 hw->sw_if_index, sw->sub.eth.outer_vlan_id,
894 sw->sub.eth.flags.dot1ad);
895 if (INDEX_INVALID == linux_parent_if_index ||
896 !(llip = lcp_itf_pair_get (linux_parent_if_index)))
899 "pair_create: can't find LCP for outer vlan %d "
902 outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
903 format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
904 err = clib_error_return (0, "parent pair not found");
908 LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
909 format_lcp_itf_pair, llip);
910 parent_vif_index = llip->lip_vif_index;
918 err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
919 (const char *) host_if_name);
922 LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
923 "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
924 "04x,vlan:%u) name:'%s'",
925 outer_proto, outer_vlan, inner_proto,
926 inner_vlan, host_if_name);
930 vif_index = if_nametoindex ((char *) host_if_name);
934 * create a sub-interface on the tap
937 vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
938 sw->sub.eth.raw_flags, inner_vlan,
939 outer_vlan, &host_sw_if_index))
942 "pair_create: failed to create tap subint: %d.%d on %U",
943 outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
944 lip->lip_host_sw_if_index);
945 err = clib_error_return (
946 0, "failed to create tap subint: %d.%d. on %U", outer_vlan,
947 inner_vlan, format_vnet_sw_if_index_name, vnm,
948 lip->lip_host_sw_if_index);
952 if (orig_ns_fd != -1)
954 clib_setns (orig_ns_fd);
961 return VNET_API_ERROR_INVALID_ARGUMENT;
965 tap_create_if_args_t args = {
966 .num_rx_queues = clib_max (1, vlib_num_workers ()),
968 .id = hw->hw_if_index,
972 .host_if_name = host_if_name,
975 ethernet_interface_t *ei;
977 if (host_if_type == LCP_ITF_HOST_TUN)
978 args.tap_flags |= TAP_FLAG_TUN;
981 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
982 mac_address_copy (&args.host_mac_addr, &ei->address.mac);
985 if (sw->mtu[VNET_MTU_L3])
987 args.host_mtu_set = 1;
988 args.host_mtu_size = sw->mtu[VNET_MTU_L3];
991 if (ns && ns[0] != 0)
992 args.host_namespace = ns;
994 vm = vlib_get_main ();
995 tap_create_if (vm, &args);
999 LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
1005 * The TAP interface does copy forward the host MTU based on the VPP
1006 * interface's L3 MTU, but it should also ensure that the VPP tap
1007 * interface has an MTU that is greater-or-equal to those. Considering
1008 * users can set the interfaces at runtime (set interface mtu packet ...)
1009 * ensure that the tap MTU is large enough, taking the VPP interface L3
1010 * if it's set, and otherwise a sensible default.
1012 if (sw->mtu[VNET_MTU_L3])
1013 vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
1014 sw->mtu[VNET_MTU_L3]);
1016 vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
1017 ETHERNET_MAX_PACKET_BYTES);
1020 * get the hw and ethernet of the tap
1022 hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
1023 virtio_main_t *mm = &virtio_main;
1024 virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1027 * Leave the TAP permanently up on the VPP side.
1028 * This TAP will be shared by many sub-interface.
1029 * Therefore we can't use it to manage admin state.
1030 * force the tap in promiscuous mode.
1032 if (host_if_type == LCP_ITF_HOST_TAP)
1034 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
1035 ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
1038 vif_index = vif->ifindex;
1039 host_sw_if_index = args.sw_if_index;
1044 LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
1045 format_vnet_sw_if_index_name, vnet_get_main (),
1046 phy_sw_if_index, format_vnet_sw_if_index_name,
1047 vnet_get_main (), host_sw_if_index, host_if_name);
1051 LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
1052 vnet_get_main (), phy_sw_if_index,
1053 format_vnet_sw_if_index_name, vnet_get_main (),
1054 host_sw_if_index, host_if_name);
1055 lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
1059 * Copy the link state from VPP into the host side.
1060 * The TAP is shared by many interfaces, always keep it up.
1061 * This controls whether the host can RX/TX.
1064 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
1065 LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
1066 format_lcp_itf_pair, lip, sw->flags, hw->flags);
1067 vnet_sw_interface_admin_up (vnm, host_sw_if_index);
1068 lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1071 * Reflect current link state and link speed of the hardware interface on the
1074 if (host_if_type == LCP_ITF_HOST_TAP &&
1075 !vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
1077 hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
1078 lcp_itf_pair_link_up_down (vnm, hw->hw_if_index, hw->flags);
1081 if (host_sw_if_indexp)
1082 *host_sw_if_indexp = host_sw_if_index;
1088 lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
1090 lcp_itf_pair_t *lip;
1092 lip = lcp_itf_pair_get (lipi);
1094 lip->lip_flags |= LIP_FLAG_STALE;
1096 return (WALK_CONTINUE);
1100 lcp_itf_pair_replace_begin (void)
1102 lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
1107 typedef struct lcp_itf_pair_sweep_ctx_t_
1110 } lcp_itf_pair_sweep_ctx_t;
1113 lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
1115 lcp_itf_pair_sweep_ctx_t *ctx = arg;
1116 lcp_itf_pair_t *lip;
1118 lip = lcp_itf_pair_get (lipi);
1120 if (lip->lip_flags & LIP_FLAG_STALE)
1121 vec_add1 (ctx->indicies, lipi);
1123 return (WALK_CONTINUE);
1127 lcp_itf_pair_replace_end (void)
1129 lcp_itf_pair_sweep_ctx_t ctx = {
1134 lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
1136 vec_foreach (lipi, ctx.indicies)
1137 lcp_itf_pair_delete_by_index (*lipi);
1139 vec_free (ctx.indicies);
1143 static clib_error_t *
1144 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1146 vnet_hw_interface_t *hi;
1147 vnet_sw_interface_t *si;
1149 lcp_itf_pair_t *lip;
1151 hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
1155 lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
1156 if (lipi == INDEX_INVALID)
1159 lip = lcp_itf_pair_get (lipi);
1160 si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
1164 if (!lcp_main.test_mode)
1166 tap_set_carrier (si->hw_if_index,
1167 (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
1169 if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1171 tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1178 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1180 static clib_error_t *
1181 lcp_interface_init (vlib_main_t *vm)
1183 vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1186 vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1189 /* punt all unknown ports */
1190 udp_punt_unknown (vm, 0, 1);
1191 udp_punt_unknown (vm, 1, 1);
1192 tcp_punt_unknown (vm, 0, 1);
1193 tcp_punt_unknown (vm, 1, 1);
1195 lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1200 VLIB_INIT_FUNCTION (lcp_interface_init) = {
1201 .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1205 * fd.io coding-style-patch-verification: ON
1208 * eval: (c-set-style "gnu")