aeff9a1131e75146ff6ab69ef73beaf4585aa107
[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, %s}", format_vnet_sw_if_index_name,
425                      vnet_get_main (), lip->lip_phy_sw_if_index,
426                      format_vnet_sw_if_index_name, vnet_get_main (),
427                      lip->lip_host_sw_if_index, lip->lip_host_name);
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 void
514 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
515 {
516   u32 api;
517
518   pool_foreach_index (api, lcp_itf_pair_pool)
519     {
520       if (!cb (api, ctx))
521         break;
522     };
523 }
524
525 typedef struct lcp_itf_pair_names_t_
526 {
527   u8 *lipn_host_name;
528   u8 *lipn_phy_name;
529   u8 *lipn_namespace;
530   u32 lipn_phy_sw_if_index;
531 } lcp_itf_pair_names_t;
532
533 static lcp_itf_pair_names_t *lipn_names;
534
535 static clib_error_t *
536 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
537 {
538   u8 *host, *phy;
539   u8 *ns;
540   u8 *default_ns;
541
542   host = phy = ns = default_ns = NULL;
543
544   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
545     {
546       vec_reset_length (host);
547
548       if (unformat (input, "pair %s %s %s", &phy, &host, &ns))
549         {
550           lcp_itf_pair_names_t *lipn;
551
552           if (vec_len (ns) > LCP_NS_LEN)
553             {
554               return clib_error_return (0,
555                                         "linux-cp namespace must"
556                                         " be less than %d characters",
557                                         LCP_NS_LEN);
558             }
559
560           vec_add2 (lipn_names, lipn, 1);
561
562           lipn->lipn_host_name = vec_dup (host);
563           lipn->lipn_phy_name = vec_dup (phy);
564           lipn->lipn_namespace = vec_dup (ns);
565         }
566       else if (unformat (input, "pair %v %v", &phy, &host))
567         {
568           lcp_itf_pair_names_t *lipn;
569
570           vec_add2 (lipn_names, lipn, 1);
571
572           lipn->lipn_host_name = vec_dup (host);
573           lipn->lipn_phy_name = vec_dup (phy);
574           lipn->lipn_namespace = 0;
575         }
576       else if (unformat (input, "default netns %v", &default_ns))
577         {
578           vec_add1 (default_ns, 0);
579           if (lcp_set_default_ns (default_ns) < 0)
580             {
581               return clib_error_return (0,
582                                         "linux-cp default namespace must"
583                                         " be less than %d characters",
584                                         LCP_NS_LEN);
585             }
586         }
587       else if (unformat (input, "interface-auto-create"))
588         lcp_set_auto_intf (1 /* is_auto */);
589       else
590         return clib_error_return (0, "interfaces not found");
591     }
592
593   vec_free (host);
594   vec_free (phy);
595   vec_free (default_ns);
596
597   return NULL;
598 }
599
600 VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
601
602 /*
603  * Returns 1 if the tap name is valid.
604  * Returns 0 if the tap name is invalid.
605  */
606 static int
607 lcp_validate_if_name (u8 *name)
608 {
609   int len;
610   char *p;
611
612   p = (char *) name;
613   len = clib_strnlen (p, IFNAMSIZ);
614   if (len >= IFNAMSIZ)
615     return 0;
616
617   for (; *p; ++p)
618     {
619       if (isalnum (*p))
620         continue;
621
622       switch (*p)
623         {
624         case '-':
625         case '_':
626         case '%':
627         case '@':
628         case ':':
629         case '.':
630           continue;
631         }
632
633       return 0;
634     }
635
636   return 1;
637 }
638
639 static void
640 lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state)
641 {
642   int curr_ns_fd, vif_ns_fd;
643
644   if (!lip)
645     return;
646
647   curr_ns_fd = vif_ns_fd = -1;
648
649   if (lip->lip_namespace)
650     {
651       curr_ns_fd = clib_netns_open (NULL /* self */);
652       vif_ns_fd = clib_netns_open (lip->lip_namespace);
653       if (vif_ns_fd != -1)
654         clib_setns (vif_ns_fd);
655     }
656
657   vnet_netlink_set_link_state (lip->lip_vif_index, state);
658
659   if (vif_ns_fd != -1)
660     close (vif_ns_fd);
661
662   if (curr_ns_fd != -1)
663     {
664       clib_setns (curr_ns_fd);
665       close (curr_ns_fd);
666     }
667
668   return;
669 }
670
671 typedef struct
672 {
673   u32 vlan;
674   bool dot1ad;
675
676   u32 matched_sw_if_index;
677 } lcp_itf_match_t;
678
679 static walk_rc_t
680 lcp_itf_pair_find_walk (vnet_main_t *vnm, u32 sw_if_index, void *arg)
681 {
682   lcp_itf_match_t *match = arg;
683   const vnet_sw_interface_t *sw;
684
685   sw = vnet_get_sw_interface (vnm, sw_if_index);
686   if (sw && (sw->sub.eth.inner_vlan_id == 0) &&
687       (sw->sub.eth.outer_vlan_id == match->vlan) &&
688       (sw->sub.eth.flags.dot1ad == match->dot1ad))
689     {
690       LCP_ITF_PAIR_DBG ("find_walk: found match outer %d dot1ad %d "
691                         "inner-dot1q %d: interface %U",
692                         sw->sub.eth.outer_vlan_id, sw->sub.eth.flags.dot1ad,
693                         sw->sub.eth.inner_vlan_id,
694                         format_vnet_sw_if_index_name, vnet_get_main (),
695                         sw->sw_if_index);
696       match->matched_sw_if_index = sw->sw_if_index;
697       return WALK_STOP;
698     }
699
700   return WALK_CONTINUE;
701 }
702
703 /* Return the index of the sub-int on the phy that has the given vlan and
704  * proto,
705  */
706 static index_t
707 lcp_itf_pair_find_by_outer_vlan (u32 sup_if_index, u16 vlan, bool dot1ad)
708 {
709   lcp_itf_match_t match;
710   const vnet_hw_interface_t *hw;
711
712   match.vlan = vlan;
713   match.dot1ad = dot1ad;
714   match.matched_sw_if_index = INDEX_INVALID;
715   hw = vnet_get_sup_hw_interface (vnet_get_main (), sup_if_index);
716
717   vnet_hw_interface_walk_sw (vnet_get_main (), hw->hw_if_index,
718                              lcp_itf_pair_find_walk, &match);
719
720   if (match.matched_sw_if_index >= vec_len (lip_db_by_phy))
721     return INDEX_INVALID;
722
723   return lip_db_by_phy[match.matched_sw_if_index];
724 }
725
726 int
727 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
728                      lip_host_type_t host_if_type, u8 *ns,
729                      u32 *host_sw_if_indexp)
730 {
731   vlib_main_t *vm;
732   vnet_main_t *vnm;
733   u32 vif_index = 0, host_sw_if_index;
734   const vnet_sw_interface_t *sw;
735   const vnet_hw_interface_t *hw;
736   const lcp_itf_pair_t *lip;
737
738   if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
739     {
740       LCP_ITF_PAIR_ERR ("pair_create: invalid phy index %u", phy_sw_if_index);
741       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
742     }
743
744   if (!lcp_validate_if_name (host_if_name))
745     {
746       LCP_ITF_PAIR_ERR ("pair_create: invalid host-if-name '%s'",
747                         host_if_name);
748       return VNET_API_ERROR_INVALID_ARGUMENT;
749     }
750
751   vnm = vnet_get_main ();
752   sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
753   hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
754   if (!sw || !hw)
755     {
756       LCP_ITF_PAIR_ERR ("pair_create: invalid interface");
757       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
758     }
759
760   /*
761    * Use interface-specific netns if supplied.
762    * Otherwise, use netns if defined, otherwise use the OS default.
763    */
764   if (ns == 0 || ns[0] == 0)
765     ns = lcp_get_default_ns ();
766
767   /* sub interfaces do not need a tap created */
768   if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
769     {
770       index_t parent_if_index;
771       int orig_ns_fd, ns_fd;
772       clib_error_t *err;
773       u16 outer_vlan, inner_vlan;
774       u16 outer_proto, inner_proto;
775       u16 vlan, proto;
776       u32 parent_vif_index;
777
778       // TODO(pim) replace with vnet_sw_interface_supports_addressing()
779       if (sw->type == VNET_SW_INTERFACE_TYPE_SUB &&
780           sw->sub.eth.flags.exact_match == 0)
781         {
782           LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
783                             "sub-interface without exact-match set");
784           return VNET_API_ERROR_INVALID_ARGUMENT;
785         }
786
787       outer_vlan = sw->sub.eth.outer_vlan_id;
788       inner_vlan = sw->sub.eth.inner_vlan_id;
789       outer_proto = inner_proto = ETH_P_8021Q;
790       if (1 == sw->sub.eth.flags.dot1ad)
791         outer_proto = ETH_P_8021AD;
792
793       LCP_ITF_PAIR_INFO ("pair_create: subif: dot1%s outer %d inner %d on %U",
794                          sw->sub.eth.flags.dot1ad ? "ad" : "q", outer_vlan,
795                          inner_vlan, format_vnet_sw_if_index_name, vnm,
796                          hw->sw_if_index);
797
798       parent_if_index = lcp_itf_pair_find_by_phy (sw->sup_sw_if_index);
799       if (INDEX_INVALID == parent_if_index)
800         {
801           LCP_ITF_PAIR_ERR ("pair_create: can't find LCP for %U",
802                             format_vnet_sw_if_index_name, vnet_get_main (),
803                             sw->sup_sw_if_index);
804           return VNET_API_ERROR_INVALID_SW_IF_INDEX;
805         }
806       lip = lcp_itf_pair_get (parent_if_index);
807       if (!lip)
808         {
809           LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a "
810                             "sub-interface without an LCP on the parent");
811           return VNET_API_ERROR_INVALID_ARGUMENT;
812         }
813       LCP_ITF_PAIR_DBG ("pair_create: parent %U", format_lcp_itf_pair, lip);
814       parent_vif_index = lip->lip_vif_index;
815
816       /*
817        * see if the requested host interface has already been created
818        */
819       orig_ns_fd = ns_fd = -1;
820       err = NULL;
821
822       if (ns && ns[0] != 0)
823         {
824           orig_ns_fd = clib_netns_open (NULL /* self */);
825           ns_fd = clib_netns_open (ns);
826           if (orig_ns_fd == -1 || ns_fd == -1)
827             goto socket_close;
828
829           clib_setns (ns_fd);
830         }
831
832       vif_index = if_nametoindex ((const char *) host_if_name);
833
834       if (!vif_index)
835         {
836           /*
837            * no existing host interface, create it now
838            */
839
840           /*
841            * Find the parent tap:
842            * - if this is an outer VLAN, use the pair from the parent phy
843            * - if this is an inner VLAN, find the pair from the outer sub-int,
844            * which must exist.
845            */
846           if (inner_vlan)
847             {
848               index_t linux_parent_if_index;
849               const lcp_itf_pair_t *llip;
850
851               vlan = inner_vlan;
852               proto = inner_proto;
853               linux_parent_if_index = lcp_itf_pair_find_by_outer_vlan (
854                 hw->sw_if_index, sw->sub.eth.outer_vlan_id,
855                 sw->sub.eth.flags.dot1ad);
856               if (INDEX_INVALID == linux_parent_if_index ||
857                   !(llip = lcp_itf_pair_get (linux_parent_if_index)))
858                 {
859                   LCP_ITF_PAIR_ERR (
860                     "pair_create: can't find LCP for outer vlan %d "
861                     "proto %s on %U",
862                     outer_vlan,
863                     outer_proto == ETH_P_8021AD ? "dot1ad" : "dot1q",
864                     format_vnet_sw_if_index_name, vnm, hw->sw_if_index);
865                   err = clib_error_return (0, "parent pair not found");
866                   goto socket_close;
867                 }
868
869               LCP_ITF_PAIR_DBG ("pair_create: linux parent %U",
870                                 format_lcp_itf_pair, llip);
871               parent_vif_index = llip->lip_vif_index;
872             }
873           else
874             {
875               vlan = outer_vlan;
876               proto = outer_proto;
877             }
878
879           err = lcp_netlink_add_link_vlan (parent_vif_index, vlan, proto,
880                                            (const char *) host_if_name);
881           if (err != 0)
882             {
883               LCP_ITF_PAIR_ERR ("pair_create: cannot create link "
884                                 "outer(proto:0x%04x,vlan:%u).inner(proto:0x%"
885                                 "04x,vlan:%u) name:'%s'",
886                                 outer_proto, outer_vlan, inner_proto,
887                                 inner_vlan, host_if_name);
888             }
889
890           if (!err)
891             vif_index = if_nametoindex ((char *) host_if_name);
892         }
893
894       /*
895        * create a sub-interface on the tap
896        */
897       if (!err &&
898           vnet_create_sub_interface (lip->lip_host_sw_if_index, sw->sub.id,
899                                      sw->sub.eth.raw_flags, inner_vlan,
900                                      outer_vlan, &host_sw_if_index))
901         {
902           LCP_ITF_PAIR_ERR (
903             "pair_create: failed to create tap subint: %d.%d on %U",
904             outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm,
905             lip->lip_host_sw_if_index);
906           err = clib_error_return (
907             0, "failed to create tap subinti: %d.%d. on %U", outer_vlan,
908             inner_vlan, format_vnet_sw_if_index_name, vnm,
909             lip->lip_host_sw_if_index);
910         }
911
912     socket_close:
913       if (orig_ns_fd != -1)
914         {
915           clib_setns (orig_ns_fd);
916           close (orig_ns_fd);
917         }
918       if (ns_fd != -1)
919         close (ns_fd);
920
921       if (err)
922         return VNET_API_ERROR_INVALID_ARGUMENT;
923     }
924   else
925     {
926       tap_create_if_args_t args = {
927         .num_rx_queues = clib_max (1, vlib_num_workers ()),
928         .id = hw->hw_if_index,
929         .sw_if_index = ~0,
930         .rx_ring_sz = 256,
931         .tx_ring_sz = 256,
932         .host_if_name = host_if_name,
933         .host_namespace = 0,
934       };
935       ethernet_interface_t *ei;
936
937       if (host_if_type == LCP_ITF_HOST_TUN)
938         args.tap_flags |= TAP_FLAG_TUN;
939       else
940         {
941           ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
942           mac_address_copy (&args.host_mac_addr, &ei->address.mac);
943         }
944
945       if (sw->mtu[VNET_MTU_L3])
946         {
947           args.host_mtu_set = 1;
948           args.host_mtu_size = sw->mtu[VNET_MTU_L3];
949         }
950
951       if (ns && ns[0] != 0)
952         args.host_namespace = ns;
953
954       vm = vlib_get_main ();
955       tap_create_if (vm, &args);
956
957       if (args.rv < 0)
958         {
959           LCP_ITF_PAIR_ERR ("pair_create: could not create tap, retval:%d",
960                             args.rv);
961           return args.rv;
962         }
963
964       /*
965        * The TAP interface does copy forward the host MTU based on the VPP
966        * interface's L3 MTU, but it should also ensure that the VPP tap
967        * interface has an MTU that is greater-or-equal to those. Considering
968        * users can set the interfaces at runtime (set interface mtu packet ...)
969        * ensure that the tap MTU is large enough, taking the VPP interface L3
970        * if it's set, and otherwise a sensible default.
971        */
972       if (sw->mtu[VNET_MTU_L3])
973         vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
974                                    sw->mtu[VNET_MTU_L3]);
975       else
976         vnet_sw_interface_set_mtu (vnm, args.sw_if_index,
977                                    ETHERNET_MAX_PACKET_BYTES);
978
979       /*
980        * get the hw and ethernet of the tap
981        */
982       hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
983       virtio_main_t *mm = &virtio_main;
984       virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
985
986       /*
987        * Leave the TAP permanently up on the VPP side.
988        * This TAP will be shared by many sub-interface.
989        * Therefore we can't use it to manage admin state.
990        * force the tap in promiscuous mode.
991        */
992       if (host_if_type == LCP_ITF_HOST_TAP)
993         {
994           ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
995           ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
996         }
997
998       vif_index = vif->ifindex;
999       host_sw_if_index = args.sw_if_index;
1000     }
1001
1002   if (!vif_index)
1003     {
1004       LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
1005                          format_vnet_sw_if_index_name, vnet_get_main (),
1006                          phy_sw_if_index, format_vnet_sw_if_index_name,
1007                          vnet_get_main (), host_sw_if_index, host_if_name);
1008       return -1;
1009     }
1010
1011   LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
1012                      vnet_get_main (), phy_sw_if_index,
1013                      format_vnet_sw_if_index_name, vnet_get_main (),
1014                      host_sw_if_index, host_if_name);
1015   lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
1016                     host_if_type, ns);
1017
1018   /*
1019    * Copy the link state from VPP into the host side.
1020    * The TAP is shared by many interfaces, always keep it up.
1021    * This controls whether the host can RX/TX.
1022    */
1023
1024   lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
1025   LCP_ITF_PAIR_INFO ("pair create: %U sw-flags %u hw-flags %u",
1026                      format_lcp_itf_pair, lip, sw->flags, hw->flags);
1027   vnet_sw_interface_admin_up (vnm, host_sw_if_index);
1028   lcp_itf_set_link_state (lip, sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1029
1030   if (host_sw_if_indexp)
1031     *host_sw_if_indexp = host_sw_if_index;
1032
1033   return 0;
1034 }
1035
1036 static walk_rc_t
1037 lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
1038 {
1039   lcp_itf_pair_t *lip;
1040
1041   lip = lcp_itf_pair_get (lipi);
1042
1043   lip->lip_flags |= LIP_FLAG_STALE;
1044
1045   return (WALK_CONTINUE);
1046 }
1047
1048 int
1049 lcp_itf_pair_replace_begin (void)
1050 {
1051   lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
1052
1053   return (0);
1054 }
1055
1056 typedef struct lcp_itf_pair_sweep_ctx_t_
1057 {
1058   index_t *indicies;
1059 } lcp_itf_pair_sweep_ctx_t;
1060
1061 static walk_rc_t
1062 lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
1063 {
1064   lcp_itf_pair_sweep_ctx_t *ctx = arg;
1065   lcp_itf_pair_t *lip;
1066
1067   lip = lcp_itf_pair_get (lipi);
1068
1069   if (lip->lip_flags & LIP_FLAG_STALE)
1070     vec_add1 (ctx->indicies, lipi);
1071
1072   return (WALK_CONTINUE);
1073 }
1074
1075 int
1076 lcp_itf_pair_replace_end (void)
1077 {
1078   lcp_itf_pair_sweep_ctx_t ctx = {
1079     .indicies = NULL,
1080   };
1081   index_t *lipi;
1082
1083   lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
1084
1085   vec_foreach (lipi, ctx.indicies)
1086     lcp_itf_pair_delete_by_index (*lipi);
1087
1088   vec_free (ctx.indicies);
1089   return (0);
1090 }
1091
1092 static uword
1093 lcp_itf_pair_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
1094                       vlib_frame_t *f)
1095 {
1096   uword *event_data = 0;
1097   uword *lipn_index;
1098
1099   while (1)
1100     {
1101       vlib_process_wait_for_event (vm);
1102
1103       vlib_process_get_events (vm, &event_data);
1104
1105       vec_foreach (lipn_index, event_data)
1106         {
1107           lcp_itf_pair_names_t *lipn;
1108
1109           lipn = &lipn_names[*lipn_index];
1110           lcp_itf_pair_create (lipn->lipn_phy_sw_if_index,
1111                                lipn->lipn_host_name, LCP_ITF_HOST_TAP,
1112                                lipn->lipn_namespace, NULL);
1113         }
1114
1115       vec_reset_length (event_data);
1116     }
1117
1118   return 0;
1119 }
1120
1121 VLIB_REGISTER_NODE (lcp_itf_pair_process_node, static) = {
1122   .function = lcp_itf_pair_process,
1123   .name = "linux-cp-itf-process",
1124   .type = VLIB_NODE_TYPE_PROCESS,
1125 };
1126
1127 static clib_error_t *
1128 lcp_itf_phy_add (vnet_main_t *vnm, u32 sw_if_index, u32 is_create)
1129 {
1130   lcp_itf_pair_names_t *lipn;
1131   vlib_main_t *vm = vlib_get_main ();
1132   vnet_hw_interface_t *hw;
1133
1134   if (!is_create || vnet_sw_interface_is_sub (vnm, sw_if_index))
1135     return NULL;
1136
1137   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1138
1139   vec_foreach (lipn, lipn_names)
1140     {
1141       if (!vec_cmp (hw->name, lipn->lipn_phy_name))
1142         {
1143           lipn->lipn_phy_sw_if_index = sw_if_index;
1144
1145           vlib_process_signal_event (vm, lcp_itf_pair_process_node.index, 0,
1146                                      lipn - lipn_names);
1147           break;
1148         }
1149     }
1150
1151   return NULL;
1152 }
1153
1154 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_phy_add);
1155
1156 static clib_error_t *
1157 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1158 {
1159   vnet_hw_interface_t *hi;
1160   vnet_sw_interface_t *si;
1161   index_t lipi;
1162   lcp_itf_pair_t *lip;
1163
1164   hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
1165   if (!hi)
1166     return 0;
1167
1168   lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
1169   if (lipi == INDEX_INVALID)
1170     return 0;
1171
1172   lip = lcp_itf_pair_get (lipi);
1173   si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
1174   if (!si)
1175     return 0;
1176
1177   if (!lcp_main.test_mode)
1178     {
1179       tap_set_carrier (si->hw_if_index,
1180                        (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
1181
1182       if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
1183         {
1184           tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
1185         }
1186     }
1187
1188   return 0;
1189 }
1190
1191 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1192
1193 static clib_error_t *
1194 lcp_itf_pair_init (vlib_main_t *vm)
1195 {
1196   vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1197
1198   /* punt IKE */
1199   vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1200                       "linux-cp-punt");
1201
1202   /* punt all unknown ports */
1203   udp_punt_unknown (vm, 0, 1);
1204   udp_punt_unknown (vm, 1, 1);
1205   tcp_punt_unknown (vm, 0, 1);
1206   tcp_punt_unknown (vm, 1, 1);
1207
1208   lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1209
1210   return NULL;
1211 }
1212
1213 VLIB_INIT_FUNCTION (lcp_itf_pair_init) = {
1214   .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1215 };
1216
1217 /*
1218  * fd.io coding-style-patch-verification: ON
1219  *
1220  * Local Variables:
1221  * eval: (c-set-style "gnu")
1222  * End:
1223  */