3fc91179cd1c330aa4990f9cd49a684d2d3745bc
[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 <sched.h>
18 #include <fcntl.h>
19 #include <ctype.h>
20 #include <sys/socket.h>
21 #include <net/if.h>
22
23 #include <linux-cp/lcp_interface.h>
24 #include <netlink/route/link/vlan.h>
25
26 #include <vnet/plugin/plugin.h>
27 #include <vnet/plugin/plugin.h>
28
29 #include <vnet/ip/ip_punt_drop.h>
30 #include <vnet/fib/fib_table.h>
31 #include <vnet/adj/adj_mcast.h>
32 #include <vnet/udp/udp.h>
33 #include <vnet/tcp/tcp.h>
34 #include <vnet/devices/tap/tap.h>
35 #include <vnet/devices/virtio/virtio.h>
36 #include <vnet/devices/netlink.h>
37 #include <vlibapi/api_helper_macros.h>
38 #include <vnet/ipsec/ipsec_punt.h>
39
40 static vlib_log_class_t lcp_itf_pair_logger;
41
42 /**
43  * Pool of LIP objects
44  */
45 lcp_itf_pair_t *lcp_itf_pair_pool;
46
47 u32
48 lcp_itf_num_pairs (void)
49 {
50   return pool_elts (lcp_itf_pair_pool);
51 }
52
53 /**
54  * DBs of interface-pair objects:
55  *  - key'd by VIF (linux ID)
56  *  - key'd by VPP's physical interface
57  *  - number of shared uses of VPP's tap/host interface
58  */
59 static uword *lip_db_by_vif;
60 index_t *lip_db_by_phy;
61 u32 *lip_db_by_host;
62
63 /**
64  * vector of virtual function table
65  */
66 static lcp_itf_pair_vft_t *lcp_itf_vfts = NULL;
67
68 void
69 lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft)
70 {
71   vec_add1 (lcp_itf_vfts, *lcp_itf_vft);
72 }
73
74 #define LCP_ITF_PAIR_DBG(...)                                                 \
75   vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
76
77 #define LCP_ITF_PAIR_INFO(...)                                                \
78   vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
79
80 u8 *
81 format_lcp_itf_pair (u8 *s, va_list *args)
82 {
83   vnet_main_t *vnm = vnet_get_main ();
84   lcp_itf_pair_t *lip = va_arg (*args, lcp_itf_pair_t *);
85   vnet_sw_interface_t *swif_phy;
86   vnet_sw_interface_t *swif_host;
87
88   s = format (s, "itf-pair: [%d]", lip - lcp_itf_pair_pool);
89
90   swif_phy = vnet_get_sw_interface_or_null (vnm, lip->lip_phy_sw_if_index);
91   if (!swif_phy)
92     s = format (s, " <no-phy-if>");
93   else
94     s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_phy);
95
96   swif_host = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
97   if (!swif_host)
98     s = format (s, " <no-host-if>");
99   else
100     s = format (s, " %U", format_vnet_sw_interface_name, vnm, swif_host);
101
102   s = format (s, " %v %d type %s", lip->lip_host_name, lip->lip_vif_index,
103               (lip->lip_host_type == LCP_ITF_HOST_TAP) ? "tap" : "tun");
104
105   if (lip->lip_namespace)
106     s = format (s, " netns %s", lip->lip_namespace);
107
108   return s;
109 }
110
111 static walk_rc_t
112 lcp_itf_pair_walk_show_cb (index_t api, void *ctx)
113 {
114   vlib_main_t *vm;
115   lcp_itf_pair_t *lip;
116
117   lip = lcp_itf_pair_get (api);
118   if (!lip)
119     return WALK_STOP;
120
121   vm = vlib_get_main ();
122   vlib_cli_output (vm, "%U\n", format_lcp_itf_pair, lip);
123
124   return WALK_CONTINUE;
125 }
126
127 void
128 lcp_itf_pair_show (u32 phy_sw_if_index)
129 {
130   vlib_main_t *vm;
131   u8 *ns;
132   index_t api;
133
134   vm = vlib_get_main ();
135   ns = lcp_get_default_ns ();
136   vlib_cli_output (vm, "lcp default netns '%s'\n",
137                    ns ? (char *) ns : "<unset>");
138
139   if (phy_sw_if_index == ~0)
140     {
141       lcp_itf_pair_walk (lcp_itf_pair_walk_show_cb, 0);
142     }
143   else
144     {
145       api = lcp_itf_pair_find_by_phy (phy_sw_if_index);
146       if (api != INDEX_INVALID)
147         lcp_itf_pair_walk_show_cb (api, 0);
148     }
149 }
150
151 lcp_itf_pair_t *
152 lcp_itf_pair_get (u32 index)
153 {
154   return pool_elt_at_index (lcp_itf_pair_pool, index);
155 }
156
157 index_t
158 lcp_itf_pair_find_by_vif (u32 vif_index)
159 {
160   uword *p;
161
162   p = hash_get (lip_db_by_vif, vif_index);
163
164   if (p)
165     return p[0];
166
167   return INDEX_INVALID;
168 }
169
170 int
171 lcp_itf_pair_add_sub (u32 vif, u8 *host_if_name, u32 sub_sw_if_index,
172                       u32 phy_sw_if_index, u8 *ns)
173 {
174   lcp_itf_pair_t *lip;
175
176   lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (phy_sw_if_index));
177
178   return lcp_itf_pair_add (lip->lip_host_sw_if_index, sub_sw_if_index,
179                            host_if_name, vif, lip->lip_host_type, ns);
180 }
181
182 const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = {
183   [LCP_ITF_HOST_TAP] = {
184     [AF_IP4] = "linux-cp-xc-ip4",
185     [AF_IP6] = "linux-cp-xc-ip6",
186   },
187   [LCP_ITF_HOST_TUN] = {
188     [AF_IP4] = "linux-cp-xc-l3-ip4",
189     [AF_IP6] = "linux-cp-xc-l3-ip6",
190   },
191 };
192
193 const fib_route_path_flags_t lcp_itf_route_path_flags[N_LCP_ITF_HOST] = {
194   [LCP_ITF_HOST_TAP] = FIB_ROUTE_PATH_DVR,
195   [LCP_ITF_HOST_TUN] = FIB_ROUTE_PATH_FLAG_NONE,
196 };
197
198 static void
199 lcp_itf_unset_adjs (lcp_itf_pair_t *lip)
200 {
201   adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP4]);
202   adj_unlock (lip->lip_phy_adjs.adj_index[AF_IP6]);
203 }
204
205 static void
206 lcp_itf_set_adjs (lcp_itf_pair_t *lip)
207 {
208   if (lip->lip_host_type == LCP_ITF_HOST_TUN)
209     {
210       lip->lip_phy_adjs.adj_index[AF_IP4] = adj_nbr_add_or_lock (
211         FIB_PROTOCOL_IP4, VNET_LINK_IP4, &zero_addr, lip->lip_phy_sw_if_index);
212       lip->lip_phy_adjs.adj_index[AF_IP6] = adj_nbr_add_or_lock (
213         FIB_PROTOCOL_IP6, VNET_LINK_IP6, &zero_addr, lip->lip_phy_sw_if_index);
214     }
215   else
216     {
217       lip->lip_phy_adjs.adj_index[AF_IP4] = adj_mcast_add_or_lock (
218         FIB_PROTOCOL_IP4, VNET_LINK_IP4, lip->lip_phy_sw_if_index);
219       lip->lip_phy_adjs.adj_index[AF_IP6] = adj_mcast_add_or_lock (
220         FIB_PROTOCOL_IP6, VNET_LINK_IP6, lip->lip_phy_sw_if_index);
221     }
222
223   ip_adjacency_t *adj;
224
225   adj = adj_get (lip->lip_phy_adjs.adj_index[AF_IP4]);
226
227   lip->lip_rewrite_len = adj->rewrite_header.data_bytes;
228 }
229
230 int
231 lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
232                   u32 host_index, lip_host_type_t host_type, u8 *ns)
233 {
234   index_t lipi;
235   lcp_itf_pair_t *lip;
236
237   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
238
239   LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%v",
240                      format_vnet_sw_if_index_name, vnet_get_main (),
241                      host_sw_if_index, format_vnet_sw_if_index_name,
242                      vnet_get_main (), phy_sw_if_index, host_name, host_index,
243                      ns);
244
245   if (lipi != INDEX_INVALID)
246     return VNET_API_ERROR_VALUE_EXIST;
247
248   /*
249    * Create a new pair.
250    */
251   pool_get (lcp_itf_pair_pool, lip);
252
253   lipi = lip - lcp_itf_pair_pool;
254
255   vec_validate_init_empty (lip_db_by_phy, phy_sw_if_index, INDEX_INVALID);
256   vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
257   lip_db_by_phy[phy_sw_if_index] = lipi;
258   lip_db_by_host[host_sw_if_index] = lipi;
259   hash_set (lip_db_by_vif, host_index, lipi);
260
261   lip->lip_host_sw_if_index = host_sw_if_index;
262   lip->lip_phy_sw_if_index = phy_sw_if_index;
263   lip->lip_host_name = vec_dup (host_name);
264   lip->lip_host_type = host_type;
265   lip->lip_vif_index = host_index;
266   lip->lip_namespace = vec_dup (ns);
267
268   if (lip->lip_host_sw_if_index == ~0)
269     return 0;
270
271   /*
272    * First use of this host interface.
273    * Enable the x-connect feature on the host to send
274    * all packets to the phy.
275    */
276   ip_address_family_t af;
277
278   FOR_EACH_IP_ADDRESS_FAMILY (af)
279   ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
280                              lcp_itf_l3_feat_names[lip->lip_host_type][af],
281                              lip->lip_host_sw_if_index, 1, NULL, 0);
282
283   /*
284    * Configure passive punt to the host interface.
285    */
286   fib_route_path_t *rpaths = NULL, rpath = {
287     .frp_flags = lcp_itf_route_path_flags[lip->lip_host_type],
288     .frp_proto = DPO_PROTO_IP4,
289     .frp_sw_if_index = lip->lip_host_sw_if_index,
290     .frp_weight = 1,
291     .frp_fib_index = ~0,
292   };
293
294   vec_add1 (rpaths, rpath);
295
296   ip4_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
297
298   rpaths[0].frp_proto = DPO_PROTO_IP6;
299
300   ip6_punt_redirect_add_paths (lip->lip_phy_sw_if_index, rpaths);
301
302   vec_free (rpaths);
303
304   lcp_itf_set_adjs (lip);
305
306   /* enable ARP feature node for broadcast interfaces */
307   if (lip->lip_host_type != LCP_ITF_HOST_TUN)
308     {
309       vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
310                                    lip->lip_phy_sw_if_index, 1, NULL, 0);
311       vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
312                                    lip->lip_host_sw_if_index, 1, NULL, 0);
313     }
314   else
315     {
316       vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 1, NULL,
317                                    0);
318       vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 1, NULL,
319                                    0);
320     }
321
322   /* invoke registered callbacks for pair addition */
323   lcp_itf_pair_vft_t *vft;
324
325   vec_foreach (vft, lcp_itf_vfts)
326     {
327       if (vft->pair_add_fn)
328         vft->pair_add_fn (lip);
329     }
330
331   /* set timestamp when pair entered service */
332   lip->lip_create_ts = vlib_time_now (vlib_get_main ());
333
334   return 0;
335 }
336
337 static clib_error_t *
338 lcp_netlink_add_link_vlan (int parent, u32 vlan, const char *name)
339 {
340   struct rtnl_link *link;
341   struct nl_sock *sk;
342   int err;
343
344   sk = nl_socket_alloc ();
345   if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
346     return clib_error_return (NULL, "Unable to connect socket: %d", err);
347
348   link = rtnl_link_vlan_alloc ();
349
350   rtnl_link_set_link (link, parent);
351   rtnl_link_set_name (link, name);
352
353   rtnl_link_vlan_set_id (link, vlan);
354
355   if ((err = rtnl_link_add (sk, link, NLM_F_CREATE)) < 0)
356     return clib_error_return (NULL, "Unable to add link %s: %d", name, err);
357
358   rtnl_link_put (link);
359   nl_close (sk);
360
361   return NULL;
362 }
363
364 static clib_error_t *
365 lcp_netlink_del_link (const char *name)
366 {
367   struct rtnl_link *link;
368   struct nl_sock *sk;
369   int err;
370
371   sk = nl_socket_alloc ();
372   if ((err = nl_connect (sk, NETLINK_ROUTE)) < 0)
373     return clib_error_return (NULL, "Unable to connect socket: %d", err);
374
375   link = rtnl_link_alloc ();
376   rtnl_link_set_name (link, name);
377
378   if ((err = rtnl_link_delete (sk, link)) < 0)
379     return clib_error_return (NULL, "Unable to del link %s: %d", name, err);
380
381   rtnl_link_put (link);
382   nl_close (sk);
383
384   return NULL;
385 }
386
387 int
388 lcp_itf_pair_del (u32 phy_sw_if_index)
389 {
390   ip_address_family_t af;
391   lcp_itf_pair_t *lip;
392   u32 lipi;
393   lcp_itf_pair_vft_t *vft;
394
395   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
396
397   if (lipi == INDEX_INVALID)
398     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
399
400   lip = lcp_itf_pair_get (lipi);
401
402   LCP_ITF_PAIR_INFO ("pair delete: {%U, %U, %s}", format_vnet_sw_if_index_name,
403                      vnet_get_main (), lip->lip_phy_sw_if_index,
404                      format_vnet_sw_if_index_name, vnet_get_main (),
405                      lip->lip_host_sw_if_index, lip->lip_host_name);
406
407   /* invoke registered callbacks for pair deletion */
408   vec_foreach (vft, lcp_itf_vfts)
409     {
410       if (vft->pair_del_fn)
411         vft->pair_del_fn (lip);
412     }
413
414   FOR_EACH_IP_ADDRESS_FAMILY (af)
415   ip_feature_enable_disable (af, N_SAFI, IP_FEATURE_INPUT,
416                              lcp_itf_l3_feat_names[lip->lip_host_type][af],
417                              lip->lip_host_sw_if_index, 0, NULL, 0);
418
419   lcp_itf_unset_adjs (lip);
420
421   ip4_punt_redirect_del (lip->lip_phy_sw_if_index);
422   ip6_punt_redirect_del (lip->lip_phy_sw_if_index);
423
424   /* disable ARP feature node for broadcast interfaces */
425   if (lip->lip_host_type != LCP_ITF_HOST_TUN)
426     {
427       vnet_feature_enable_disable ("arp", "linux-cp-arp-phy",
428                                    lip->lip_phy_sw_if_index, 0, NULL, 0);
429       vnet_feature_enable_disable ("arp", "linux-cp-arp-host",
430                                    lip->lip_host_sw_if_index, 0, NULL, 0);
431     }
432   else
433     {
434       vnet_feature_enable_disable ("ip4-punt", "linux-cp-punt-l3", 0, 0, NULL,
435                                    0);
436       vnet_feature_enable_disable ("ip6-punt", "linux-cp-punt-l3", 0, 0, NULL,
437                                    0);
438     }
439
440   lip_db_by_phy[phy_sw_if_index] = INDEX_INVALID;
441   lip_db_by_host[lip->lip_host_sw_if_index] = INDEX_INVALID;
442   hash_unset (lip_db_by_vif, lip->lip_vif_index);
443
444   vec_free (lip->lip_host_name);
445   vec_free (lip->lip_namespace);
446   pool_put (lcp_itf_pair_pool, lip);
447
448   return 0;
449 }
450
451 static void
452 lcp_itf_pair_delete_by_index (index_t lipi)
453 {
454   u32 host_sw_if_index;
455   lcp_itf_pair_t *lip;
456   u8 *host_name;
457
458   lip = lcp_itf_pair_get (lipi);
459
460   host_name = vec_dup (lip->lip_host_name);
461   host_sw_if_index = lip->lip_host_sw_if_index;
462
463   lcp_itf_pair_del (lip->lip_phy_sw_if_index);
464
465   if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index))
466     {
467       lcp_netlink_del_link ((const char *) host_name);
468       vnet_delete_sub_interface (host_sw_if_index);
469     }
470   else
471     tap_delete_if (vlib_get_main (), host_sw_if_index);
472
473   vec_free (host_name);
474 }
475
476 int
477 lcp_itf_pair_delete (u32 phy_sw_if_index)
478 {
479   index_t lipi;
480
481   lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
482
483   if (lipi == INDEX_INVALID)
484     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
485
486   lcp_itf_pair_delete_by_index (lipi);
487
488   return 0;
489 }
490
491 void
492 lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx)
493 {
494   u32 api;
495
496   pool_foreach_index (api, lcp_itf_pair_pool)
497     {
498       if (!cb (api, ctx))
499         break;
500     };
501 }
502
503 typedef struct lcp_itf_pair_names_t_
504 {
505   u8 *lipn_host_name;
506   u8 *lipn_phy_name;
507   u8 *lipn_namespace;
508   u32 lipn_phy_sw_if_index;
509 } lcp_itf_pair_names_t;
510
511 static lcp_itf_pair_names_t *lipn_names;
512
513 static clib_error_t *
514 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
515 {
516   u8 *host, *phy;
517   u8 *ns;
518   u8 *default_ns;
519
520   host = phy = ns = default_ns = NULL;
521
522   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
523     {
524       vec_reset_length (host);
525
526       if (unformat (input, "pair %s %s %s", &phy, &host, &ns))
527         {
528           lcp_itf_pair_names_t *lipn;
529
530           if (vec_len (ns) > LCP_NS_LEN)
531             {
532               return clib_error_return (0,
533                                         "linux-cp IF namespace must"
534                                         " be less than %d characters",
535                                         LCP_NS_LEN);
536             }
537
538           vec_add2 (lipn_names, lipn, 1);
539
540           lipn->lipn_host_name = vec_dup (host);
541           lipn->lipn_phy_name = vec_dup (phy);
542           lipn->lipn_namespace = vec_dup (ns);
543         }
544       else if (unformat (input, "pair %v %v", &phy, &host))
545         {
546           lcp_itf_pair_names_t *lipn;
547
548           vec_add2 (lipn_names, lipn, 1);
549
550           lipn->lipn_host_name = vec_dup (host);
551           lipn->lipn_phy_name = vec_dup (phy);
552           lipn->lipn_namespace = 0;
553         }
554       else if (unformat (input, "default netns %v", &default_ns))
555         {
556           vec_add1 (default_ns, 0);
557           if (lcp_set_default_ns (default_ns) < 0)
558             {
559               return clib_error_return (0,
560                                         "linux-cp default namespace must"
561                                         " be less than %d characters",
562                                         LCP_NS_LEN);
563             }
564         }
565       else if (unformat (input, "interface-auto-create"))
566         lcp_set_auto_intf (1 /* is_auto */);
567       else
568         return clib_error_return (0, "interfaces not found");
569     }
570
571   vec_free (host);
572   vec_free (phy);
573   vec_free (default_ns);
574
575   return NULL;
576 }
577
578 VLIB_EARLY_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-cp");
579
580 /*
581  * Returns 1 if the tap name is valid.
582  * Returns 0 if the tap name is invalid.
583  */
584 static int
585 lcp_validate_if_name (u8 *name)
586 {
587   int len;
588   char *p;
589
590   p = (char *) name;
591   len = clib_strnlen (p, IFNAMSIZ);
592   if (len >= IFNAMSIZ)
593     return 0;
594
595   for (; *p; ++p)
596     {
597       if (isalnum (*p))
598         continue;
599
600       switch (*p)
601         {
602         case '-':
603         case '_':
604         case '%':
605         case '@':
606         case ':':
607         case '.':
608           continue;
609         }
610
611       return 0;
612     }
613
614   return 1;
615 }
616
617 static int
618 lcp_itf_get_ns_fd (char *ns_name)
619 {
620   char ns_path[256] = "/proc/self/ns/net";
621
622   if (ns_name)
623     snprintf (ns_path, sizeof (ns_path) - 1, "/var/run/netns/%s", ns_name);
624
625   return open (ns_path, O_RDONLY);
626 }
627
628 static void
629 lcp_itf_set_vif_link_state (u32 vif_index, u8 up, u8 *ns)
630 {
631   int curr_ns_fd, vif_ns_fd;
632
633   curr_ns_fd = vif_ns_fd = -1;
634
635   if (ns)
636     {
637       u8 *ns_path = 0;
638
639       curr_ns_fd = open ("/proc/self/ns/net", O_RDONLY);
640       ns_path = format (0, "/var/run/netns/%s%c", (char *) ns, 0);
641       vif_ns_fd = open ((char *) ns_path, O_RDONLY);
642       if (vif_ns_fd != -1)
643         setns (vif_ns_fd, CLONE_NEWNET);
644     }
645
646   vnet_netlink_set_link_state (vif_index, up);
647
648   if (vif_ns_fd != -1)
649     close (vif_ns_fd);
650
651   if (curr_ns_fd != -1)
652     {
653       setns (curr_ns_fd, CLONE_NEWNET);
654       close (curr_ns_fd);
655     }
656 }
657
658 int
659 lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
660                      lip_host_type_t host_if_type, u8 *ns,
661                      u32 *host_sw_if_indexp)
662 {
663   vlib_main_t *vm;
664   vnet_main_t *vnm;
665   u32 vif_index = 0, host_sw_if_index;
666   const vnet_sw_interface_t *sw;
667   const vnet_hw_interface_t *hw;
668
669   if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
670     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
671
672   if (!lcp_validate_if_name (host_if_name))
673     return VNET_API_ERROR_INVALID_ARGUMENT;
674
675   vnm = vnet_get_main ();
676   sw = vnet_get_sw_interface (vnm, phy_sw_if_index);
677   hw = vnet_get_sup_hw_interface (vnm, phy_sw_if_index);
678
679   /*
680    * Use interface-specific netns if supplied.
681    * Otherwise, use default netns if defined.
682    * Otherwise ignore a netns and use the OS default.
683    */
684   if (ns == 0 || ns[0] == 0)
685     ns = lcp_get_default_ns ();
686
687   /* sub interfaces do not need a tap created */
688   if (vnet_sw_interface_is_sub (vnm, phy_sw_if_index))
689     {
690       const lcp_itf_pair_t *lip;
691       int orig_ns_fd, ns_fd;
692       clib_error_t *err;
693       u16 vlan;
694
695       /*
696        * Find the parent tap by finding the pair from the parent phy
697        */
698       lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (sw->sup_sw_if_index));
699       vlan = sw->sub.eth.outer_vlan_id;
700
701       /*
702        * see if the requested host interface has already been created
703        */
704       orig_ns_fd = ns_fd = -1;
705       err = NULL;
706
707       if (ns && ns[0] != 0)
708         {
709           orig_ns_fd = lcp_itf_get_ns_fd (NULL);
710           ns_fd = lcp_itf_get_ns_fd ((char *) ns);
711           if (orig_ns_fd == -1 || ns_fd == -1)
712             goto socket_close;
713
714           setns (ns_fd, CLONE_NEWNET);
715         }
716
717       vif_index = if_nametoindex ((const char *) host_if_name);
718
719       if (!vif_index)
720         {
721           /*
722            * no existing host interface, create it now
723            */
724           err = lcp_netlink_add_link_vlan (lip->lip_vif_index, vlan,
725                                            (const char *) host_if_name);
726
727           if (!err && -1 != ns_fd)
728             err = vnet_netlink_set_link_netns (vif_index, ns_fd, NULL);
729
730           if (!err)
731             vif_index = if_nametoindex ((char *) host_if_name);
732         }
733
734       /*
735        * create a sub-interface on the tap
736        */
737       if (!err && vnet_create_sub_interface (lip->lip_host_sw_if_index,
738                                              sw->sub.id, sw->sub.eth.raw_flags,
739                                              sw->sub.eth.inner_vlan_id, vlan,
740                                              &host_sw_if_index))
741         LCP_ITF_PAIR_INFO ("failed create vlan: %d on %U", vlan,
742                            format_vnet_sw_if_index_name, vnet_get_main (),
743                            lip->lip_host_sw_if_index);
744
745     socket_close:
746       if (orig_ns_fd != -1)
747         {
748           setns (orig_ns_fd, CLONE_NEWNET);
749           close (orig_ns_fd);
750         }
751       if (ns_fd != -1)
752         close (ns_fd);
753
754       if (err)
755         return VNET_API_ERROR_INVALID_ARGUMENT;
756     }
757   else
758     {
759       tap_create_if_args_t args = {
760         .num_rx_queues = clib_max (1, vlib_num_workers ()),
761         .id = hw->hw_if_index,
762         .sw_if_index = ~0,
763         .rx_ring_sz = 256,
764         .tx_ring_sz = 256,
765         .host_if_name = host_if_name,
766         .host_namespace = 0,
767       };
768       ethernet_interface_t *ei;
769
770       if (host_if_type == LCP_ITF_HOST_TUN)
771         args.tap_flags |= TAP_FLAG_TUN;
772       else
773         {
774           ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
775           mac_address_copy (&args.host_mac_addr, &ei->address.mac);
776         }
777
778       if (sw->mtu[VNET_MTU_L3])
779         {
780           args.host_mtu_set = 1;
781           args.host_mtu_size = sw->mtu[VNET_MTU_L3];
782         }
783
784       if (ns && ns[0] != 0)
785         args.host_namespace = ns;
786
787       vm = vlib_get_main ();
788       tap_create_if (vm, &args);
789
790       if (args.rv < 0)
791         {
792           return args.rv;
793         }
794
795       /*
796        * get the hw and ethernet of the tap
797        */
798       hw = vnet_get_sup_hw_interface (vnm, args.sw_if_index);
799
800       /*
801        * Set the interface down on the host side.
802        * This controls whether the host can RX/TX.
803        */
804       virtio_main_t *mm = &virtio_main;
805       virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
806
807       lcp_itf_set_vif_link_state (vif->ifindex, 0 /* down */,
808                                   args.host_namespace);
809
810       /*
811        * Leave the TAP permanently up on the VPP side.
812        * This TAP will be shared by many sub-interface.
813        * Therefore we can't use it to manage admin state.
814        * force the tap in promiscuous mode.
815        */
816       if (host_if_type == LCP_ITF_HOST_TAP)
817         {
818           ei = pool_elt_at_index (ethernet_main.interfaces, hw->hw_instance);
819           ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
820         }
821
822       vif_index = vif->ifindex;
823       host_sw_if_index = args.sw_if_index;
824     }
825
826   if (!vif_index)
827     {
828       LCP_ITF_PAIR_INFO ("failed pair add (no vif index): {%U, %U, %s}",
829                          format_vnet_sw_if_index_name, vnet_get_main (),
830                          phy_sw_if_index, format_vnet_sw_if_index_name,
831                          vnet_get_main (), host_sw_if_index, host_if_name);
832       return -1;
833     }
834
835   vnet_sw_interface_admin_up (vnm, host_sw_if_index);
836   lcp_itf_pair_add (host_sw_if_index, phy_sw_if_index, host_if_name, vif_index,
837                     host_if_type, ns);
838
839   LCP_ITF_PAIR_INFO ("pair create: {%U, %U, %s}", format_vnet_sw_if_index_name,
840                      vnet_get_main (), phy_sw_if_index,
841                      format_vnet_sw_if_index_name, vnet_get_main (),
842                      host_sw_if_index, host_if_name);
843
844   if (host_sw_if_indexp)
845     *host_sw_if_indexp = host_sw_if_index;
846
847   return 0;
848 }
849
850 static walk_rc_t
851 lcp_itf_pair_walk_mark (index_t lipi, void *ctx)
852 {
853   lcp_itf_pair_t *lip;
854
855   lip = lcp_itf_pair_get (lipi);
856
857   lip->lip_flags |= LIP_FLAG_STALE;
858
859   return (WALK_CONTINUE);
860 }
861
862 int
863 lcp_itf_pair_replace_begin (void)
864 {
865   lcp_itf_pair_walk (lcp_itf_pair_walk_mark, NULL);
866
867   return (0);
868 }
869
870 typedef struct lcp_itf_pair_sweep_ctx_t_
871 {
872   index_t *indicies;
873 } lcp_itf_pair_sweep_ctx_t;
874
875 static walk_rc_t
876 lcp_itf_pair_walk_sweep (index_t lipi, void *arg)
877 {
878   lcp_itf_pair_sweep_ctx_t *ctx = arg;
879   lcp_itf_pair_t *lip;
880
881   lip = lcp_itf_pair_get (lipi);
882
883   if (lip->lip_flags & LIP_FLAG_STALE)
884     vec_add1 (ctx->indicies, lipi);
885
886   return (WALK_CONTINUE);
887 }
888
889 int
890 lcp_itf_pair_replace_end (void)
891 {
892   lcp_itf_pair_sweep_ctx_t ctx = {
893     .indicies = NULL,
894   };
895   index_t *lipi;
896
897   lcp_itf_pair_walk (lcp_itf_pair_walk_sweep, &ctx);
898
899   vec_foreach (lipi, ctx.indicies)
900     lcp_itf_pair_delete_by_index (*lipi);
901
902   vec_free (ctx.indicies);
903   return (0);
904 }
905
906 static uword
907 lcp_itf_pair_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
908                       vlib_frame_t *f)
909 {
910   uword *event_data = 0;
911   uword *lipn_index;
912
913   while (1)
914     {
915       vlib_process_wait_for_event (vm);
916
917       vlib_process_get_events (vm, &event_data);
918
919       vec_foreach (lipn_index, event_data)
920         {
921           lcp_itf_pair_names_t *lipn;
922
923           lipn = &lipn_names[*lipn_index];
924           lcp_itf_pair_create (lipn->lipn_phy_sw_if_index,
925                                lipn->lipn_host_name, LCP_ITF_HOST_TAP,
926                                lipn->lipn_namespace, NULL);
927         }
928
929       vec_reset_length (event_data);
930     }
931
932   return 0;
933 }
934
935 VLIB_REGISTER_NODE (lcp_itf_pair_process_node, static) = {
936   .function = lcp_itf_pair_process,
937   .name = "linux-cp-itf-process",
938   .type = VLIB_NODE_TYPE_PROCESS,
939 };
940
941 static clib_error_t *
942 lcp_itf_phy_add (vnet_main_t *vnm, u32 sw_if_index, u32 is_create)
943 {
944   lcp_itf_pair_names_t *lipn;
945   vlib_main_t *vm = vlib_get_main ();
946   vnet_hw_interface_t *hw;
947
948   if (!is_create || vnet_sw_interface_is_sub (vnm, sw_if_index))
949     return NULL;
950
951   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
952
953   vec_foreach (lipn, lipn_names)
954     {
955       if (!vec_cmp (hw->name, lipn->lipn_phy_name))
956         {
957           lipn->lipn_phy_sw_if_index = sw_if_index;
958
959           vlib_process_signal_event (vm, lcp_itf_pair_process_node.index, 0,
960                                      lipn - lipn_names);
961           break;
962         }
963     }
964
965   return NULL;
966 }
967
968 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_phy_add);
969
970 static clib_error_t *
971 lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
972 {
973   vnet_hw_interface_t *hi;
974   vnet_sw_interface_t *si;
975   index_t lipi;
976   lcp_itf_pair_t *lip;
977
978   hi = vnet_get_hw_interface_or_null (vnm, hw_if_index);
979   if (!hi)
980     return 0;
981
982   lipi = lcp_itf_pair_find_by_phy (hi->sw_if_index);
983   if (lipi == INDEX_INVALID)
984     return 0;
985
986   lip = lcp_itf_pair_get (lipi);
987   si = vnet_get_sw_interface_or_null (vnm, lip->lip_host_sw_if_index);
988   if (!si)
989     return 0;
990
991   if (!lcp_main.test_mode)
992     {
993       tap_set_carrier (si->hw_if_index,
994                        (flags & VNET_HW_INTERFACE_FLAG_LINK_UP));
995
996       if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
997         {
998           tap_set_speed (si->hw_if_index, hi->link_speed / 1000);
999         }
1000     }
1001
1002   return 0;
1003 }
1004
1005 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down);
1006
1007 static clib_error_t *
1008 lcp_itf_pair_init (vlib_main_t *vm)
1009 {
1010   vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("linux-cp");
1011
1012   /* punt IKE */
1013   vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
1014                       "linux-cp-punt");
1015
1016   /* punt all unknown ports */
1017   udp_punt_unknown (vm, 0, 1);
1018   udp_punt_unknown (vm, 1, 1);
1019   tcp_punt_unknown (vm, 0, 1);
1020   tcp_punt_unknown (vm, 1, 1);
1021
1022   lcp_itf_pair_logger = vlib_log_register_class ("linux-cp", "itf");
1023
1024   return NULL;
1025 }
1026
1027 VLIB_INIT_FUNCTION (lcp_itf_pair_init) = {
1028   .runs_after = VLIB_INITS ("vnet_interface_init", "tcp_init", "udp_init"),
1029 };
1030
1031 /*
1032  * fd.io coding-style-patch-verification: ON
1033  *
1034  * Local Variables:
1035  * eval: (c-set-style "gnu")
1036  * End:
1037  */