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");
137 vlib_cli_output (vm, "lcp del-static-on-link-down %s\n",
138 lcp_get_del_static_on_link_down () ? "on" : "off");
139 vlib_cli_output (vm, "lcp del-dynamic-on-link-down %s\n",
140 lcp_get_del_dynamic_on_link_down () ? "on" : "off");
142 if (phy_sw_if_index == ~0)
144 lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
148 api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
149 if (api != INDEX_INVALID)
150 lcp_itf_pair_walk_show_cb (api, 0);
155 lcp_itf_pair_get (u32 index)
157 if (!lcp_itf_pair_pool)
159 if (index == INDEX_INVALID)
162 return pool_elt_at_index (lcp_itf_pair_pool, index);
166 lcp_itf_pair_find_by_vif (u32 vif_index)
170 p = hash_get (lip_db_by_vif, vif_index);
175 return INDEX_INVALID;
178 const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
179 [LCP_ITF_HOST_TAP] = {
180 [AF_IP4] = "linux-cp-xc-ip4",
181 [AF_IP6] = "linux-cp-xc-ip6",
183 [LCP_ITF_HOST_TUN] = {
184 [AF_IP4] = "linux-cp-xc-l3-ip4",
185 [AF_IP6] = "linux-cp-xc-l3-ip6",
189 const fib_route_path_flags_t lcp_itf_route_path_flags[N_LCP_ITF_HOST] = {
190 [LCP_ITF_HOST_TAP] = FIB_ROUTE_PATH_DVR,
191 [LCP_ITF_HOST_TUN] = FIB_ROUTE_PATH_FLAG_NONE,
195 lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
197 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
198 adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
202 lcp_itf_set_adjs (lcp_itf_pair_t *lip)
204 if (lip->lip_host_type == LCP_ITF_HOST_TUN)
206 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_nbr_add_or_lock (
207 FIB_PROTOCOL_IP4, VNET_LINK_IP4, &zero_addr, lip->lip_phy_sw_if_index);
208 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_nbr_add_or_lock (
209 FIB_PROTOCOL_IP6, VNET_LINK_IP6, &zero_addr, lip->lip_phy_sw_if_index);
213 lip->lip_phy_adjs.adj_index[AF_IP4] = adj_mcast_add_or_lock (
214 FIB_PROTOCOL_IP4, VNET_LINK_IP4, lip->lip_phy_sw_if_index);
215 lip->lip_phy_adjs.adj_index[AF_IP6] = adj_mcast_add_or_lock (
216 FIB_PROTOCOL_IP6, VNET_LINK_IP6, lip->lip_phy_sw_if_index);
221 adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
223 lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
227 lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
228 u32 host_index, lip_host_type_t host_type, u8 *ns)
233 if (host_sw_if_index == ~0)
235 LCP_ITF_PAIR_ERR ("pair_add: Cannot add LIP - invalid host");
236 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
239 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
241 if (lipi != INDEX_INVALID)
242 return VNET_API_ERROR_VALUE_EXIST;
244 LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%s",
245 format_vnet_sw_if_index_name, vnet_get_main (),
246 host_sw_if_index, format_vnet_sw_if_index_name,
247 vnet_get_main (), phy_sw_if_index, host_name, host_index,
253 pool_get (lcp_itf_pair_pool, lip);
255 lipi = lip - lcp_itf_pair_pool;
257 vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
258 vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
259 lip_db_by_phy[phy_sw_if_index] = lipi;
260 lip_db_by_host[host_sw_if_index] = lipi;
261 hash_set (lip_db_by_vif, host_index, lipi);
263 lip->lip_host_sw_if_index = host_sw_if_index;
264 lip->lip_phy_sw_if_index = phy_sw_if_index;
265 lip->lip_host_name = vec_dup (host_name);
266 lip->lip_host_type = host_type;
267 lip->lip_vif_index = host_index;
268 lip->lip_namespace = vec_dup (ns);
271 * First use of this host interface.
272 * Enable the x-connect feature on the host to send
273 * all packets to the phy.
275 ip_address_family_t af;
277 FOR_EACH_IP_ADDRESS_FAMILY (af)
278 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
279 lcp_itf_l3_feat_names[lip->lip_host_type][af],
280 lip->lip_host_sw_if_index, 1, NULL, 0);
283 * Configure passive punt to the host interface.
285 fib_route_path_t *rpaths = NULL, rpath = {
286 .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
287 .frp_proto = DPO_PROTO_IP4,
288 .frp_sw_if_index = lip->lip_host_sw_if_index,
293 vec_add1 (rpaths, rpath);
295 ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
297 rpaths[0].frp_proto = DPO_PROTO_IP6;
299 ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
303 lcp_itf_set_adjs (lip);
305 /* enable ARP feature node for broadcast interfaces */
306 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
308 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
309 lip->lip_phy_sw_if_index, 1, NULL, 0);
310 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
311 lip->lip_host_sw_if_index, 1, NULL, 0);
315 if (hash_elts (lip_db_by_vif) == 1)
317 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1,
319 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1,
324 /* invoke registered callbacks for pair addition */
325 lcp_itf_pair_vft_t *vft;
327 vec_foreach (vft, lcp_itf_vfts)
329 if (vft->pair_add_fn)
330 vft->pair_add_fn (lip);
333 /* set timestamp when pair entered service */
334 lip->lip_create_ts = vlib_time_now (vlib_get_main ());
339 static clib_error_t *
340 lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name)
342 struct rtnl_link *link;
346 sk = nl_socket_alloc ();
347 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
349 LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: connect error: %s",
351 return clib_error_return (NULL, "Unable to connect socket: %d", err);
354 link = rtnl_link_vlan_alloc ();
356 rtnl_link_set_link (link, parent);
357 rtnl_link_set_name (link, name);
358 rtnl_link_vlan_set_id (link, vlan);
359 rtnl_link_vlan_set_protocol (link, htons (proto));
361 if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
363 LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: link add error: %s",
365 return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
368 rtnl_link_put (link);
374 static clib_error_t *
375 lcp_netlink_del_link (const char *name)
377 struct rtnl_link *link;
381 sk = nl_socket_alloc ();
382 if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
383 return clib_error_return (NULL, "Unable to connect socket: %d", err);
385 link = rtnl_link_alloc ();
386 rtnl_link_set_name (link, name);
388 if ((err = rtnl_link_delete (sk, link)) < 0)
389 return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
391 rtnl_link_put (link);
398 lcp_itf_pair_del (u32 phy_sw_if_index)
400 ip_address_family_t af;
403 lcp_itf_pair_vft_t *vft;
405 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
407 if (lipi == INDEX_INVALID)
408 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
410 lip = lcp_itf_pair_get (lipi);
412 LCP_ITF_PAIR_NOTICE (
413 "pair_del: host:%U phy:%U host_if:%v vif:%d ns:%v",
414 format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_host_sw_if_index,
415 format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_phy_sw_if_index,
416 lip->lip_host_name, lip->lip_vif_index, lip->lip_namespace);
418 /* invoke registered callbacks for pair deletion */
419 vec_foreach (vft, lcp_itf_vfts)
421 if (vft->pair_del_fn)
422 vft->pair_del_fn (lip);
425 FOR_EACH_IP_ADDRESS_FAMILY (af)
426 ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
427 lcp_itf_l3_feat_names[lip->lip_host_type][af],
428 lip->lip_host_sw_if_index, 0, NULL, 0);
430 lcp_itf_unset_adjs (lip);
432 ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
433 ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
435 /* disable ARP feature node for broadcast interfaces */
436 if (lip->lip_host_type != LCP_ITF_HOST_TUN)
438 vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
439 lip->lip_phy_sw_if_index, 0, NULL, 0);
440 vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
441 lip->lip_host_sw_if_index, 0, NULL, 0);
445 if (hash_elts (lip_db_by_vif) == 1)
447 vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0,
449 vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0,
453 lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
454 lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
455 hash_unset (lip_db_by_vif, lip->lip_vif_index);
457 vec_free (lip->lip_host_name);
458 vec_free (lip->lip_namespace);
459 pool_put (lcp_itf_pair_pool, lip);
465 lcp_itf_pair_delete_by_index (index_t lipi)
467 u32 host_sw_if_index;
471 lip = lcp_itf_pair_get (lipi);
473 host_name = vec_dup (lip->lip_host_name);
474 host_sw_if_index = lip->lip_host_sw_if_index;
475 ns = vec_dup (lip->lip_namespace);
477 lcp_itf_pair_del (lip->lip_phy_sw_if_index);
479 if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
485 curr_ns_fd = clib_netns_open (NULL /* self */);
486 vif_ns_fd = clib_netns_open ((u8 *) ns);
488 clib_setns (vif_ns_fd);
491 lcp_netlink_del_link ((const char *) host_name);
495 if (curr_ns_fd != -1)
497 clib_setns (curr_ns_fd);
501 vnet_delete_sub_interface (host_sw_if_index);
504 tap_delete_if (vlib_get_main (), host_sw_if_index);
506 vec_free (host_name);
511 lcp_itf_pair_delete (u32 phy_sw_if_index)
515 lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
517 if (lipi == INDEX_INVALID)
518 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
520 lcp_itf_pair_delete_by_index (lipi);
526 * lcp_itf_interface_add_del
528 * Registered to receive interface Add and delete notifications
530 static clib_error_t *
531 lcp_itf_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
534 /* remove any interface pair we have for this interface */
535 lcp_itf_pair_delete (sw_if_index);
540 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_interface_add_del);
543 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
547 pool_foreach_index (api, lcp_itf_pair_pool)
554 static clib_error_t *
555 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
561 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
563 if (unformat (input, "default netns %v", &default_ns))
565 vec_add1 (default_ns, 0);
566 if (lcp_set_default_ns (default_ns) < 0)
568 return clib_error_return (0,
569 "linux-cp default namespace must"
570 " be less than %d characters",
574 else if (unformat (input, "lcp-auto-subint"))
575 lcp_set_auto_subint (1 /* is_auto */);
576 else if (unformat (input, "lcp-sync"))
577 lcp_set_sync (1 /* is_auto */);
578 else if (unformat (input, "del-static-on-link-down"))
579 lcp_set_del_static_on_link_down (1 /* is_del */);
580 else if (unformat (input, "del-dynamic-on-link-down"))
581 lcp_set_del_dynamic_on_link_down (1 /* is_del */);
583 return clib_error_return (0, "interfaces not found");
586 vec_free (default_ns);
591 VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
594 * Returns 1 if the tap name is valid.
595 * Returns 0 if the tap name is invalid.
598 lcp_validate_if_name (u8 *name)
604 len = clib_strnlen (p, IFNAMSIZ);
631 lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
633 int curr_ns_fd, vif_ns_fd;
638 curr_ns_fd = vif_ns_fd = -1;
640 if (lip->lip_namespace)
642 curr_ns_fd = clib_netns_open (NULL /* self */);
643 vif_ns_fd = clib_netns_open (lip->lip_namespace);
645 clib_setns (vif_ns_fd);
648 /* Set the same link state on the netlink interface
650 vnet_netlink_set_link_state (lip->lip_vif_index, state);
655 if (curr_ns_fd != -1)
657 clib_setns (curr_ns_fd);
665 lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip)
667 ip4_main_t *im4 = &ip4_main;
668 ip6_main_t *im6 = &ip6_main;
669 ip_lookup_main_t *lm4 = &im4->lookup_main;
670 ip_lookup_main_t *lm6 = &im6->lookup_main;
671 ip_interface_address_t *ia = 0;
678 if (lip->lip_namespace)
680 curr_ns_fd = clib_netns_open (NULL /* self */);
681 vif_ns_fd = clib_netns_open (lip->lip_namespace);
683 clib_setns (vif_ns_fd);
686 /* Sync any IP4 addressing info into LCP */
687 foreach_ip_interface_address (
688 lm4, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
689 ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia);
690 LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip4 %U/%d",
691 format_lcp_itf_pair, lip, format_ip4_address, r4,
693 vnet_netlink_add_ip4_addr (lip->lip_vif_index, r4, ia->address_length);
696 /* Sync any IP6 addressing info into LCP */
697 foreach_ip_interface_address (
698 lm6, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({
699 ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia);
700 LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip6 %U/%d",
701 format_lcp_itf_pair, lip, format_ip6_address, r6,
703 vnet_netlink_add_ip6_addr (lip->lip_vif_index, r6, ia->address_length);
709 if (curr_ns_fd != -1)
711 clib_setns (curr_ns_fd);
721 u32 matched_sw_if_index;
725 lcp_itf_pair_find_walk (vnet_main_t *vnm, u32 sw_if_index, void *arg)
727 lcp_itf_match_t *match = arg;
728 const vnet_sw_interface_t *sw;
730 sw = vnet_get_sw_interface (vnm, sw_if_index);
731 if (sw && (sw->sub.eth.inner_vlan_id == 0) &&
732 (sw->sub.eth.outer_vlan_id == match->vlan) &&
733 (sw->sub.eth.flags.dot1ad == match->dot1ad))
735 LCP_ITF_PAIR_DBG ("find_walk: found match outer %d dot1ad %d "
736 "inner-dot1q %d: interface %U",
737 sw->sub.eth.outer_vlan_id, sw->sub.eth.flags.dot1ad,
738 sw->sub.eth.inner_vlan_id,
739 format_vnet_sw_if_index_name, vnet_get_main (),
741 match->matched_sw_if_index = sw->sw_if_index;
745 return WALK_CONTINUE;
748 /* Return the index of the sub-int on the phy that has the given vlan and
752 lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
754 lcp_itf_match_t match;
755 const vnet_hw_interface_t *hw;
758 match.dot1ad = dot1ad;
759 match.matched_sw_if_index = INDEX_INVALID;
760 hw = vnet_get_sup_hw_interface (vnet_get_main (), sup_if_index);
762 vnet_hw_interface_walk_sw (vnet_get_main (), hw->hw_if_index,
763 lcp_itf_pair_find_walk, &match);
765 if (match.matched_sw_if_index >= vec_len (lip_db_by_phy))
766 return INDEX_INVALID;
768 return lip_db_by_phy[match.matched_sw_if_index];
771 static clib_error_t *lcp_itf_pair_link_up_down (vnet_main_t *vnm,
772 u32 hw_if_index, u32 flags);
775 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
776 lip_host_type_t host_if_type, u8 *ns,
777 u32 *host_sw_if_indexp)
781 u32 vif_index = 0, host_sw_if_index;
782 const vnet_sw_interface_t *sw;
783 const vnet_hw_interface_t *hw;
784 const lcp_itf_pair_t *lip;
786 if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
788 LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
789 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
792 if (!lcp_validate_if_name (host_if_name))
794 LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
796 return VNET_API_ERROR_INVALID_ARGUMENT;
799 vnm = vnet_get_main ();
800 sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
801 hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
804 LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
805 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
809 * Use interface-specific netns if supplied.
810 * Otherwise, use netns if defined, otherwise use the OS default.
812 if (ns == 0 || ns[0] == 0)
813 ns = lcp_get_default_ns ();
815 /* sub interfaces do not need a tap created */
816 if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
818 index_t parent_if_index;
819 int orig_ns_fd, ns_fd;
821 u16 outer_vlan, inner_vlan;
822 u16 outer_proto, inner_proto;
824 u32 parent_vif_index;
826 err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index);
829 LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
830 "sub-interface without exact-match set");
831 return VNET_API_ERROR_INVALID_ARGUMENT;
834 outer_vlan = sw->sub.eth.outer_vlan_id;
835 inner_vlan = sw->sub.eth.inner_vlan_id;
836 outer_proto = inner_proto = ETH_P_8021Q;
837 if (1 == sw->sub.eth.flags.dot1ad)
838 outer_proto = ETH_P_8021AD;
840 LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
841 sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
842 inner_vlan, format_vnet_sw_if_index_name, vnm,
845 parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
846 if (INDEX_INVALID == parent_if_index)
848 LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
849 format_vnet_sw_if_index_name, vnet_get_main (),
850 sw->sup_sw_if_index);
851 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
853 lip = lcp_itf_pair_get (parent_if_index);
856 LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
857 "sub-interface without an LCP on the parent");
858 return VNET_API_ERROR_INVALID_ARGUMENT;
860 LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
861 parent_vif_index = lip->lip_vif_index;
864 * see if the requested host interface has already been created
866 orig_ns_fd = ns_fd = -1;
869 if (ns && ns[0] != 0)
871 orig_ns_fd = clib_netns_open (NULL /* self */);
872 ns_fd = clib_netns_open (ns);
873 if (orig_ns_fd == -1 || ns_fd == -1)
879 vif_index = if_nametoindex ((const char *) host_if_name);
884 * no existing host interface, create it now
888 * Find the parent tap:
889 * - if this is an outer VLAN, use the pair from the parent phy
890 * - if this is an inner VLAN, find the pair from the outer sub-int,
895 index_t linux_parent_if_index;
896 const lcp_itf_pair_t *llip;
900 linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
901 hw->sw_if_index, sw->sub.eth.outer_vlan_id,
902 sw->sub.eth.flags.dot1ad);
903 if (INDEX_INVALID == linux_parent_if_index ||
904 !(llip = lcp_itf_pair_get (linux_parent_if_index)))
907 "pair_create: can't find LCP for outer vlan %d "
910 outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
911 format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
912 err = clib_error_return (0, "parent pair not found");
916 LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
917 format_lcp_itf_pair, llip);
918 parent_vif_index = llip->lip_vif_index;
926 err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
927 (const char *) host_if_name);
930 LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
931 "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
932 "04x,vlan:%u) name:'%s'",
933 outer_proto, outer_vlan, inner_proto,
934 inner_vlan, host_if_name);
938 vif_index = if_nametoindex ((char *) host_if_name);
942 * create a sub-interface on the tap
945 vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
946 sw->sub.eth.raw_flags, inner_vlan,
947 outer_vlan, &host_sw_if_index))
950 "pair_create: failed to create tap subint: %d.%d on %U",
951 outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
952 lip->lip_host_sw_if_index);
953 err = clib_error_return (
954 0, "failed to create tap subint: %d.%d. on %U", outer_vlan,
955 inner_vlan, format_vnet_sw_if_index_name, vnm,
956 lip->lip_host_sw_if_index);
960 if (orig_ns_fd != -1)
962 clib_setns (orig_ns_fd);
969 return VNET_API_ERROR_INVALID_ARGUMENT;
973 tap_create_if_args_t args = {
974 .num_rx_queues = clib_max (1, vlib_num_workers ()),
976 .id = hw->hw_if_index,
980 .host_if_name = host_if_name,
983 ethernet_interface_t *ei;
984 u32 host_sw_mtu_size;
986 if (host_if_type == LCP_ITF_HOST_TUN)
987 args.tap_flags |= TAP_FLAG_TUN;
990 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
991 mac_address_copy (&args.host_mac_addr, &ei->address.mac);
995 * The TAP interface does copy forward the host MTU based on the VPP
996 * interface's L3 MTU, but it should also ensure that the VPP tap
997 * interface has an MTU that is greater-or-equal to those. Considering
998 * users can set the interfaces at runtime (set interface mtu packet ...)
999 * ensure that the tap MTU is large enough, taking the VPP interface L3
1000 * if it's set, and otherwise a sensible default.
1002 host_sw_mtu_size = sw->mtu[VNET_MTU_L3];
1003 if (host_sw_mtu_size)
1005 args.host_mtu_set = 1;
1006 args.host_mtu_size = host_sw_mtu_size;
1009 host_sw_mtu_size = ETHERNET_MAX_PACKET_BYTES;
1011 if (ns && ns[0] != 0)
1012 args.host_namespace = ns;
1014 vm = vlib_get_main ();
1015 tap_create_if (vm, &args);
1018 LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
1023 vnet_sw_interface_set_mtu (vnm, args.sw_if_index, host_sw_mtu_size);
1026 * get the hw and ethernet of the tap
1028 hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
1029 virtio_main_t *mm = &virtio_main;
1030 virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1033 * Leave the TAP permanently up on the VPP side.
1034 * This TAP will be shared by many sub-interface.
1035 * Therefore we can't use it to manage admin state.
1036 * force the tap in promiscuous mode.
1038 if (host_if_type == LCP_ITF_HOST_TAP)
1040 ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
1041 ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
1044 vif_index = vif->ifindex;
1045 host_sw_if_index = args.sw_if_index;
1050 LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
1051 format_vnet_sw_if_index_name, vnet_get_main (),
1052 phy_sw_if_index, format_vnet_sw_if_index_name,
1053 vnet_get_main (), host_sw_if_index, host_if_name);
1057 LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
1058 vnet_get_main (), phy_sw_if_index,
1059 format_vnet_sw_if_index_name, vnet_get_main (),
1060 host_sw_if_index, host_if_name);
1061 lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
1065 * Copy the link state from VPP into the host side.
1066 * The TAP is shared by many interfaces, always keep it up.
1067 * This controls whether the host can RX/TX.
1069 sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
1070 lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
1071 LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
1072 format_lcp_itf_pair, lip, sw->flags, hw->flags);
1073 vnet_sw_interface_admin_up (vnm, host_sw_if_index);
1074 lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1077 * Reflect current link state and link speed of the hardware interface on the
1080 if (host_if_type == LCP_ITF_HOST_TAP &&
1081 !vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
1083 hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
1084 lcp_itf_pair_link_up_down (vnm, hw->hw_if_index, hw->flags);
1087 if (host_sw_if_indexp)
1088 *host_sw_if_indexp = host_sw_if_index;
1094 lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
1096 lcp_itf_pair_t *lip;
1098 lip = lcp_itf_pair_get (lipi);
1100 lip->lip_flags |= LIP_FLAG_STALE;
1102 return (WALK_CONTINUE);
1106 lcp_itf_pair_replace_begin (void)
1108 lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
1113 typedef struct lcp_itf_pair_sweep_ctx_t_
1116 } lcp_itf_pair_sweep_ctx_t;
1119 lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
1121 lcp_itf_pair_sweep_ctx_t *ctx = arg;
1122 lcp_itf_pair_t *lip;
1124 lip = lcp_itf_pair_get (lipi);
1126 if (lip->lip_flags & LIP_FLAG_STALE)
1127 vec_add1 (ctx->indicies, lipi);
1129 return (WALK_CONTINUE);
1133 lcp_itf_pair_replace_end (void)
1135 lcp_itf_pair_sweep_ctx_t ctx = {
1140 lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
1142 vec_foreach (lipi, ctx.indicies)
1143 lcp_itf_pair_delete_by_index (*lipi);
1145 vec_free (ctx.indicies);
1149 static clib_error_t *
1150 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1152 vnet_hw_interface_t *hi;
1153 vnet_sw_interface_t *si;
1155 lcp_itf_pair_t *lip;
1157 hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
1161 lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
1162 if (lipi == INDEX_INVALID)
1165 lip = lcp_itf_pair_get (lipi);
1166 si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
1170 if (!lcp_main.test_mode)
1172 tap_set_carrier (si->hw_if_index,
1173 (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
1175 if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1177 tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1184 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1186 static clib_error_t *
1187 lcp_interface_init (vlib_main_t *vm)
1189 vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1192 vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1195 /* punt all unknown ports */
1196 udp_punt_unknown (vm, 0, 1);
1197 udp_punt_unknown (vm, 1, 1);
1198 tcp_punt_unknown (vm, 0, 1);
1199 tcp_punt_unknown (vm, 1, 1);
1201 lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1206 VLIB_INIT_FUNCTION (lcp_interface_init) = {
1207 .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1211 * fd.io coding-style-patch-verification: ON
1214 * eval: (c-set-style "gnu")