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