LCOV - code coverage report
Current view: top level - plugins/linux-cp - lcp_interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 160 480 33.3 %
Date: 2023-07-05 22:20:52 Functions: 22 38 57.9 %

          Line data    Source code
       1             : /*
       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:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       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.
      14             :  */
      15             : 
      16             : #define _GNU_SOURCE
      17             : #include <fcntl.h>
      18             : #include <ctype.h>
      19             : #include <sys/socket.h>
      20             : #include <net/if.h>
      21             : 
      22             : #include <linux-cp/lcp_interface.h>
      23             : #include <netlink/route/link/vlan.h>
      24             : #include <linux/if_ether.h>
      25             : 
      26             : #include <vnet/plugin/plugin.h>
      27             : #include <vnet/plugin/plugin.h>
      28             : 
      29             : #include <vppinfra/linux/netns.h>
      30             : 
      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>
      41             : 
      42             : vlib_log_class_t lcp_itf_pair_logger;
      43             : 
      44             : /**
      45             :  * Pool of LIP objects
      46             :  */
      47             : lcp_itf_pair_t *lcp_itf_pair_pool = NULL;
      48             : 
      49             : u32
      50           0 : lcp_itf_num_pairs (void)
      51             : {
      52           0 :   return pool_elts (lcp_itf_pair_pool);
      53             : }
      54             : 
      55             : /**
      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
      60             :  */
      61             : static uword *lip_db_by_vif;
      62             : index_t *lip_db_by_phy;
      63             : u32 *lip_db_by_host;
      64             : 
      65             : /**
      66             :  * vector of virtual function table
      67             :  */
      68             : static lcp_itf_pair_vft_t *lcp_itf_vfts = NULL;
      69             : 
      70             : void
      71           0 : lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
      72             : {
      73           0 :   vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
      74           0 : }
      75             : 
      76             : u8 *
      77           5 : format_lcp_itf_pair (u8 *s, va_list *args)
      78             : {
      79           5 :   vnet_main_t *vnm = vnet_get_main ();
      80           5 :   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;
      83             : 
      84           5 :   s = format (s, "itf-pair: [%d]", lip - lcp_itf_pair_pool);
      85             : 
      86           5 :   swif_phy = vnet_get_sw_interface_or_null (vnm, lip->lip_phy_sw_if_index);
      87           5 :   if (!swif_phy)
      88           0 :     s = format (s, " <no-phy-if>");
      89             :   else
      90           5 :     s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_phy);
      91             : 
      92           5 :   swif_host = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
      93           5 :   if (!swif_host)
      94           0 :     s = format (s, " <no-host-if>");
      95             :   else
      96           5 :     s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_host);
      97             : 
      98           5 :   s = format (s, " %v %d type %s", lip->lip_host_name, lip->lip_vif_index,
      99           5 :               (lip->lip_host_type == LCP_ITF_HOST_TAP) ? "tap" : "tun");
     100             : 
     101           5 :   if (lip->lip_namespace)
     102           0 :     s = format (s, " netns %s", lip->lip_namespace);
     103             : 
     104           5 :   return s;
     105             : }
     106             : 
     107             : static walk_rc_t
     108           5 : lcp_itf_pair_walk_show_cb (index_t api, void *ctx)
     109             : {
     110             :   vlib_main_t *vm;
     111             :   lcp_itf_pair_t *lip;
     112             : 
     113           5 :   lip = lcp_itf_pair_get (api);
     114           5 :   if (!lip)
     115           0 :     return WALK_STOP;
     116             : 
     117           5 :   vm = vlib_get_main ();
     118           5 :   vlib_cli_output (vm, "%U\n", format_lcp_itf_pair, lip);
     119             : 
     120           5 :   return WALK_CONTINUE;
     121             : }
     122             : 
     123             : void
     124           3 : lcp_itf_pair_show (u32 phy_sw_if_index)
     125             : {
     126             :   vlib_main_t *vm;
     127             :   u8 *ns;
     128             :   index_t api;
     129             : 
     130           3 :   vm = vlib_get_main ();
     131           3 :   ns = lcp_get_default_ns ();
     132           3 :   vlib_cli_output (vm, "lcp default netns '%s'\n",
     133             :                    ns ? (char *) ns : "<unset>");
     134           3 :   vlib_cli_output (vm, "lcp lcp-auto-subint %s\n",
     135           3 :                    lcp_auto_subint () ? "on" : "off");
     136           3 :   vlib_cli_output (vm, "lcp lcp-sync %s\n", lcp_sync () ? "on" : "off");
     137           3 :   vlib_cli_output (vm, "lcp del-static-on-link-down %s\n",
     138           3 :                    lcp_get_del_static_on_link_down () ? "on" : "off");
     139           3 :   vlib_cli_output (vm, "lcp del-dynamic-on-link-down %s\n",
     140           3 :                    lcp_get_del_dynamic_on_link_down () ? "on" : "off");
     141             : 
     142           3 :   if (phy_sw_if_index == ~0)
     143             :     {
     144           3 :       lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
     145             :     }
     146             :   else
     147             :     {
     148           0 :       api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
     149           0 :       if (api != INDEX_INVALID)
     150           0 :         lcp_itf_pair_walk_show_cb (api, 0);
     151             :     }
     152           3 : }
     153             : 
     154             : lcp_itf_pair_t *
     155         236 : lcp_itf_pair_get (u32 index)
     156             : {
     157         236 :   if (!lcp_itf_pair_pool)
     158           0 :     return NULL;
     159         236 :   if (index == INDEX_INVALID)
     160           0 :     return NULL;
     161             : 
     162         236 :   return pool_elt_at_index (lcp_itf_pair_pool, index);
     163             : }
     164             : 
     165             : index_t
     166           0 : lcp_itf_pair_find_by_vif (u32 vif_index)
     167             : {
     168             :   uword *p;
     169             : 
     170           0 :   p = hash_get (lip_db_by_vif, vif_index);
     171             : 
     172           0 :   if (p)
     173           0 :     return p[0];
     174             : 
     175           0 :   return INDEX_INVALID;
     176             : }
     177             : 
     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",
     182             :   },
     183             :   [LCP_ITF_HOST_TUN] = {
     184             :     [AF_IP4] = "linux-cp-xc-l3-ip4",
     185             :     [AF_IP6] = "linux-cp-xc-l3-ip6",
     186             :   },
     187             : };
     188             : 
     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,
     192             : };
     193             : 
     194             : static void
     195           5 : lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
     196             : {
     197           5 :   adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
     198           5 :   adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
     199           5 : }
     200             : 
     201             : static void
     202           5 : lcp_itf_set_adjs (lcp_itf_pair_t *lip)
     203             : {
     204           5 :   if (lip->lip_host_type == LCP_ITF_HOST_TUN)
     205             :     {
     206           3 :       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           3 :       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);
     210             :     }
     211             :   else
     212             :     {
     213           2 :       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           2 :       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);
     217             :     }
     218             : 
     219             :   ip_adjacency_t *adj;
     220             : 
     221           5 :   adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
     222             : 
     223           5 :   lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
     224           5 : }
     225             : 
     226             : int
     227           5 : 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)
     229             : {
     230             :   index_t lipi;
     231             :   lcp_itf_pair_t *lip;
     232             : 
     233           5 :   if (host_sw_if_index == ~0)
     234             :     {
     235           0 :       LCP_ITF_PAIR_ERR ("pair_add: Cannot add LIP - invalid host");
     236           0 :       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     237             :     }
     238             : 
     239           5 :   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
     240             : 
     241           5 :   if (lipi != INDEX_INVALID)
     242           0 :     return VNET_API_ERROR_VALUE_EXIST;
     243             : 
     244           5 :   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,
     248             :                      ns);
     249             : 
     250             :   /*
     251             :    * Create a new pair.
     252             :    */
     253           5 :   pool_get (lcp_itf_pair_pool, lip);
     254             : 
     255           5 :   lipi = lip - lcp_itf_pair_pool;
     256             : 
     257          21 :   vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
     258          17 :   vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
     259           5 :   lip_db_by_phy[phy_sw_if_index] = lipi;
     260           5 :   lip_db_by_host[host_sw_if_index] = lipi;
     261           5 :   hash_set (lip_db_by_vif, host_index, lipi);
     262             : 
     263           5 :   lip->lip_host_sw_if_index = host_sw_if_index;
     264           5 :   lip->lip_phy_sw_if_index = phy_sw_if_index;
     265           5 :   lip->lip_host_name = vec_dup (host_name);
     266           5 :   lip->lip_host_type = host_type;
     267           5 :   lip->lip_vif_index = host_index;
     268           5 :   lip->lip_namespace = vec_dup (ns);
     269             : 
     270             :   /*
     271             :    * First use of this host interface.
     272             :    * Enable the x-connect feature on the host to send
     273             :    * all packets to the phy.
     274             :    */
     275             :   ip_address_family_t af;
     276             : 
     277          15 :   FOR_EACH_IP_ADDRESS_FAMILY (af)
     278          10 :   ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
     279          10 :                              lcp_itf_l3_feat_names[lip->lip_host_type][af],
     280          10 :                              lip->lip_host_sw_if_index, 1, NULL, 0);
     281             : 
     282             :   /*
     283             :    * Configure passive punt to the host interface.
     284             :    */
     285           5 :   fib_route_path_t *rpaths = NULL, rpath = {
     286           5 :     .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
     287             :     .frp_proto = DPO_PROTO_IP4,
     288           5 :     .frp_sw_if_index = lip->lip_host_sw_if_index,
     289             :     .frp_weight = 1,
     290             :     .frp_fib_index = ~0,
     291             :   };
     292             : 
     293           5 :   vec_add1 (rpaths, rpath);
     294             : 
     295           5 :   ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
     296             : 
     297           5 :   rpaths[0].frp_proto = DPO_PROTO_IP6;
     298             : 
     299           5 :   ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
     300             : 
     301           5 :   vec_free (rpaths);
     302             : 
     303           5 :   lcp_itf_set_adjs (lip);
     304             : 
     305             :   /* enable ARP feature node for broadcast interfaces */
     306           5 :   if (lip->lip_host_type != LCP_ITF_HOST_TUN)
     307             :     {
     308           2 :       vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
     309           2 :                                    lip->lip_phy_sw_if_index, 1, NULL, 0);
     310           2 :       vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
     311           2 :                                    lip->lip_host_sw_if_index, 1, NULL, 0);
     312             :     }
     313             :   else
     314             :     {
     315           3 :       if (hash_elts (lip_db_by_vif) == 1)
     316             :         {
     317           2 :           vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1,
     318             :                                        NULL, 0);
     319           2 :           vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1,
     320             :                                        NULL, 0);
     321             :         }
     322             :     }
     323             : 
     324             :   /* invoke registered callbacks for pair addition */
     325             :   lcp_itf_pair_vft_t *vft;
     326             : 
     327           5 :   vec_foreach (vft, lcp_itf_vfts)
     328             :     {
     329           0 :       if (vft->pair_add_fn)
     330           0 :         vft->pair_add_fn (lip);
     331             :     }
     332             : 
     333             :   /* set timestamp when pair entered service */
     334           5 :   lip->lip_create_ts = vlib_time_now (vlib_get_main ());
     335             : 
     336           5 :   return 0;
     337             : }
     338             : 
     339             : static clib_error_t *
     340           0 : lcp_netlink_add_link_vlan (int parent, u32 vlan, u16 proto, const char *name)
     341             : {
     342             :   struct rtnl_link *link;
     343             :   struct nl_sock *sk;
     344             :   int err;
     345             : 
     346           0 :   sk = nl_socket_alloc ();
     347           0 :   if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
     348             :     {
     349           0 :       LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: connect error: %s",
     350             :                         nl_geterror (err));
     351           0 :       return clib_error_return (NULL, "Unable to connect socket: %d", err);
     352             :     }
     353             : 
     354           0 :   link = rtnl_link_vlan_alloc ();
     355             : 
     356           0 :   rtnl_link_set_link (link, parent);
     357           0 :   rtnl_link_set_name (link, name);
     358           0 :   rtnl_link_vlan_set_id (link, vlan);
     359           0 :   rtnl_link_vlan_set_protocol (link, htons (proto));
     360             : 
     361           0 :   if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
     362             :     {
     363           0 :       LCP_ITF_PAIR_ERR ("netlink_add_link_vlan: link add error: %s",
     364             :                         nl_geterror (err));
     365           0 :       return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
     366             :     }
     367             : 
     368           0 :   rtnl_link_put (link);
     369           0 :   nl_close (sk);
     370             : 
     371           0 :   return NULL;
     372             : }
     373             : 
     374             : static clib_error_t *
     375           0 : lcp_netlink_del_link (const char *name)
     376             : {
     377             :   struct rtnl_link *link;
     378             :   struct nl_sock *sk;
     379             :   int err;
     380             : 
     381           0 :   sk = nl_socket_alloc ();
     382           0 :   if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
     383           0 :     return clib_error_return (NULL, "Unable to connect socket: %d", err);
     384             : 
     385           0 :   link = rtnl_link_alloc ();
     386           0 :   rtnl_link_set_name (link, name);
     387             : 
     388           0 :   if ((err = rtnl_link_delete (sk, link)) < 0)
     389           0 :     return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
     390             : 
     391           0 :   rtnl_link_put (link);
     392           0 :   nl_close (sk);
     393             : 
     394           0 :   return NULL;
     395             : }
     396             : 
     397             : int
     398           5 : lcp_itf_pair_del (u32 phy_sw_if_index)
     399             : {
     400             :   ip_address_family_t af;
     401             :   lcp_itf_pair_t *lip;
     402             :   u32 lipi;
     403             :   lcp_itf_pair_vft_t *vft;
     404             : 
     405           5 :   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
     406             : 
     407           5 :   if (lipi == INDEX_INVALID)
     408           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     409             : 
     410           5 :   lip = lcp_itf_pair_get (lipi);
     411             : 
     412           5 :   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);
     417             : 
     418             :   /* invoke registered callbacks for pair deletion */
     419           5 :   vec_foreach (vft, lcp_itf_vfts)
     420             :     {
     421           0 :       if (vft->pair_del_fn)
     422           0 :         vft->pair_del_fn (lip);
     423             :     }
     424             : 
     425          15 :   FOR_EACH_IP_ADDRESS_FAMILY (af)
     426          10 :   ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
     427          10 :                              lcp_itf_l3_feat_names[lip->lip_host_type][af],
     428             :                              lip->lip_host_sw_if_index, 0, NULL, 0);
     429             : 
     430           5 :   lcp_itf_unset_adjs (lip);
     431             : 
     432           5 :   ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
     433           5 :   ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
     434             : 
     435             :   /* disable ARP feature node for broadcast interfaces */
     436           5 :   if (lip->lip_host_type != LCP_ITF_HOST_TUN)
     437             :     {
     438           2 :       vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
     439             :                                    lip->lip_phy_sw_if_index, 0, NULL, 0);
     440           2 :       vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
     441             :                                    lip->lip_host_sw_if_index, 0, NULL, 0);
     442             :     }
     443             :   else
     444             :     {
     445           3 :       if (hash_elts (lip_db_by_vif) == 1)
     446             :         {
     447           2 :           vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0,
     448             :                                        NULL, 0);
     449           2 :           vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0,
     450             :                                        NULL, 0);
     451             :         }
     452             :     }
     453           5 :   lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
     454           5 :   lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
     455           5 :   hash_unset (lip_db_by_vif, lip->lip_vif_index);
     456             : 
     457           5 :   vec_free (lip->lip_host_name);
     458           5 :   vec_free (lip->lip_namespace);
     459           5 :   pool_put (lcp_itf_pair_pool, lip);
     460             : 
     461           5 :   return 0;
     462             : }
     463             : 
     464             : static void
     465           0 : lcp_itf_pair_delete_by_index (index_t lipi)
     466             : {
     467             :   u32 host_sw_if_index;
     468             :   lcp_itf_pair_t *lip;
     469             :   u8 *host_name, *ns;
     470             : 
     471           0 :   lip = lcp_itf_pair_get (lipi);
     472             : 
     473           0 :   host_name = vec_dup (lip->lip_host_name);
     474           0 :   host_sw_if_index = lip->lip_host_sw_if_index;
     475           0 :   ns = vec_dup (lip->lip_namespace);
     476             : 
     477           0 :   lcp_itf_pair_del (lip->lip_phy_sw_if_index);
     478             : 
     479           0 :   if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
     480             :     {
     481           0 :       int curr_ns_fd = -1;
     482           0 :       int vif_ns_fd = -1;
     483           0 :       if (ns)
     484             :         {
     485           0 :           curr_ns_fd = clib_netns_open (NULL /* self */);
     486           0 :           vif_ns_fd = clib_netns_open ((u8 *) ns);
     487           0 :           if (vif_ns_fd != -1)
     488           0 :             clib_setns (vif_ns_fd);
     489             :         }
     490             : 
     491           0 :       lcp_netlink_del_link ((const char *) host_name);
     492           0 :       if (vif_ns_fd != -1)
     493           0 :         close (vif_ns_fd);
     494             : 
     495           0 :       if (curr_ns_fd != -1)
     496             :         {
     497           0 :           clib_setns (curr_ns_fd);
     498           0 :           close (curr_ns_fd);
     499             :         }
     500             : 
     501           0 :       vnet_delete_sub_interface (host_sw_if_index);
     502             :     }
     503             :   else
     504           0 :     tap_delete_if (vlib_get_main (), host_sw_if_index);
     505             : 
     506           0 :   vec_free (host_name);
     507           0 :   vec_free (ns);
     508           0 : }
     509             : 
     510             : int
     511           3 : lcp_itf_pair_delete (u32 phy_sw_if_index)
     512             : {
     513             :   index_t lipi;
     514             : 
     515           3 :   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
     516             : 
     517           3 :   if (lipi == INDEX_INVALID)
     518           3 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     519             : 
     520           0 :   lcp_itf_pair_delete_by_index (lipi);
     521             : 
     522           0 :   return 0;
     523             : }
     524             : 
     525             : /**
     526             :  * lcp_itf_interface_add_del
     527             :  *
     528             :  * Registered to receive interface Add and delete notifications
     529             :  */
     530             : static clib_error_t *
     531          19 : lcp_itf_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
     532             : {
     533          19 :   if (!is_add)
     534             :     /* remove any interface pair we have for this interface */
     535           3 :     lcp_itf_pair_delete (sw_if_index);
     536             : 
     537          19 :   return (NULL);
     538             : }
     539             : 
     540           6 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_interface_add_del);
     541             : 
     542             : void
     543           3 : lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
     544             : {
     545             :   u32 api;
     546             : 
     547           8 :   pool_foreach_index (api, lcp_itf_pair_pool)
     548             :     {
     549           5 :       if (!cb (api, ctx))
     550           0 :         break;
     551             :     };
     552           3 : }
     553             : 
     554             : static clib_error_t *
     555           2 : lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
     556             : {
     557             :   u8 *default_ns;
     558             : 
     559           2 :   default_ns = NULL;
     560             : 
     561           2 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     562             :     {
     563           0 :       if (unformat (input, "default netns %v", &default_ns))
     564             :         {
     565           0 :           vec_add1 (default_ns, 0);
     566           0 :           if (lcp_set_default_ns (default_ns) < 0)
     567             :             {
     568           0 :               return clib_error_return (0,
     569             :                                         "linux-cp default namespace must"
     570             :                                         " be less than %d characters",
     571             :                                         LCP_NS_LEN);
     572             :             }
     573             :         }
     574           0 :       else if (unformat (input, "lcp-auto-subint"))
     575           0 :         lcp_set_auto_subint (1 /* is_auto */);
     576           0 :       else if (unformat (input, "lcp-sync"))
     577           0 :         lcp_set_sync (1 /* is_auto */);
     578           0 :       else if (unformat (input, "del-static-on-link-down"))
     579           0 :         lcp_set_del_static_on_link_down (1 /* is_del */);
     580           0 :       else if (unformat (input, "del-dynamic-on-link-down"))
     581           0 :         lcp_set_del_dynamic_on_link_down (1 /* is_del */);
     582             :       else
     583           0 :         return clib_error_return (0, "interfaces not found");
     584             :     }
     585             : 
     586           2 :   vec_free (default_ns);
     587             : 
     588           2 :   return NULL;
     589             : }
     590             : 
     591          10 : VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
     592             : 
     593             : /*
     594             :  * Returns 1 if the tap name is valid.
     595             :  * Returns 0 if the tap name is invalid.
     596             :  */
     597             : static int
     598           0 : lcp_validate_if_name (u8 *name)
     599             : {
     600             :   int len;
     601             :   char *p;
     602             : 
     603           0 :   p = (char *) name;
     604           0 :   len = clib_strnlen (p, IFNAMSIZ);
     605           0 :   if (len >= IFNAMSIZ)
     606           0 :     return 0;
     607             : 
     608           0 :   for (; *p; ++p)
     609             :     {
     610           0 :       if (isalnum (*p))
     611           0 :         continue;
     612             : 
     613           0 :       switch (*p)
     614             :         {
     615           0 :         case '-':
     616             :         case '_':
     617             :         case '%':
     618             :         case '@':
     619             :         case ':':
     620             :         case '.':
     621           0 :           continue;
     622             :         }
     623             : 
     624           0 :       return 0;
     625             :     }
     626             : 
     627           0 :   return 1;
     628             : }
     629             : 
     630             : void
     631           0 : lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
     632             : {
     633             :   int curr_ns_fd, vif_ns_fd;
     634             : 
     635           0 :   if (!lip)
     636           0 :     return;
     637             : 
     638           0 :   curr_ns_fd = vif_ns_fd = -1;
     639             : 
     640           0 :   if (lip->lip_namespace)
     641             :     {
     642           0 :       curr_ns_fd = clib_netns_open (NULL /* self */);
     643           0 :       vif_ns_fd = clib_netns_open (lip->lip_namespace);
     644           0 :       if (vif_ns_fd != -1)
     645           0 :         clib_setns (vif_ns_fd);
     646             :     }
     647             : 
     648             :   /* Set the same link state on the netlink interface
     649             :    */
     650           0 :   vnet_netlink_set_link_state (lip->lip_vif_index, state);
     651             : 
     652           0 :   if (vif_ns_fd != -1)
     653           0 :     close (vif_ns_fd);
     654             : 
     655           0 :   if (curr_ns_fd != -1)
     656             :     {
     657           0 :       clib_setns (curr_ns_fd);
     658           0 :       close (curr_ns_fd);
     659             :     }
     660             : 
     661           0 :   return;
     662             : }
     663             : 
     664             : void
     665           0 : lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip)
     666             : {
     667           0 :   ip4_main_t *im4 = &ip4_main;
     668           0 :   ip6_main_t *im6 = &ip6_main;
     669           0 :   ip_lookup_main_t *lm4 = &im4->lookup_main;
     670           0 :   ip_lookup_main_t *lm6 = &im6->lookup_main;
     671           0 :   ip_interface_address_t *ia = 0;
     672           0 :   int vif_ns_fd = -1;
     673           0 :   int curr_ns_fd = -1;
     674             : 
     675           0 :   if (!lip)
     676           0 :     return;
     677             : 
     678           0 :   if (lip->lip_namespace)
     679             :     {
     680           0 :       curr_ns_fd = clib_netns_open (NULL /* self */);
     681           0 :       vif_ns_fd = clib_netns_open (lip->lip_namespace);
     682           0 :       if (vif_ns_fd != -1)
     683           0 :         clib_setns (vif_ns_fd);
     684             :     }
     685             : 
     686             :   /* Sync any IP4 addressing info into LCP */
     687           0 :   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,
     692             :                            ia->address_length);
     693             :       vnet_netlink_add_ip4_addr (lip->lip_vif_index, r4, ia->address_length);
     694             :     }));
     695             : 
     696             :   /* Sync any IP6 addressing info into LCP */
     697           0 :   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,
     702             :                            ia->address_length);
     703             :       vnet_netlink_add_ip6_addr (lip->lip_vif_index, r6, ia->address_length);
     704             :     }));
     705             : 
     706           0 :   if (vif_ns_fd != -1)
     707           0 :     close (vif_ns_fd);
     708             : 
     709           0 :   if (curr_ns_fd != -1)
     710             :     {
     711           0 :       clib_setns (curr_ns_fd);
     712           0 :       close (curr_ns_fd);
     713             :     }
     714             : }
     715             : 
     716             : typedef struct
     717             : {
     718             :   u32 vlan;
     719             :   bool dot1ad;
     720             : 
     721             :   u32 matched_sw_if_index;
     722             : } lcp_itf_match_t;
     723             : 
     724             : static walk_rc_t
     725           0 : lcp_itf_pair_find_walk (vnet_main_t *vnm, u32 sw_if_index, void *arg)
     726             : {
     727           0 :   lcp_itf_match_t *match = arg;
     728             :   const vnet_sw_interface_t *sw;
     729             : 
     730           0 :   sw = vnet_get_sw_interface (vnm, sw_if_index);
     731           0 :   if (sw && (sw->sub.eth.inner_vlan_id == 0) &&
     732           0 :       (sw->sub.eth.outer_vlan_id == match->vlan) &&
     733           0 :       (sw->sub.eth.flags.dot1ad == match->dot1ad))
     734             :     {
     735           0 :       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 (),
     740             :                         sw->sw_if_index);
     741           0 :       match->matched_sw_if_index = sw->sw_if_index;
     742           0 :       return WALK_STOP;
     743             :     }
     744             : 
     745           0 :   return WALK_CONTINUE;
     746             : }
     747             : 
     748             : /* Return the index of the sub-int on the phy that has the given vlan and
     749             :  * proto,
     750             :  */
     751             : static index_t
     752           0 : lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
     753             : {
     754             :   lcp_itf_match_t match;
     755             :   const vnet_hw_interface_t *hw;
     756             : 
     757           0 :   match.vlan = vlan;
     758           0 :   match.dot1ad = dot1ad;
     759           0 :   match.matched_sw_if_index = INDEX_INVALID;
     760           0 :   hw = vnet_get_sup_hw_interface (vnet_get_main (), sup_if_index);
     761             : 
     762           0 :   vnet_hw_interface_walk_sw (vnet_get_main (), hw->hw_if_index,
     763             :                              lcp_itf_pair_find_walk, &match);
     764             : 
     765           0 :   if (match.matched_sw_if_index >= vec_len (lip_db_by_phy))
     766           0 :     return INDEX_INVALID;
     767             : 
     768           0 :   return lip_db_by_phy[match.matched_sw_if_index];
     769             : }
     770             : 
     771             : static clib_error_t *lcp_itf_pair_link_up_down (vnet_main_t *vnm,
     772             :                                                 u32 hw_if_index, u32 flags);
     773             : 
     774             : int
     775           0 : 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)
     778             : {
     779             :   vlib_main_t *vm;
     780             :   vnet_main_t *vnm;
     781           0 :   u32 vif_index = 0, host_sw_if_index = ~0;
     782             :   const vnet_sw_interface_t *sw;
     783             :   const vnet_hw_interface_t *hw;
     784             :   const lcp_itf_pair_t *lip;
     785             : 
     786           0 :   if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
     787             :     {
     788           0 :       LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
     789           0 :       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     790             :     }
     791             : 
     792           0 :   if (!lcp_validate_if_name (host_if_name))
     793             :     {
     794           0 :       LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
     795             :                         host_if_name);
     796           0 :       return VNET_API_ERROR_INVALID_ARGUMENT;
     797             :     }
     798             : 
     799           0 :   vnm = vnet_get_main ();
     800           0 :   sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
     801           0 :   hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
     802           0 :   if (!sw || !hw)
     803             :     {
     804           0 :       LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
     805           0 :       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     806             :     }
     807             : 
     808           0 :   if (hw->hw_class_index != ethernet_hw_interface_class.index &&
     809             :       host_if_type == LCP_ITF_HOST_TAP)
     810             :     {
     811           0 :       LCP_ITF_PAIR_ERR (
     812             :         "pair_create: don't create TAP for non-eth interface; use tun");
     813           0 :       return VNET_API_ERROR_INVALID_ARGUMENT;
     814             :     }
     815             : 
     816             :   /*
     817             :    * Use interface-specific netns if supplied.
     818             :    * Otherwise, use netns if defined, otherwise use the OS default.
     819             :    */
     820           0 :   if (ns == 0 || ns[0] == 0)
     821           0 :     ns = lcp_get_default_ns ();
     822             : 
     823             :   /* sub interfaces do not need a tap created */
     824           0 :   if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
     825             :     {
     826             :       index_t parent_if_index;
     827             :       int orig_ns_fd, ns_fd;
     828             :       clib_error_t *err;
     829             :       u16 outer_vlan, inner_vlan;
     830             :       u16 outer_proto, inner_proto;
     831             :       u16 vlan, proto;
     832             :       u32 parent_vif_index;
     833             : 
     834           0 :       err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index);
     835           0 :       if (err)
     836             :         {
     837           0 :           LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
     838             :                             "sub-interface without exact-match set");
     839           0 :           return VNET_API_ERROR_INVALID_ARGUMENT;
     840             :         }
     841             : 
     842           0 :       outer_vlan = sw->sub.eth.outer_vlan_id;
     843           0 :       inner_vlan = sw->sub.eth.inner_vlan_id;
     844           0 :       outer_proto = inner_proto = ETH_P_8021Q;
     845           0 :       if (1 == sw->sub.eth.flags.dot1ad)
     846           0 :         outer_proto = ETH_P_8021AD;
     847             : 
     848           0 :       LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
     849             :                          sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
     850             :                          inner_vlan, format_vnet_sw_if_index_name, vnm,
     851             :                          hw->sw_if_index);
     852             : 
     853           0 :       parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
     854           0 :       if (INDEX_INVALID == parent_if_index)
     855             :         {
     856           0 :           LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
     857             :                             format_vnet_sw_if_index_name, vnet_get_main (),
     858             :                             sw->sup_sw_if_index);
     859           0 :           return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     860             :         }
     861           0 :       lip = lcp_itf_pair_get (parent_if_index);
     862           0 :       if (!lip)
     863             :         {
     864           0 :           LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
     865             :                             "sub-interface without an LCP on the parent");
     866           0 :           return VNET_API_ERROR_INVALID_ARGUMENT;
     867             :         }
     868           0 :       LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
     869           0 :       parent_vif_index = lip->lip_vif_index;
     870             : 
     871             :       /*
     872             :        * see if the requested host interface has already been created
     873             :        */
     874           0 :       orig_ns_fd = ns_fd = -1;
     875           0 :       err = NULL;
     876             : 
     877           0 :       if (ns && ns[0] != 0)
     878             :         {
     879           0 :           orig_ns_fd = clib_netns_open (NULL /* self */);
     880           0 :           ns_fd = clib_netns_open (ns);
     881           0 :           if (orig_ns_fd == -1 || ns_fd == -1)
     882           0 :             goto socket_close;
     883             : 
     884           0 :           clib_setns (ns_fd);
     885             :         }
     886             : 
     887           0 :       vif_index = if_nametoindex ((const char *) host_if_name);
     888             : 
     889           0 :       if (!vif_index)
     890             :         {
     891             :           /*
     892             :            * no existing host interface, create it now
     893             :            */
     894             : 
     895             :           /*
     896             :            * Find the parent tap:
     897             :            * - if this is an outer VLAN, use the pair from the parent phy
     898             :            * - if this is an inner VLAN, find the pair from the outer sub-int,
     899             :            * which must exist.
     900             :            */
     901           0 :           if (inner_vlan)
     902             :             {
     903             :               index_t linux_parent_if_index;
     904             :               const lcp_itf_pair_t *llip;
     905             : 
     906           0 :               vlan = inner_vlan;
     907           0 :               proto = inner_proto;
     908           0 :               linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
     909           0 :                 hw->sw_if_index, sw->sub.eth.outer_vlan_id,
     910           0 :                 sw->sub.eth.flags.dot1ad);
     911           0 :               if (INDEX_INVALID == linux_parent_if_index ||
     912           0 :                   !(llip = lcp_itf_pair_get (linux_parent_if_index)))
     913             :                 {
     914           0 :                   LCP_ITF_PAIR_ERR (
     915             :                     "pair_create: can't find LCP for outer vlan %d "
     916             :                     "proto %s on %U",
     917             :                     outer_vlan,
     918             :                     outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
     919             :                     format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
     920           0 :                   err = clib_error_return (0, "parent pair not found");
     921           0 :                   goto socket_close;
     922             :                 }
     923             : 
     924           0 :               LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
     925             :                                 format_lcp_itf_pair, llip);
     926           0 :               parent_vif_index = llip->lip_vif_index;
     927             :             }
     928             :           else
     929             :             {
     930           0 :               vlan = outer_vlan;
     931           0 :               proto = outer_proto;
     932             :             }
     933             : 
     934           0 :           err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
     935             :                                            (const char *) host_if_name);
     936           0 :           if (err != 0)
     937             :             {
     938           0 :               LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
     939             :                                 "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
     940             :                                 "04x,vlan:%u) name:'%s'",
     941             :                                 outer_proto, outer_vlan, inner_proto,
     942             :                                 inner_vlan, host_if_name);
     943             :             }
     944             : 
     945           0 :           if (!err)
     946           0 :             vif_index = if_nametoindex ((char *) host_if_name);
     947             :         }
     948             : 
     949             :       /*
     950             :        * create a sub-interface on the tap
     951             :        */
     952           0 :       if (!err &&
     953           0 :           vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
     954           0 :                                      sw->sub.eth.raw_flags, inner_vlan,
     955             :                                      outer_vlan, &host_sw_if_index))
     956             :         {
     957           0 :           LCP_ITF_PAIR_ERR (
     958             :             "pair_create: failed to create tap subint: %d.%d on %U",
     959             :             outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
     960             :             lip->lip_host_sw_if_index);
     961           0 :           err = clib_error_return (
     962             :             0, "failed to create tap subint: %d.%d. on %U", outer_vlan,
     963             :             inner_vlan, format_vnet_sw_if_index_name, vnm,
     964             :             lip->lip_host_sw_if_index);
     965             :         }
     966             : 
     967           0 :     socket_close:
     968           0 :       if (orig_ns_fd != -1)
     969             :         {
     970           0 :           clib_setns (orig_ns_fd);
     971           0 :           close (orig_ns_fd);
     972             :         }
     973           0 :       if (ns_fd != -1)
     974           0 :         close (ns_fd);
     975             : 
     976           0 :       if (err)
     977           0 :         return VNET_API_ERROR_INVALID_ARGUMENT;
     978             :     }
     979             :   else
     980             :     {
     981           0 :       tap_create_if_args_t args = {
     982           0 :         .num_rx_queues = clib_max (1, vlib_num_workers ()),
     983             :         .num_tx_queues = 1,
     984           0 :         .id = hw->hw_if_index,
     985             :         .sw_if_index = ~0,
     986             :         .rx_ring_sz = 256,
     987             :         .tx_ring_sz = 256,
     988             :         .host_if_name = host_if_name,
     989             :         .host_namespace = 0,
     990             :         .rv = 0,
     991             :         .error = NULL,
     992             :       };
     993             :       ethernet_interface_t *ei;
     994             :       u32 host_sw_mtu_size;
     995             : 
     996           0 :       if (host_if_type == LCP_ITF_HOST_TUN)
     997           0 :         args.tap_flags |= TAP_FLAG_TUN;
     998             :       else
     999             :         {
    1000           0 :           ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
    1001           0 :           mac_address_copy (&args.host_mac_addr, &ei->address.mac);
    1002             :         }
    1003             : 
    1004             :       /*
    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.
    1011             :        */
    1012           0 :       host_sw_mtu_size = sw->mtu[VNET_MTU_L3];
    1013           0 :       if (host_sw_mtu_size)
    1014             :         {
    1015           0 :           args.host_mtu_set = 1;
    1016           0 :           args.host_mtu_size = host_sw_mtu_size;
    1017             :         }
    1018             :       else
    1019           0 :         host_sw_mtu_size = ETHERNET_MAX_PACKET_BYTES;
    1020             : 
    1021           0 :       if (ns && ns[0] != 0)
    1022           0 :         args.host_namespace = ns;
    1023             : 
    1024           0 :       vm = vlib_get_main ();
    1025           0 :       tap_create_if (vm, &args);
    1026           0 :       if (args.rv < 0)
    1027             :         {
    1028           0 :           LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
    1029             :                             args.rv);
    1030           0 :           clib_error_free (args.error);
    1031           0 :           return args.rv;
    1032             :         }
    1033             : 
    1034           0 :       vnet_sw_interface_set_mtu (vnm, args.sw_if_index, host_sw_mtu_size);
    1035             : 
    1036             :       /*
    1037             :        * get the hw and ethernet of the tap
    1038             :        */
    1039           0 :       hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
    1040           0 :       virtio_main_t *mm = &virtio_main;
    1041           0 :       virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
    1042             : 
    1043             :       /*
    1044             :        * Leave the TAP permanently up on the VPP side.
    1045             :        * This TAP will be shared by many sub-interface.
    1046             :        * Therefore we can't use it to manage admin state.
    1047             :        * force the tap in promiscuous mode.
    1048             :        */
    1049           0 :       if (host_if_type == LCP_ITF_HOST_TAP)
    1050             :         {
    1051           0 :           ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
    1052           0 :           ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
    1053             :         }
    1054             : 
    1055           0 :       vif_index = vif->ifindex;
    1056           0 :       host_sw_if_index = args.sw_if_index;
    1057             :     }
    1058             : 
    1059           0 :   if (!vif_index)
    1060             :     {
    1061           0 :       LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
    1062             :                          format_vnet_sw_if_index_name, vnet_get_main (),
    1063             :                          phy_sw_if_index, format_vnet_sw_if_index_name,
    1064             :                          vnet_get_main (), host_sw_if_index, host_if_name);
    1065           0 :       return -1;
    1066             :     }
    1067             : 
    1068           0 :   LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
    1069             :                      vnet_get_main (), phy_sw_if_index,
    1070             :                      format_vnet_sw_if_index_name, vnet_get_main (),
    1071             :                      host_sw_if_index, host_if_name);
    1072           0 :   lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
    1073             :                     host_if_type, ns);
    1074             : 
    1075             :   /*
    1076             :    * Copy the link state from VPP into the host side.
    1077             :    * The TAP is shared by many interfaces, always keep it up.
    1078             :    * This controls whether the host can RX/TX.
    1079             :    */
    1080           0 :   sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
    1081           0 :   lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
    1082           0 :   LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
    1083             :                      format_lcp_itf_pair, lip, sw->flags, hw->flags);
    1084           0 :   vnet_sw_interface_admin_up (vnm, host_sw_if_index);
    1085           0 :   lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
    1086             : 
    1087             :   /*
    1088             :    * Reflect current link state and link speed of the hardware interface on the
    1089             :    * TAP interface.
    1090             :    */
    1091           0 :   if (host_if_type == LCP_ITF_HOST_TAP &&
    1092           0 :       !vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
    1093             :     {
    1094           0 :       hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
    1095           0 :       lcp_itf_pair_link_up_down (vnm, hw->hw_if_index, hw->flags);
    1096             :     }
    1097             : 
    1098           0 :   if (host_sw_if_indexp)
    1099           0 :     *host_sw_if_indexp = host_sw_if_index;
    1100             : 
    1101           0 :   return 0;
    1102             : }
    1103             : 
    1104             : static walk_rc_t
    1105           0 : lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
    1106             : {
    1107             :   lcp_itf_pair_t *lip;
    1108             : 
    1109           0 :   lip = lcp_itf_pair_get (lipi);
    1110             : 
    1111           0 :   lip->lip_flags |= LIP_FLAG_STALE;
    1112             : 
    1113           0 :   return (WALK_CONTINUE);
    1114             : }
    1115             : 
    1116             : int
    1117           0 : lcp_itf_pair_replace_begin (void)
    1118             : {
    1119           0 :   lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
    1120             : 
    1121           0 :   return (0);
    1122             : }
    1123             : 
    1124             : typedef struct lcp_itf_pair_sweep_ctx_t_
    1125             : {
    1126             :   index_t *indicies;
    1127             : } lcp_itf_pair_sweep_ctx_t;
    1128             : 
    1129             : static walk_rc_t
    1130           0 : lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
    1131             : {
    1132           0 :   lcp_itf_pair_sweep_ctx_t *ctx = arg;
    1133             :   lcp_itf_pair_t *lip;
    1134             : 
    1135           0 :   lip = lcp_itf_pair_get (lipi);
    1136             : 
    1137           0 :   if (lip->lip_flags & LIP_FLAG_STALE)
    1138           0 :     vec_add1 (ctx->indicies, lipi);
    1139             : 
    1140           0 :   return (WALK_CONTINUE);
    1141             : }
    1142             : 
    1143             : int
    1144           0 : lcp_itf_pair_replace_end (void)
    1145             : {
    1146           0 :   lcp_itf_pair_sweep_ctx_t ctx = {
    1147             :     .indicies = NULL,
    1148             :   };
    1149             :   index_t *lipi;
    1150             : 
    1151           0 :   lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
    1152             : 
    1153           0 :   vec_foreach (lipi, ctx.indicies)
    1154           0 :     lcp_itf_pair_delete_by_index (*lipi);
    1155             : 
    1156           0 :   vec_free (ctx.indicies);
    1157           0 :   return (0);
    1158             : }
    1159             : 
    1160             : static clib_error_t *
    1161          37 : lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
    1162             : {
    1163             :   vnet_hw_interface_t *hi;
    1164             :   vnet_sw_interface_t *si;
    1165             :   index_t lipi;
    1166             :   lcp_itf_pair_t *lip;
    1167             : 
    1168          37 :   hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
    1169          37 :   if (!hi)
    1170           0 :     return 0;
    1171             : 
    1172          37 :   lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
    1173          37 :   if (lipi == INDEX_INVALID)
    1174          35 :     return 0;
    1175             : 
    1176           2 :   lip = lcp_itf_pair_get (lipi);
    1177           2 :   si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
    1178           2 :   if (!si)
    1179           0 :     return 0;
    1180             : 
    1181           2 :   if (!lcp_main.test_mode)
    1182             :     {
    1183           0 :       tap_set_carrier (si->hw_if_index,
    1184             :                        (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
    1185             : 
    1186           0 :       if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP &&
    1187           0 :           hi->link_speed != UINT32_MAX)
    1188             :         {
    1189           0 :           tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
    1190             :         }
    1191             :     }
    1192             : 
    1193           2 :   return 0;
    1194             : }
    1195             : 
    1196           6 : VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
    1197             : 
    1198             : static clib_error_t *
    1199           2 : lcp_interface_init (vlib_main_t *vm)
    1200             : {
    1201           2 :   vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
    1202             : 
    1203             :   /* punt IKE */
    1204           2 :   vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
    1205             :                       "linux-cp-punt");
    1206           2 :   vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP6_SPI_UDP_0],
    1207             :                       "linux-cp-punt");
    1208             : 
    1209             :   /* punt all unknown ports */
    1210           2 :   udp_punt_unknown (vm, 0, 1);
    1211           2 :   udp_punt_unknown (vm, 1, 1);
    1212           2 :   tcp_punt_unknown (vm, 0, 1);
    1213           2 :   tcp_punt_unknown (vm, 1, 1);
    1214             : 
    1215           2 :   lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
    1216             : 
    1217           2 :   return NULL;
    1218             : }
    1219             : 
    1220           4 : VLIB_INIT_FUNCTION (lcp_interface_init) = {
    1221             :   .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
    1222             : };
    1223             : 
    1224             : /*
    1225             :  * fd.io coding-style-patch-verification: ON
    1226             :  *
    1227             :  * Local Variables:
    1228             :  * eval: (c-set-style "gnu")
    1229             :  * End:
    1230             :  */

Generated by: LCOV version 1.14