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