tap: add check for vhost-net backend
[vpp.git] / src / vnet / devices / tap / tap.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #define _GNU_SOURCE
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <net/if.h>
23 #include <linux/if_tun.h>
24 #include <sys/ioctl.h>
25 #include <linux/virtio_net.h>
26 #include <linux/vhost.h>
27 #include <sys/eventfd.h>
28 #include <sched.h>
29
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
32
33 #include <vlib/vlib.h>
34 #include <vlib/physmem.h>
35 #include <vlib/unix/unix.h>
36 #include <vnet/ethernet/ethernet.h>
37 #include <vnet/ip/ip4_packet.h>
38 #include <vnet/ip/ip6_packet.h>
39 #include <vnet/devices/netlink.h>
40 #include <vnet/devices/virtio/virtio.h>
41 #include <vnet/devices/tap/tap.h>
42
43 tap_main_t tap_main;
44
45 #define _IOCTL(fd,a,...) \
46   if (ioctl (fd, a, __VA_ARGS__) < 0) \
47     { \
48       err = clib_error_return_unix (0, "ioctl(" #a ")"); \
49       goto error; \
50     }
51
52 static u32
53 virtio_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
54                         u32 flags)
55 {
56   /* nothing for now */
57   //TODO On MTU change call vnet_netlink_set_if_mtu
58   return 0;
59 }
60
61 static int
62 open_netns_fd (char *netns)
63 {
64   u8 *s = 0;
65   int fd;
66
67   if (strncmp (netns, "pid:", 4) == 0)
68     s = format (0, "/proc/%u/ns/net%c", atoi (netns + 4), 0);
69   else if (netns[0] == '/')
70     s = format (0, "%s%c", netns, 0);
71   else
72     s = format (0, "/var/run/netns/%s%c", netns, 0);
73
74   fd = open ((char *) s, O_RDONLY);
75   vec_free (s);
76   return fd;
77 }
78
79 #define TAP_MAX_INSTANCE 1024
80
81 void
82 tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
83 {
84   vlib_physmem_main_t *vpm = &vm->physmem_main;
85   vnet_main_t *vnm = vnet_get_main ();
86   virtio_main_t *vim = &virtio_main;
87   tap_main_t *tm = &tap_main;
88   vnet_sw_interface_t *sw;
89   vnet_hw_interface_t *hw;
90   int i;
91   int old_netns_fd = -1;
92   struct ifreq ifr;
93   size_t hdrsz;
94   struct vhost_memory *vhost_mem = 0;
95   virtio_if_t *vif = 0;
96   clib_error_t *err = 0;
97   unsigned int tap_features;
98   int fd = -1;
99   char *host_if_name = 0;
100
101   if (args->id != ~0)
102     {
103       if (clib_bitmap_get (tm->tap_ids, args->id))
104         {
105           args->rv = VNET_API_ERROR_INVALID_INTERFACE;
106           args->error = clib_error_return (0, "interface already exists");
107           return;
108         }
109     }
110   else
111     {
112       args->id = clib_bitmap_first_clear (tm->tap_ids);
113     }
114
115   if (args->id > TAP_MAX_INSTANCE)
116     {
117       args->rv = VNET_API_ERROR_UNSPECIFIED;
118       args->error = clib_error_return (0, "cannot find free interface id");
119       return;
120     }
121
122   clib_memset (&ifr, 0, sizeof (ifr));
123   pool_get (vim->interfaces, vif);
124   vif->dev_instance = vif - vim->interfaces;
125   vif->tap_fd = -1;
126   vif->id = args->id;
127
128   if ((vif->fd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0)
129     {
130       args->rv = VNET_API_ERROR_SYSCALL_ERROR_1;
131       args->error = clib_error_return_unix (0, "open '/dev/vhost-net'");
132       goto error;
133     }
134
135   _IOCTL (vif->fd, VHOST_GET_FEATURES, &vif->remote_features);
136
137   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
138     {
139       args->rv = VNET_API_ERROR_UNSUPPORTED;
140       args->error = clib_error_return (0, "vhost-net backend doesn't support "
141                                        "VIRTIO_NET_F_MRG_RXBUF feature");
142       goto error;
143     }
144
145   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
146       0)
147     {
148       args->rv = VNET_API_ERROR_UNSUPPORTED;
149       args->error = clib_error_return (0, "vhost-net backend doesn't support "
150                                        "VIRTIO_RING_F_INDIRECT_DESC feature");
151       goto error;
152     }
153
154   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1)) == 0)
155     {
156       args->rv = VNET_API_ERROR_UNSUPPORTED;
157       args->error = clib_error_return (0, "vhost-net backend doesn't support "
158                                        "VIRTIO_F_VERSION_1 features");
159       goto error;
160     }
161
162   vif->features |= VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
163   vif->features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
164   vif->features |= VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
165
166   virtio_set_net_hdr_size (vif);
167
168   _IOCTL (vif->fd, VHOST_SET_FEATURES, &vif->features);
169
170   if ((vif->tap_fd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
171     {
172       args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
173       args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
174       goto error;
175     }
176
177   _IOCTL (vif->tap_fd, TUNGETFEATURES, &tap_features);
178   if ((tap_features & IFF_VNET_HDR) == 0)
179     {
180       args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
181       args->error = clib_error_return (0, "vhost-net backend not available");
182       goto error;
183     }
184
185   ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR;
186   _IOCTL (vif->tap_fd, TUNSETIFF, (void *) &ifr);
187   vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
188
189   if (!args->host_if_name)
190     host_if_name = ifr.ifr_ifrn.ifrn_name;
191   else
192     host_if_name = (char *) args->host_if_name;
193
194   unsigned int offload = 0;
195   hdrsz = sizeof (struct virtio_net_hdr_v1);
196   if (args->tap_flags & TAP_FLAG_GSO)
197     {
198       offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
199       vif->gso_enabled = 1;
200     }
201   else
202     {
203       vif->gso_enabled = 0;
204     }
205
206   _IOCTL (vif->tap_fd, TUNSETOFFLOAD, offload);
207   _IOCTL (vif->tap_fd, TUNSETVNETHDRSZ, &hdrsz);
208   _IOCTL (vif->fd, VHOST_SET_OWNER, 0);
209
210   /* if namespace is specified, all further netlink messages should be executed
211      after we change our net namespace */
212   if (args->host_namespace)
213     {
214       old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
215       if ((fd = open_netns_fd ((char *) args->host_namespace)) == -1)
216         {
217           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
218           args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
219                                                 args->host_namespace);
220           goto error;
221         }
222       args->error = vnet_netlink_set_link_netns (vif->ifindex, fd,
223                                                  host_if_name);
224       if (args->error)
225         {
226           args->rv = VNET_API_ERROR_NETLINK_ERROR;
227           goto error;
228         }
229       if (setns (fd, CLONE_NEWNET) == -1)
230         {
231           args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
232           args->error = clib_error_return_unix (0, "setns '%s'",
233                                                 args->host_namespace);
234           goto error;
235         }
236       if ((vif->ifindex = if_nametoindex (host_if_name)) == 0)
237         {
238           args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
239           args->error = clib_error_return_unix (0, "if_nametoindex '%s'",
240                                                 host_if_name);
241           goto error;
242         }
243     }
244   else
245     {
246       if (host_if_name)
247         {
248           args->error = vnet_netlink_set_link_name (vif->ifindex,
249                                                     host_if_name);
250           if (args->error)
251             {
252               args->rv = VNET_API_ERROR_NETLINK_ERROR;
253               goto error;
254             }
255         }
256     }
257
258   if (!ethernet_mac_address_is_zero (args->host_mac_addr))
259     {
260       args->error = vnet_netlink_set_link_addr (vif->ifindex,
261                                                 args->host_mac_addr);
262       if (args->error)
263         {
264           args->rv = VNET_API_ERROR_NETLINK_ERROR;
265           goto error;
266         }
267     }
268
269   if (args->host_bridge)
270     {
271       args->error = vnet_netlink_set_link_master (vif->ifindex,
272                                                   (char *) args->host_bridge);
273       if (args->error)
274         {
275           args->rv = VNET_API_ERROR_NETLINK_ERROR;
276           goto error;
277         }
278     }
279
280
281   if (args->host_ip4_prefix_len)
282     {
283       args->error = vnet_netlink_add_ip4_addr (vif->ifindex,
284                                                &args->host_ip4_addr,
285                                                args->host_ip4_prefix_len);
286       if (args->error)
287         {
288           args->rv = VNET_API_ERROR_NETLINK_ERROR;
289           goto error;
290         }
291     }
292
293   if (args->host_ip6_prefix_len)
294     {
295       args->error = vnet_netlink_add_ip6_addr (vif->ifindex,
296                                                &args->host_ip6_addr,
297                                                args->host_ip6_prefix_len);
298       if (args->error)
299         {
300           args->rv = VNET_API_ERROR_NETLINK_ERROR;
301           goto error;
302         }
303     }
304
305   args->error = vnet_netlink_set_link_state (vif->ifindex, 1 /* UP */ );
306   if (args->error)
307     {
308       args->rv = VNET_API_ERROR_NETLINK_ERROR;
309       goto error;
310     }
311
312   if (args->host_ip4_gw_set)
313     {
314       args->error = vnet_netlink_add_ip4_route (0, 0, &args->host_ip4_gw);
315       if (args->error)
316         {
317           args->rv = VNET_API_ERROR_NETLINK_ERROR;
318           goto error;
319         }
320     }
321
322   if (args->host_ip6_gw_set)
323     {
324       args->error = vnet_netlink_add_ip6_route (0, 0, &args->host_ip6_gw);
325       if (args->error)
326         {
327           args->rv = VNET_API_ERROR_NETLINK_ERROR;
328           goto error;
329         }
330     }
331
332   /* switch back to old net namespace */
333   if (args->host_namespace)
334     {
335       if (setns (old_netns_fd, CLONE_NEWNET) == -1)
336         {
337           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
338           args->error = clib_error_return_unix (0, "setns '%s'",
339                                                 args->host_namespace);
340           goto error;
341         }
342     }
343
344   if (args->host_mtu_set)
345     {
346       args->error =
347         vnet_netlink_set_link_mtu (vif->ifindex, args->host_mtu_size);
348       if (args->error)
349         {
350           args->rv = VNET_API_ERROR_NETLINK_ERROR;
351           goto error;
352         }
353     }
354   else if (tm->host_mtu_size != 0)
355     {
356       args->error =
357         vnet_netlink_set_link_mtu (vif->ifindex, tm->host_mtu_size);
358       if (args->error)
359         {
360           args->rv = VNET_API_ERROR_NETLINK_ERROR;
361           goto error;
362         }
363       args->host_mtu_set = 1;
364       args->host_mtu_size = tm->host_mtu_size;
365     }
366
367   /* Set vhost memory table */
368   i = sizeof (struct vhost_memory) + sizeof (struct vhost_memory_region);
369   vhost_mem = clib_mem_alloc (i);
370   clib_memset (vhost_mem, 0, i);
371   vhost_mem->nregions = 1;
372   vhost_mem->regions[0].memory_size = vpm->max_size;
373   vhost_mem->regions[0].guest_phys_addr = vpm->base_addr;
374   vhost_mem->regions[0].userspace_addr =
375     vhost_mem->regions[0].guest_phys_addr;
376   _IOCTL (vif->fd, VHOST_SET_MEM_TABLE, vhost_mem);
377
378   if ((args->error =
379        virtio_vring_init (vm, vif, RX_QUEUE (0), args->rx_ring_sz)))
380     {
381       args->rv = VNET_API_ERROR_INIT_FAILED;
382       goto error;
383     }
384   vif->num_rxqs = 1;
385
386   if ((args->error =
387        virtio_vring_init (vm, vif, TX_QUEUE (0), args->tx_ring_sz)))
388     {
389       args->rv = VNET_API_ERROR_INIT_FAILED;
390       goto error;
391     }
392   vif->num_txqs = 1;
393
394   if (!args->mac_addr_set)
395     ethernet_mac_address_generate (args->mac_addr);
396
397   clib_memcpy (vif->mac_addr, args->mac_addr, 6);
398
399   vif->host_if_name = format (0, "%s%c", host_if_name, 0);
400   vif->net_ns = format (0, "%s%c", args->host_namespace, 0);
401   vif->host_bridge = format (0, "%s%c", args->host_bridge, 0);
402   vif->host_mtu_size = args->host_mtu_size;
403   clib_memcpy (vif->host_mac_addr, args->host_mac_addr, 6);
404   vif->host_ip4_prefix_len = args->host_ip4_prefix_len;
405   vif->host_ip6_prefix_len = args->host_ip6_prefix_len;
406   if (args->host_ip4_prefix_len)
407     clib_memcpy (&vif->host_ip4_addr, &args->host_ip4_addr, 4);
408   if (args->host_ip6_prefix_len)
409     clib_memcpy (&vif->host_ip6_addr, &args->host_ip6_addr, 16);
410
411   vif->type = VIRTIO_IF_TYPE_TAP;
412   args->error = ethernet_register_interface (vnm, virtio_device_class.index,
413                                              vif->dev_instance,
414                                              vif->mac_addr,
415                                              &vif->hw_if_index,
416                                              virtio_eth_flag_change);
417   if (args->error)
418     {
419       args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
420       goto error;
421     }
422
423   tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 1);
424   sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
425   vif->sw_if_index = sw->sw_if_index;
426   args->sw_if_index = vif->sw_if_index;
427   args->rv = 0;
428   hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
429   hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE;
430   if (args->tap_flags & TAP_FLAG_GSO)
431     {
432       hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO;
433       vnm->interface_main.gso_interface_count++;
434     }
435   vnet_hw_interface_set_input_node (vnm, vif->hw_if_index,
436                                     virtio_input_node.index);
437   vnet_hw_interface_assign_rx_thread (vnm, vif->hw_if_index, 0, ~0);
438   vnet_hw_interface_set_rx_mode (vnm, vif->hw_if_index, 0,
439                                  VNET_HW_INTERFACE_RX_MODE_DEFAULT);
440   vif->per_interface_next_index = ~0;
441   virtio_vring_set_numa_node (vm, vif, RX_QUEUE (0));
442   vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
443   vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
444                                VNET_HW_INTERFACE_FLAG_LINK_UP);
445   vif->cxq_vring = NULL;
446
447   goto done;
448
449 error:
450   if (err)
451     {
452       ASSERT (args->error == 0);
453       args->error = err;
454       args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
455     }
456   if (vif->tap_fd != -1)
457     close (vif->tap_fd);
458   if (vif->fd != -1)
459     close (vif->fd);
460   vec_foreach_index (i, vif->rxq_vrings) virtio_vring_free_rx (vm, vif,
461                                                                RX_QUEUE (i));
462   vec_foreach_index (i, vif->txq_vrings) virtio_vring_free_tx (vm, vif,
463                                                                TX_QUEUE (i));
464   vec_free (vif->rxq_vrings);
465   vec_free (vif->txq_vrings);
466
467   vec_free (vif->host_if_name);
468   vec_free (vif->net_ns);
469   vec_free (vif->host_bridge);
470
471   clib_memset (vif, 0, sizeof (virtio_if_t));
472   pool_put (vim->interfaces, vif);
473
474 done:
475   if (vhost_mem)
476     clib_mem_free (vhost_mem);
477   if (old_netns_fd != -1)
478     close (old_netns_fd);
479   if (fd != -1)
480     close (fd);
481 }
482
483 int
484 tap_delete_if (vlib_main_t * vm, u32 sw_if_index)
485 {
486   vnet_main_t *vnm = vnet_get_main ();
487   virtio_main_t *mm = &virtio_main;
488   tap_main_t *tm = &tap_main;
489   int i;
490   virtio_if_t *vif;
491   vnet_hw_interface_t *hw;
492
493   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
494   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
495     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
496
497   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
498
499   if (vif->type != VIRTIO_IF_TYPE_TAP)
500     return VNET_API_ERROR_INVALID_INTERFACE;
501
502   /* decrement if this was a GSO interface */
503   if (hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO)
504     vnm->interface_main.gso_interface_count--;
505
506   /* bring down the interface */
507   vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
508   vnet_sw_interface_set_flags (vnm, vif->sw_if_index, 0);
509   vnet_hw_interface_unassign_rx_thread (vnm, vif->hw_if_index, RX_QUEUE (0));
510
511   ethernet_delete_interface (vnm, vif->hw_if_index);
512   vif->hw_if_index = ~0;
513
514   if (vif->tap_fd != -1)
515     close (vif->tap_fd);
516   if (vif->fd != -1)
517     close (vif->fd);
518
519   vec_foreach_index (i, vif->rxq_vrings) virtio_vring_free_rx (vm, vif,
520                                                                RX_QUEUE (i));
521   vec_foreach_index (i, vif->txq_vrings) virtio_vring_free_tx (vm, vif,
522                                                                TX_QUEUE (i));
523   vec_free (vif->rxq_vrings);
524   vec_free (vif->txq_vrings);
525
526   vec_free (vif->host_if_name);
527   vec_free (vif->net_ns);
528   vec_free (vif->host_bridge);
529
530   tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 0);
531   clib_memset (vif, 0, sizeof (*vif));
532   pool_put (mm->interfaces, vif);
533
534   return 0;
535 }
536
537 int
538 tap_gso_enable_disable (vlib_main_t * vm, u32 sw_if_index, int enable_disable)
539 {
540   vnet_main_t *vnm = vnet_get_main ();
541   virtio_main_t *mm = &virtio_main;
542   virtio_if_t *vif;
543   vnet_hw_interface_t *hw;
544   clib_error_t *err = 0;
545
546   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
547
548   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
549     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
550
551   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
552
553   const unsigned int gso_on = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
554   const unsigned int gso_off = 0;
555   unsigned int offload = enable_disable ? gso_on : gso_off;
556   _IOCTL (vif->tap_fd, TUNSETOFFLOAD, offload);
557   vif->gso_enabled = enable_disable ? 1 : 0;
558   if (enable_disable)
559     {
560       if ((hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) == 0)
561         {
562           vnm->interface_main.gso_interface_count++;
563           hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO;
564         }
565     }
566   else
567     {
568       if ((hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) != 0)
569         {
570           vnm->interface_main.gso_interface_count--;
571           hw->flags &= ~VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO;
572         }
573     }
574
575 error:
576   if (err)
577     {
578       clib_warning ("Error %s gso on sw_if_index %d",
579                     enable_disable ? "enabling" : "disabling", sw_if_index);
580       return VNET_API_ERROR_SYSCALL_ERROR_3;
581     }
582   return 0;
583 }
584
585 int
586 tap_dump_ifs (tap_interface_details_t ** out_tapids)
587 {
588   vnet_main_t *vnm = vnet_get_main ();
589   virtio_main_t *mm = &virtio_main;
590   virtio_if_t *vif;
591   virtio_vring_t *vring;
592   vnet_hw_interface_t *hi;
593   tap_interface_details_t *r_tapids = NULL;
594   tap_interface_details_t *tapid = NULL;
595
596   /* *INDENT-OFF* */
597   pool_foreach (vif, mm->interfaces,
598     if (vif->type != VIRTIO_IF_TYPE_TAP)
599       continue;
600     vec_add2(r_tapids, tapid, 1);
601     clib_memset (tapid, 0, sizeof (*tapid));
602     tapid->id = vif->id;
603     tapid->sw_if_index = vif->sw_if_index;
604     hi = vnet_get_hw_interface (vnm, vif->hw_if_index);
605     clib_memcpy(tapid->dev_name, hi->name,
606                 MIN (ARRAY_LEN (tapid->dev_name) - 1,
607                      strlen ((const char *) hi->name)));
608     vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS(0));
609     tapid->rx_ring_sz = vring->size;
610     vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS(0));
611     tapid->tx_ring_sz = vring->size;
612     clib_memcpy(tapid->host_mac_addr, vif->host_mac_addr, 6);
613     if (vif->host_if_name)
614       {
615         clib_memcpy(tapid->host_if_name, vif->host_if_name,
616                     MIN (ARRAY_LEN (tapid->host_if_name) - 1,
617                     strlen ((const char *) vif->host_if_name)));
618       }
619     if (vif->net_ns)
620       {
621         clib_memcpy(tapid->host_namespace, vif->net_ns,
622                     MIN (ARRAY_LEN (tapid->host_namespace) - 1,
623                     strlen ((const char *) vif->net_ns)));
624       }
625     if (vif->host_bridge)
626       {
627         clib_memcpy(tapid->host_bridge, vif->host_bridge,
628                     MIN (ARRAY_LEN (tapid->host_bridge) - 1,
629                     strlen ((const char *) vif->host_bridge)));
630       }
631     if (vif->host_ip4_prefix_len)
632       clib_memcpy(tapid->host_ip4_addr, &vif->host_ip4_addr, 4);
633     tapid->host_ip4_prefix_len = vif->host_ip4_prefix_len;
634     if (vif->host_ip6_prefix_len)
635       clib_memcpy(tapid->host_ip6_addr, &vif->host_ip6_addr, 16);
636     tapid->host_ip6_prefix_len = vif->host_ip6_prefix_len;
637     tapid->host_mtu_size = vif->host_mtu_size;
638   );
639   /* *INDENT-ON* */
640
641   *out_tapids = r_tapids;
642
643   return 0;
644 }
645
646 static clib_error_t *
647 tap_mtu_config (vlib_main_t * vm, unformat_input_t * input)
648 {
649   tap_main_t *tm = &tap_main;
650
651   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
652     {
653       if (unformat (input, "host-mtu %d", &tm->host_mtu_size))
654         ;
655       else
656         return clib_error_return (0, "unknown input `%U'",
657                                   format_unformat_error, input);
658     }
659
660   return 0;
661 }
662
663 /* tap { host-mtu <size> } configuration. */
664 VLIB_CONFIG_FUNCTION (tap_mtu_config, "tap");
665
666 static clib_error_t *
667 tap_init (vlib_main_t * vm)
668 {
669   tap_main_t *tm = &tap_main;
670   clib_error_t *error = 0;
671
672   tm->log_default = vlib_log_register_class ("tap", 0);
673   vlib_log_debug (tm->log_default, "initialized");
674
675   tm->host_mtu_size = 0;
676
677   return error;
678 }
679
680 VLIB_INIT_FUNCTION (tap_init);
681
682 /*
683  * fd.io coding-style-patch-verification: ON
684  *
685  * Local Variables:
686  * eval: (c-set-style "gnu")
687  * End:
688  */