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