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