vppinfra: add abstract socket & netns fns
[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 <sys/socket.h>
22 #include <fcntl.h>
23 #include <net/if.h>
24 #include <linux/if_tun.h>
25 #include <sys/ioctl.h>
26 #include <linux/ethtool.h>
27 #include <linux/sockios.h>
28 #include <sys/eventfd.h>
29 #include <net/if_arp.h>
30 #include <limits.h>
31
32 #include <linux/netlink.h>
33 #include <linux/rtnetlink.h>
34
35 #include <vlib/vlib.h>
36 #include <vlib/physmem.h>
37 #include <vlib/unix/unix.h>
38 #include <vppinfra/linux/netns.h>
39 #include <vnet/ethernet/ethernet.h>
40 #include <vnet/ip/ip4_packet.h>
41 #include <vnet/ip/ip6_packet.h>
42 #include <vnet/devices/netlink.h>
43 #include <vnet/devices/virtio/virtio.h>
44 #include <vnet/devices/tap/tap.h>
45
46 tap_main_t tap_main;
47
48 #define tap_log_err(dev, f, ...)                        \
49   vlib_log (VLIB_LOG_LEVEL_ERR, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
50 #define tap_log_dbg(dev, f, ...)                        \
51   vlib_log (VLIB_LOG_LEVEL_DEBUG, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
52
53 #define _IOCTL(fd,a,...) \
54   if (ioctl (fd, a, __VA_ARGS__) < 0) \
55     { \
56       err = clib_error_return_unix (0, "ioctl(" #a ")"); \
57       tap_log_err (vif, "%U", format_clib_error, err); \
58       goto error; \
59     }
60
61   /* *INDENT-OFF* */
62 VNET_HW_INTERFACE_CLASS (tun_device_hw_interface_class, static) =
63 {
64   .name = "tun-device",
65   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
66 };
67   /* *INDENT-ON* */
68
69 #define TUN_MAX_PACKET_BYTES     65355
70 #define TUN_MIN_PACKET_BYTES     64
71 #define TUN_DEFAULT_PACKET_BYTES 1500
72
73 static u32
74 virtio_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
75                         u32 flags)
76 {
77   /* nothing for now */
78   //TODO On MTU change call vnet_netlink_set_if_mtu
79   return 0;
80 }
81
82 #define TAP_MAX_INSTANCE 1024
83
84 static void
85 tap_free (vlib_main_t * vm, virtio_if_t * vif)
86 {
87   virtio_main_t *mm = &virtio_main;
88   tap_main_t *tm = &tap_main;
89   clib_error_t *err = 0;
90   int i;
91
92   /* *INDENT-OFF* */
93   vec_foreach_index (i, vif->vhost_fds) if (vif->vhost_fds[i] != -1)
94     close (vif->vhost_fds[i]);
95   vec_foreach_index (i, vif->rxq_vrings)
96     virtio_vring_free_rx (vm, vif, RX_QUEUE (i));
97   vec_foreach_index (i, vif->txq_vrings)
98     virtio_vring_free_tx (vm, vif, TX_QUEUE (i));
99   /* *INDENT-ON* */
100
101   if (vif->tap_fds)
102     {
103       _IOCTL (vif->tap_fds[0], TUNSETPERSIST, (void *) (uintptr_t) 0);
104       tap_log_dbg (vif, "TUNSETPERSIST: unset");
105     }
106 error:
107   vec_foreach_index (i, vif->tap_fds) close (vif->tap_fds[i]);
108
109   vec_free (vif->vhost_fds);
110   vec_free (vif->rxq_vrings);
111   vec_free (vif->txq_vrings);
112   vec_free (vif->host_if_name);
113   vec_free (vif->net_ns);
114   vec_free (vif->host_bridge);
115   clib_error_free (vif->error);
116
117   tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 0);
118   clib_memset (vif, 0, sizeof (*vif));
119   pool_put (mm->interfaces, vif);
120 }
121
122 void
123 tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
124 {
125   vlib_thread_main_t *thm = vlib_get_thread_main ();
126   vlib_physmem_main_t *vpm = &vm->physmem_main;
127   vnet_main_t *vnm = vnet_get_main ();
128   virtio_main_t *vim = &virtio_main;
129   tap_main_t *tm = &tap_main;
130   vnet_sw_interface_t *sw;
131   vnet_hw_interface_t *hw;
132   int i, num_vhost_queues;
133   int old_netns_fd = -1;
134   struct ifreq ifr = {.ifr_flags = IFF_NO_PI | IFF_VNET_HDR };
135   struct ifreq get_ifr = {.ifr_flags = 0 };
136   size_t hdrsz;
137   vhost_memory_t *vhost_mem = 0;
138   virtio_if_t *vif = 0;
139   clib_error_t *err = 0;
140   unsigned int tap_features;
141   int tfd = -1, qfd = -1, vfd = -1, nfd = -1;
142   char *host_if_name = 0;
143   unsigned int offload = 0;
144   int sndbuf = 0;
145
146   if (args->id != ~0)
147     {
148       if (clib_bitmap_get (tm->tap_ids, args->id))
149         {
150           args->rv = VNET_API_ERROR_INVALID_INTERFACE;
151           args->error = clib_error_return (0, "interface already exists");
152           return;
153         }
154     }
155   else
156     {
157       args->id = clib_bitmap_first_clear (tm->tap_ids);
158     }
159
160   if (args->id > TAP_MAX_INSTANCE)
161     {
162       args->rv = VNET_API_ERROR_UNSPECIFIED;
163       args->error = clib_error_return (0, "cannot find free interface id");
164       return;
165     }
166
167   pool_get_zero (vim->interfaces, vif);
168
169   if (args->tap_flags & TAP_FLAG_TUN)
170     {
171       vif->type = VIRTIO_IF_TYPE_TUN;
172       ifr.ifr_flags |= IFF_TUN;
173
174       /*
175        * From kernel 4.20, xdp support has been added in tun_sendmsg.
176        * If sndbuf == INT_MAX, vhost batches the packet and processes
177        * them using xdp data path for tun driver. It assumes packets
178        * are ethernet frames (It needs to be fixed).
179        * To avoid xdp data path in tun driver, sndbuf value should
180        * be < INT_MAX.
181        */
182       sndbuf = INT_MAX - 1;
183     }
184   else
185     {
186       vif->type = VIRTIO_IF_TYPE_TAP;
187       ifr.ifr_flags |= IFF_TAP;
188       sndbuf = INT_MAX;
189     }
190
191   vif->dev_instance = vif - vim->interfaces;
192   vif->id = args->id;
193   vif->num_txqs = thm->n_vlib_mains;
194   vif->num_rxqs = clib_max (args->num_rx_queues, 1);
195
196   if (args->tap_flags & TAP_FLAG_ATTACH)
197     {
198       if (args->host_if_name != NULL)
199         {
200           host_if_name = (char *) args->host_if_name;
201           clib_memcpy (ifr.ifr_name, host_if_name,
202                        clib_min (IFNAMSIZ, vec_len (host_if_name)));
203         }
204       else
205         {
206           args->rv = VNET_API_ERROR_NO_MATCHING_INTERFACE;
207           err = clib_error_return (0, "host_if_name is not provided");
208           goto error;
209         }
210       if (args->host_namespace)
211         {
212           old_netns_fd = clib_netns_open (NULL /* self */);
213           if ((nfd = clib_netns_open (args->host_namespace)) == -1)
214             {
215               args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
216               args->error = clib_error_return_unix (0, "clib_netns_open '%s'",
217                                                     args->host_namespace);
218               goto error;
219             }
220           if (clib_setns (nfd) == -1)
221             {
222               args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
223               args->error = clib_error_return_unix (0, "setns '%s'",
224                                                     args->host_namespace);
225               goto error;
226             }
227         }
228     }
229
230   if ((tfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
231     {
232       args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
233       args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
234       goto error;
235     }
236   vec_add1 (vif->tap_fds, tfd);
237   tap_log_dbg (vif, "open tap fd %d", tfd);
238
239   _IOCTL (tfd, TUNGETFEATURES, &tap_features);
240   tap_log_dbg (vif, "TUNGETFEATURES: features 0x%lx", tap_features);
241   if ((tap_features & IFF_VNET_HDR) == 0)
242     {
243       args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
244       args->error = clib_error_return (0, "vhost-net backend not available");
245       goto error;
246     }
247
248   if ((tap_features & IFF_MULTI_QUEUE) == 0)
249     {
250       if (vif->num_rxqs > 1)
251         {
252           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
253           args->error = clib_error_return (0, "multiqueue not supported");
254           goto error;
255         }
256       vif->num_rxqs = vif->num_txqs = 1;
257     }
258   else
259     ifr.ifr_flags |= IFF_MULTI_QUEUE;
260
261   hdrsz = sizeof (virtio_net_hdr_v1_t);
262   if (args->tap_flags & TAP_FLAG_GSO)
263     {
264       offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
265       vif->gso_enabled = 1;
266     }
267   else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
268     {
269       offload = TUN_F_CSUM;
270       vif->csum_offload_enabled = 1;
271     }
272
273   _IOCTL (tfd, TUNSETIFF, (void *) &ifr);
274   tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", tfd,
275                ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
276
277   vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
278   tap_log_dbg (vif, "ifindex %d", vif->ifindex);
279
280   if (!args->host_if_name)
281     host_if_name = ifr.ifr_ifrn.ifrn_name;
282   else
283     host_if_name = (char *) args->host_if_name;
284
285   /*
286    * unset the persistence when attaching to existing
287    * interface
288    */
289   if (args->tap_flags & TAP_FLAG_ATTACH)
290     {
291       _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 0);
292       tap_log_dbg (vif, "TUNSETPERSIST: unset");
293     }
294
295   /* set the persistence */
296   if (args->tap_flags & TAP_FLAG_PERSIST)
297     {
298       _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 1);
299       tap_log_dbg (vif, "TUNSETPERSIST: set");
300
301       /* verify persistence is set, read the flags */
302       _IOCTL (tfd, TUNGETIFF, (void *) &get_ifr);
303       tap_log_dbg (vif, "TUNGETIFF: flags 0x%lx", get_ifr.ifr_flags);
304       if ((get_ifr.ifr_flags & IFF_PERSIST) == 0)
305         {
306           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
307           args->error = clib_error_return (0, "persistence not supported");
308           goto error;
309         }
310     }
311
312   /* create additional queues on the linux side.
313    * we create as many linux queue pairs as we have rx queues
314    */
315   for (i = 1; i < vif->num_rxqs; i++)
316     {
317       if ((qfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
318         {
319           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
320           args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
321           goto error;
322         }
323       _IOCTL (qfd, TUNSETIFF, (void *) &ifr);
324       tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", qfd,
325                    ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
326       vec_add1 (vif->tap_fds, qfd);
327     }
328
329   for (i = 0; i < vif->num_rxqs; i++)
330     {
331       tap_log_dbg (vif, "TUNSETVNETHDRSZ: fd %d vnet_hdr_sz %u",
332                    vif->tap_fds[i], hdrsz);
333       _IOCTL (vif->tap_fds[i], TUNSETVNETHDRSZ, &hdrsz);
334
335       tap_log_dbg (vif, "TUNSETSNDBUF: fd %d sndbuf %d", vif->tap_fds[i],
336                    sndbuf);
337       _IOCTL (vif->tap_fds[i], TUNSETSNDBUF, &sndbuf);
338
339       tap_log_dbg (vif, "TUNSETOFFLOAD: fd %d offload 0x%lx", vif->tap_fds[i],
340                    offload);
341       _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
342
343       if (fcntl (vif->tap_fds[i], F_SETFL, O_NONBLOCK) < 0)
344         {
345           err = clib_error_return_unix (0, "fcntl(tfd, F_SETFL, O_NONBLOCK)");
346           tap_log_err (vif, "set nonblocking: %U", format_clib_error, err);
347           goto error;
348         }
349     }
350
351   /* open as many vhost-net fds as required and set ownership */
352   num_vhost_queues = clib_max (vif->num_rxqs, vif->num_txqs);
353   for (i = 0; i < num_vhost_queues; i++)
354     {
355       if ((vfd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0)
356         {
357           args->rv = VNET_API_ERROR_SYSCALL_ERROR_1;
358           args->error = clib_error_return_unix (0, "open '/dev/vhost-net'");
359           goto error;
360         }
361       vec_add1 (vif->vhost_fds, vfd);
362       virtio_log_debug (vif, "open vhost-net fd %d qpair %u", vfd, i);
363       _IOCTL (vfd, VHOST_SET_OWNER, 0);
364       virtio_log_debug (vif, "VHOST_SET_OWNER: fd %u", vfd);
365     }
366
367   _IOCTL (vif->vhost_fds[0], VHOST_GET_FEATURES, &vif->remote_features);
368   virtio_log_debug (vif, "VHOST_GET_FEATURES: features 0x%lx",
369                     vif->remote_features);
370
371   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
372     {
373       args->rv = VNET_API_ERROR_UNSUPPORTED;
374       args->error = clib_error_return (0, "vhost-net backend doesn't support "
375                                        "VIRTIO_NET_F_MRG_RXBUF feature");
376       goto error;
377     }
378
379   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
380       0)
381     {
382       args->rv = VNET_API_ERROR_UNSUPPORTED;
383       args->error = clib_error_return (0, "vhost-net backend doesn't support "
384                                        "VIRTIO_RING_F_INDIRECT_DESC feature");
385       goto error;
386     }
387
388   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1)) == 0)
389     {
390       args->rv = VNET_API_ERROR_UNSUPPORTED;
391       args->error = clib_error_return (0, "vhost-net backend doesn't support "
392                                        "VIRTIO_F_VERSION_1 features");
393       goto error;
394     }
395
396   vif->features |= VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
397   vif->features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
398   vif->features |= VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
399
400   virtio_set_net_hdr_size (vif);
401
402   if (!(args->tap_flags & TAP_FLAG_ATTACH))
403     {
404       /* if namespace is specified, all further netlink messages should be executed
405          after we change our net namespace */
406       if (args->host_namespace)
407         {
408           old_netns_fd = clib_netns_open (NULL /* self */);
409           if ((nfd = clib_netns_open (args->host_namespace)) == -1)
410             {
411               args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
412               args->error = clib_error_return_unix (0, "clib_netns_open '%s'",
413                                                     args->host_namespace);
414               goto error;
415             }
416           args->error = vnet_netlink_set_link_netns (vif->ifindex, nfd,
417                                                      host_if_name);
418           if (args->error)
419             {
420               args->rv = VNET_API_ERROR_NETLINK_ERROR;
421               goto error;
422             }
423           if (clib_setns (nfd) == -1)
424             {
425               args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
426               args->error = clib_error_return_unix (0, "setns '%s'",
427                                                     args->host_namespace);
428               goto error;
429             }
430           if ((vif->ifindex = if_nametoindex (host_if_name)) == 0)
431             {
432               args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
433               args->error = clib_error_return_unix (0, "if_nametoindex '%s'",
434                                                     host_if_name);
435               goto error;
436             }
437         }
438       else if (host_if_name)
439         {
440           args->error =
441             vnet_netlink_set_link_name (vif->ifindex, host_if_name);
442           if (args->error)
443             {
444               args->rv = VNET_API_ERROR_NETLINK_ERROR;
445               goto error;
446             }
447         }
448     }
449
450   if (vif->type == VIRTIO_IF_TYPE_TAP)
451     {
452       if (ethernet_mac_address_is_zero (args->host_mac_addr.bytes))
453         ethernet_mac_address_generate (args->host_mac_addr.bytes);
454       args->error = vnet_netlink_set_link_addr (vif->ifindex,
455                                                 args->host_mac_addr.bytes);
456       if (args->error)
457         {
458           args->rv = VNET_API_ERROR_NETLINK_ERROR;
459           goto error;
460         }
461
462       if (args->host_bridge)
463         {
464           args->error = vnet_netlink_set_link_master (vif->ifindex,
465                                                       (char *)
466                                                       args->host_bridge);
467           if (args->error)
468             {
469               args->rv = VNET_API_ERROR_NETLINK_ERROR;
470               goto error;
471             }
472         }
473     }
474
475   if (args->host_ip4_prefix_len)
476     {
477       args->error = vnet_netlink_add_ip4_addr (vif->ifindex,
478                                                &args->host_ip4_addr,
479                                                args->host_ip4_prefix_len);
480       if (args->error)
481         {
482           args->rv = VNET_API_ERROR_NETLINK_ERROR;
483           goto error;
484         }
485     }
486
487   if (args->host_ip6_prefix_len)
488     {
489       args->error = vnet_netlink_add_ip6_addr (vif->ifindex,
490                                                &args->host_ip6_addr,
491                                                args->host_ip6_prefix_len);
492       if (args->error)
493         {
494           args->rv = VNET_API_ERROR_NETLINK_ERROR;
495           goto error;
496         }
497     }
498
499   args->error = vnet_netlink_set_link_state (vif->ifindex, 1 /* UP */ );
500   if (args->error)
501     {
502       args->rv = VNET_API_ERROR_NETLINK_ERROR;
503       goto error;
504     }
505
506   if (args->host_ip4_gw_set)
507     {
508       args->error = vnet_netlink_add_ip4_route (0, 0, &args->host_ip4_gw);
509       if (args->error)
510         {
511           args->rv = VNET_API_ERROR_NETLINK_ERROR;
512           goto error;
513         }
514     }
515
516   if (args->host_ip6_gw_set)
517     {
518       args->error = vnet_netlink_add_ip6_route (0, 0, &args->host_ip6_gw);
519       if (args->error)
520         {
521           args->rv = VNET_API_ERROR_NETLINK_ERROR;
522           goto error;
523         }
524     }
525
526   if (args->host_mtu_set)
527     {
528       args->error =
529         vnet_netlink_set_link_mtu (vif->ifindex, args->host_mtu_size);
530       if (args->error)
531         {
532           args->rv = VNET_API_ERROR_NETLINK_ERROR;
533           goto error;
534         }
535     }
536   else if (tm->host_mtu_size != 0)
537     {
538       args->error =
539         vnet_netlink_set_link_mtu (vif->ifindex, tm->host_mtu_size);
540       if (args->error)
541         {
542           args->rv = VNET_API_ERROR_NETLINK_ERROR;
543           goto error;
544         }
545       args->host_mtu_set = 1;
546       args->host_mtu_size = tm->host_mtu_size;
547     }
548
549   /* switch back to old net namespace */
550   if (args->host_namespace)
551     {
552       if (clib_setns (old_netns_fd) == -1)
553         {
554           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
555           args->error = clib_error_return_unix (0, "setns '%s'",
556                                                 args->host_namespace);
557           goto error;
558         }
559     }
560
561   for (i = 0; i < num_vhost_queues; i++)
562     {
563       if (i < vif->num_rxqs && (args->error =
564                                 virtio_vring_init (vm, vif, RX_QUEUE (i),
565                                                    args->rx_ring_sz)))
566         {
567           args->rv = VNET_API_ERROR_INIT_FAILED;
568           goto error;
569         }
570
571       if (i < vif->num_txqs && (args->error =
572                                 virtio_vring_init (vm, vif, TX_QUEUE (i),
573                                                    args->tx_ring_sz)))
574         {
575           args->rv = VNET_API_ERROR_INIT_FAILED;
576           goto error;
577         }
578     }
579
580   /* setup features and memtable */
581   i = sizeof (vhost_memory_t) + sizeof (vhost_memory_region_t);
582   vhost_mem = clib_mem_alloc (i);
583   clib_memset (vhost_mem, 0, i);
584   vhost_mem->nregions = 1;
585   vhost_mem->regions[0].memory_size = vpm->max_size;
586   vhost_mem->regions[0].guest_phys_addr = vpm->base_addr;
587   vhost_mem->regions[0].userspace_addr =
588     vhost_mem->regions[0].guest_phys_addr;
589
590   for (i = 0; i < vhost_mem->nregions; i++)
591     virtio_log_debug (vif, "memtable region %u memory_size 0x%lx "
592                       "guest_phys_addr 0x%lx userspace_addr 0x%lx", i,
593                       vhost_mem->regions[0].memory_size,
594                       vhost_mem->regions[0].guest_phys_addr,
595                       vhost_mem->regions[0].userspace_addr);
596
597
598   for (i = 0; i < num_vhost_queues; i++)
599     {
600       int fd = vif->vhost_fds[i];
601       _IOCTL (fd, VHOST_SET_FEATURES, &vif->features);
602       virtio_log_debug (vif, "VHOST_SET_FEATURES: fd %u features 0x%lx",
603                         fd, vif->features);
604       _IOCTL (fd, VHOST_SET_MEM_TABLE, vhost_mem);
605       virtio_log_debug (vif, "VHOST_SET_MEM_TABLE: fd %u", fd);
606     }
607
608   /* finish initializing queue pair */
609   for (i = 0; i < num_vhost_queues * 2; i++)
610     {
611       vhost_vring_addr_t addr = { 0 };
612       vhost_vring_state_t state = { 0 };
613       vhost_vring_file_t file = { 0 };
614       virtio_vring_t *vring;
615       u16 qp = i >> 1;
616       int fd = vif->vhost_fds[qp];
617
618       if (i & 1)
619         {
620           if (qp >= vif->num_txqs)
621             continue;
622           vring = vec_elt_at_index (vif->txq_vrings, qp);
623         }
624       else
625         {
626           if (qp >= vif->num_rxqs)
627             continue;
628           vring = vec_elt_at_index (vif->rxq_vrings, qp);
629         }
630
631       addr.index = state.index = file.index = vring->queue_id & 1;
632       state.num = vring->size;
633       virtio_log_debug (vif, "VHOST_SET_VRING_NUM fd %d index %u num %u", fd,
634                         state.index, state.num);
635       _IOCTL (fd, VHOST_SET_VRING_NUM, &state);
636
637       addr.flags = 0;
638       addr.desc_user_addr = pointer_to_uword (vring->desc);
639       addr.avail_user_addr = pointer_to_uword (vring->avail);
640       addr.used_user_addr = pointer_to_uword (vring->used);
641
642       virtio_log_debug (vif, "VHOST_SET_VRING_ADDR fd %d index %u flags 0x%x "
643                         "desc_user_addr 0x%lx avail_user_addr 0x%lx "
644                         "used_user_addr 0x%lx", fd, addr.index,
645                         addr.flags, addr.desc_user_addr, addr.avail_user_addr,
646                         addr.used_user_addr);
647       _IOCTL (fd, VHOST_SET_VRING_ADDR, &addr);
648
649       file.fd = vring->call_fd;
650       virtio_log_debug (vif, "VHOST_SET_VRING_CALL fd %d index %u call_fd %d",
651                         fd, file.index, file.fd);
652       _IOCTL (fd, VHOST_SET_VRING_CALL, &file);
653
654       file.fd = vring->kick_fd;
655       virtio_log_debug (vif, "VHOST_SET_VRING_KICK fd %d index %u kick_fd %d",
656                         fd, file.index, file.fd);
657       _IOCTL (fd, VHOST_SET_VRING_KICK, &file);
658
659       file.fd = vif->tap_fds[qp % vif->num_rxqs];
660       virtio_log_debug (vif, "VHOST_NET_SET_BACKEND fd %d index %u tap_fd %d",
661                         fd, file.index, file.fd);
662       _IOCTL (fd, VHOST_NET_SET_BACKEND, &file);
663     }
664
665   if (vif->type == VIRTIO_IF_TYPE_TAP)
666     {
667       if (!args->mac_addr_set)
668         ethernet_mac_address_generate (args->mac_addr.bytes);
669
670       clib_memcpy (vif->mac_addr, args->mac_addr.bytes, 6);
671       vif->host_bridge = format (0, "%s%c", args->host_bridge, 0);
672     }
673   vif->host_if_name = format (0, "%s%c", host_if_name, 0);
674   vif->net_ns = format (0, "%s%c", args->host_namespace, 0);
675   vif->host_mtu_size = args->host_mtu_size;
676   vif->tap_flags = args->tap_flags;
677   clib_memcpy (vif->host_mac_addr, args->host_mac_addr.bytes, 6);
678   vif->host_ip4_prefix_len = args->host_ip4_prefix_len;
679   vif->host_ip6_prefix_len = args->host_ip6_prefix_len;
680   if (args->host_ip4_prefix_len)
681     clib_memcpy (&vif->host_ip4_addr, &args->host_ip4_addr, 4);
682   if (args->host_ip6_prefix_len)
683     clib_memcpy (&vif->host_ip6_addr, &args->host_ip6_addr, 16);
684
685   if (vif->type != VIRTIO_IF_TYPE_TUN)
686     {
687       args->error =
688         ethernet_register_interface (vnm, virtio_device_class.index,
689                                      vif->dev_instance, vif->mac_addr,
690                                      &vif->hw_if_index,
691                                      virtio_eth_flag_change);
692       if (args->error)
693         {
694           args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
695           goto error;
696         }
697
698     }
699   else
700     {
701       vif->hw_if_index = vnet_register_interface
702         (vnm, virtio_device_class.index,
703          vif->dev_instance /* device instance */ ,
704          tun_device_hw_interface_class.index, vif->dev_instance);
705
706     }
707   tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 1);
708   sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
709   vif->sw_if_index = sw->sw_if_index;
710   args->sw_if_index = vif->sw_if_index;
711   args->rv = 0;
712   hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
713   hw->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_INT_MODE;
714   if (args->tap_flags & TAP_FLAG_GSO)
715     {
716       hw->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO |
717                   VNET_HW_INTERFACE_CAP_SUPPORTS_TX_TCP_CKSUM |
718                   VNET_HW_INTERFACE_CAP_SUPPORTS_TX_UDP_CKSUM;
719     }
720   else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
721     {
722       hw->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_TX_TCP_CKSUM |
723                   VNET_HW_INTERFACE_CAP_SUPPORTS_TX_UDP_CKSUM;
724     }
725   if ((args->tap_flags & TAP_FLAG_GSO)
726       && (args->tap_flags & TAP_FLAG_GRO_COALESCE))
727     {
728       virtio_set_packet_coalesce (vif);
729     }
730   if (vif->type == VIRTIO_IF_TYPE_TUN)
731     {
732       hw->max_supported_packet_bytes = TUN_MAX_PACKET_BYTES;
733       hw->min_packet_bytes = hw->min_supported_packet_bytes =
734         TUN_MIN_PACKET_BYTES;
735       hw->max_packet_bytes =
736         args->host_mtu_size ? args->host_mtu_size : TUN_DEFAULT_PACKET_BYTES;
737       vnet_sw_interface_set_mtu (vnm, hw->sw_if_index, hw->max_packet_bytes);
738     }
739
740   virtio_vring_set_rx_queues (vm, vif);
741
742   vif->per_interface_next_index = ~0;
743   vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
744   vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
745                                VNET_HW_INTERFACE_FLAG_LINK_UP);
746   /*
747    * Host tun/tap driver link carrier state is "up" at creation. The
748    * driver never changes this unless the backend (VPP) changes it using
749    * TUNSETCARRIER ioctl(). See tap_set_carrier().
750    */
751   vif->host_carrier_up = 1;
752   vif->cxq_vring = NULL;
753
754   goto done;
755
756 error:
757   if (err)
758     {
759       ASSERT (args->error == 0);
760       args->error = err;
761       args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
762     }
763
764   tap_log_err (vif, "%U", format_clib_error, args->error);
765   tap_free (vm, vif);
766 done:
767   if (vhost_mem)
768     clib_mem_free (vhost_mem);
769   if (old_netns_fd != -1)
770     close (old_netns_fd);
771   if (nfd != -1)
772     close (nfd);
773 }
774
775 int
776 tap_delete_if (vlib_main_t * vm, u32 sw_if_index)
777 {
778   vnet_main_t *vnm = vnet_get_main ();
779   virtio_main_t *mm = &virtio_main;
780   virtio_if_t *vif;
781   vnet_hw_interface_t *hw;
782
783   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
784   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
785     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
786
787   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
788
789   if ((vif->type != VIRTIO_IF_TYPE_TAP) && (vif->type != VIRTIO_IF_TYPE_TUN))
790     return VNET_API_ERROR_INVALID_INTERFACE;
791
792   /* bring down the interface */
793   vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
794   vnet_sw_interface_set_flags (vnm, vif->sw_if_index, 0);
795
796   if (vif->type == VIRTIO_IF_TYPE_TAP)
797     ethernet_delete_interface (vnm, vif->hw_if_index);
798   else                          /* VIRTIO_IF_TYPE_TUN */
799     vnet_delete_hw_interface (vnm, vif->hw_if_index);
800   vif->hw_if_index = ~0;
801
802   tap_free (vm, vif);
803
804   return 0;
805 }
806
807 int
808 tap_csum_offload_enable_disable (vlib_main_t * vm, u32 sw_if_index,
809                                  int enable_disable)
810 {
811   vnet_main_t *vnm = vnet_get_main ();
812   virtio_main_t *mm = &virtio_main;
813   virtio_if_t *vif;
814   vnet_hw_interface_t *hw;
815   clib_error_t *err = 0;
816   int i = 0;
817
818   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
819
820   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
821     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
822
823   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
824
825   const unsigned int csum_offload_on = TUN_F_CSUM;
826   const unsigned int csum_offload_off = 0;
827   unsigned int offload = enable_disable ? csum_offload_on : csum_offload_off;
828   vec_foreach_index (i, vif->tap_fds)
829     _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
830   vif->gso_enabled = 0;
831   vif->packet_coalesce = 0;
832   vif->csum_offload_enabled = enable_disable ? 1 : 0;
833
834   if ((hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO) != 0)
835     {
836       hw->caps &= ~VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO;
837     }
838
839   if (enable_disable)
840     {
841       hw->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_L4_TX_CKSUM;
842     }
843   else
844     {
845       hw->caps &= ~VNET_HW_INTERFACE_CAP_SUPPORTS_L4_TX_CKSUM;
846     }
847
848 error:
849   if (err)
850     {
851       clib_warning ("Error %s checksum offload on sw_if_index %d",
852                     enable_disable ? "enabling" : "disabling", sw_if_index);
853       return VNET_API_ERROR_SYSCALL_ERROR_3;
854     }
855   return 0;
856 }
857
858 int
859 tap_gso_enable_disable (vlib_main_t * vm, u32 sw_if_index, int enable_disable,
860                         int is_packet_coalesce)
861 {
862   vnet_main_t *vnm = vnet_get_main ();
863   virtio_main_t *mm = &virtio_main;
864   virtio_if_t *vif;
865   vnet_hw_interface_t *hw;
866   clib_error_t *err = 0;
867   int i = 0;
868
869   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
870
871   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
872     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
873
874   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
875
876   const unsigned int gso_on = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
877   const unsigned int gso_off = 0;
878   unsigned int offload = enable_disable ? gso_on : gso_off;
879   vec_foreach_index (i, vif->tap_fds)
880     _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
881   vif->gso_enabled = enable_disable ? 1 : 0;
882   vif->csum_offload_enabled = 0;
883   if (enable_disable)
884     {
885       if ((hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO) == 0)
886         {
887           hw->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO |
888                       VNET_HW_INTERFACE_CAP_SUPPORTS_L4_TX_CKSUM;
889         }
890       if (is_packet_coalesce)
891         {
892           virtio_set_packet_coalesce (vif);
893         }
894     }
895   else
896     {
897       if ((hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO) != 0)
898         {
899           hw->caps &= ~(VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO |
900                         VNET_HW_INTERFACE_CAP_SUPPORTS_L4_TX_CKSUM);
901         }
902       vif->packet_coalesce = 0;
903     }
904
905 error:
906   if (err)
907     {
908       clib_warning ("Error %s gso on sw_if_index %d",
909                     enable_disable ? "enabling" : "disabling", sw_if_index);
910       return VNET_API_ERROR_SYSCALL_ERROR_3;
911     }
912   return 0;
913 }
914
915 int
916 tap_dump_ifs (tap_interface_details_t ** out_tapids)
917 {
918   vnet_main_t *vnm = vnet_get_main ();
919   virtio_main_t *mm = &virtio_main;
920   virtio_if_t *vif;
921   virtio_vring_t *vring;
922   vnet_hw_interface_t *hi;
923   tap_interface_details_t *r_tapids = NULL;
924   tap_interface_details_t *tapid = NULL;
925
926   /* *INDENT-OFF* */
927   pool_foreach (vif, mm->interfaces) {
928     if ((vif->type != VIRTIO_IF_TYPE_TAP)
929       && (vif->type != VIRTIO_IF_TYPE_TUN))
930       continue;
931     vec_add2(r_tapids, tapid, 1);
932     clib_memset (tapid, 0, sizeof (*tapid));
933     tapid->id = vif->id;
934     tapid->sw_if_index = vif->sw_if_index;
935     hi = vnet_get_hw_interface (vnm, vif->hw_if_index);
936     clib_memcpy(tapid->dev_name, hi->name,
937                 MIN (ARRAY_LEN (tapid->dev_name) - 1, vec_len (hi->name)));
938     vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS(0));
939     tapid->rx_ring_sz = vring->size;
940     vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS(0));
941     tapid->tx_ring_sz = vring->size;
942     tapid->tap_flags = vif->tap_flags;
943     clib_memcpy(&tapid->host_mac_addr, vif->host_mac_addr, 6);
944     if (vif->host_if_name)
945       {
946         clib_memcpy(tapid->host_if_name, vif->host_if_name,
947                     MIN (ARRAY_LEN (tapid->host_if_name) - 1,
948                     vec_len (vif->host_if_name)));
949       }
950     if (vif->net_ns)
951       {
952         clib_memcpy(tapid->host_namespace, vif->net_ns,
953                     MIN (ARRAY_LEN (tapid->host_namespace) - 1,
954                     vec_len (vif->net_ns)));
955       }
956     if (vif->host_bridge)
957       {
958         clib_memcpy(tapid->host_bridge, vif->host_bridge,
959                     MIN (ARRAY_LEN (tapid->host_bridge) - 1,
960                     vec_len (vif->host_bridge)));
961       }
962     if (vif->host_ip4_prefix_len)
963       clib_memcpy(tapid->host_ip4_addr.as_u8, &vif->host_ip4_addr, 4);
964     tapid->host_ip4_prefix_len = vif->host_ip4_prefix_len;
965     if (vif->host_ip6_prefix_len)
966       clib_memcpy(tapid->host_ip6_addr.as_u8, &vif->host_ip6_addr, 16);
967     tapid->host_ip6_prefix_len = vif->host_ip6_prefix_len;
968     tapid->host_mtu_size = vif->host_mtu_size;
969   }
970   /* *INDENT-ON* */
971
972   *out_tapids = r_tapids;
973
974   return 0;
975 }
976
977 /*
978  * Set host tap/tun interface carrier state so it will appear to host
979  * applications that the interface's link state changed.
980  *
981  * If the kernel we're building against does not have support for the
982  * TUNSETCARRIER ioctl command, do nothing.
983  */
984 int
985 tap_set_carrier (u32 hw_if_index, u32 carrier_up)
986 {
987   int ret = 0;
988 #ifdef TUNSETCARRIER
989   vnet_main_t *vnm = vnet_get_main ();
990   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
991   virtio_main_t *mm = &virtio_main;
992   virtio_if_t *vif;
993   int *fd;
994
995   vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
996   vec_foreach (fd, vif->tap_fds)
997   {
998     ret = ioctl (*fd, TUNSETCARRIER, &carrier_up);
999     if (ret < 0)
1000       {
1001         clib_warning ("ioctl (TUNSETCARRIER) returned %d", ret);
1002         break;
1003       }
1004   }
1005   if (!ret)
1006     vif->host_carrier_up = (carrier_up != 0);
1007 #endif
1008
1009   return ret;
1010 }
1011
1012 static clib_error_t *
1013 tap_mtu_config (vlib_main_t * vm, unformat_input_t * input)
1014 {
1015   tap_main_t *tm = &tap_main;
1016
1017   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1018     {
1019       if (unformat (input, "host-mtu %d", &tm->host_mtu_size))
1020         ;
1021       else
1022         return clib_error_return (0, "unknown input `%U'",
1023                                   format_unformat_error, input);
1024     }
1025
1026   return 0;
1027 }
1028
1029 /*
1030  * Set host tap/tun interface speed in Mbps.
1031  */
1032 int
1033 tap_set_speed (u32 hw_if_index, u32 speed)
1034 {
1035   vnet_main_t *vnm = vnet_get_main ();
1036   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1037   virtio_main_t *mm = &virtio_main;
1038   virtio_if_t *vif;
1039   int old_netns_fd = -1;
1040   int nfd = -1;
1041   int ctl_fd = -1;
1042   struct ifreq ifr;
1043   struct ethtool_cmd ecmd;
1044   int ret = -1;
1045
1046   vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
1047
1048   if (vif->net_ns)
1049     {
1050       old_netns_fd = clib_netns_open (NULL /* self */);
1051       if ((nfd = clib_netns_open (vif->net_ns)) == -1)
1052         {
1053           clib_warning ("Cannot open netns");
1054           goto done;
1055         }
1056       if (clib_setns (nfd) == -1)
1057         {
1058           clib_warning ("Cannot set ns");
1059           goto done;
1060         }
1061     }
1062
1063   if ((ctl_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
1064     {
1065       clib_warning ("Cannot open control socket");
1066       goto done;
1067     }
1068
1069   ecmd.cmd = ETHTOOL_GSET;
1070   clib_memset (&ifr, 0, sizeof (ifr));
1071   clib_memcpy (ifr.ifr_name, vif->host_if_name,
1072                strlen ((const char *) vif->host_if_name));
1073   ifr.ifr_data = (void *) &ecmd;
1074   if ((ret = ioctl (ctl_fd, SIOCETHTOOL, &ifr)) < 0)
1075     {
1076       clib_warning ("Cannot get device settings");
1077       goto done;
1078     }
1079
1080   if (ethtool_cmd_speed (&ecmd) != speed)
1081     {
1082       ecmd.cmd = ETHTOOL_SSET;
1083       ethtool_cmd_speed_set (&ecmd, speed);
1084       if ((ret = ioctl (ctl_fd, SIOCETHTOOL, &ifr)) < 0)
1085         {
1086           clib_warning ("Cannot set device settings");
1087           goto done;
1088         }
1089     }
1090
1091 done:
1092   if (old_netns_fd != -1)
1093     {
1094       if (clib_setns (old_netns_fd) == -1)
1095         {
1096           clib_warning ("Cannot set old ns");
1097         }
1098       close (old_netns_fd);
1099     }
1100   if (nfd != -1)
1101     close (nfd);
1102   if (ctl_fd != -1)
1103     close (ctl_fd);
1104
1105   return ret;
1106 }
1107
1108 /* tap { host-mtu <size> } configuration. */
1109 VLIB_CONFIG_FUNCTION (tap_mtu_config, "tap");
1110
1111 static clib_error_t *
1112 tap_init (vlib_main_t * vm)
1113 {
1114   tap_main_t *tm = &tap_main;
1115   clib_error_t *error = 0;
1116
1117   tm->log_default = vlib_log_register_class ("tap", 0);
1118   vlib_log_debug (tm->log_default, "initialized");
1119
1120   tm->host_mtu_size = 0;
1121
1122   return error;
1123 }
1124
1125 VLIB_INIT_FUNCTION (tap_init);
1126
1127 /*
1128  * fd.io coding-style-patch-verification: ON
1129  *
1130  * Local Variables:
1131  * eval: (c-set-style "gnu")
1132  * End:
1133  */