FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
tap.c
Go to the documentation of this file.
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 <net/if_arp.h>
29 #include <sched.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 <vnet/ethernet/ethernet.h>
39 #include <vnet/ip/ip4_packet.h>
40 #include <vnet/ip/ip6_packet.h>
41 #include <vnet/devices/netlink.h>
43 #include <vnet/devices/tap/tap.h>
44 
46 
47 #define tap_log_err(dev, f, ...) \
48  vlib_log (VLIB_LOG_LEVEL_ERR, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
49 #define tap_log_dbg(dev, f, ...) \
50  vlib_log (VLIB_LOG_LEVEL_DEBUG, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
51 
52 #define _IOCTL(fd,a,...) \
53  if (ioctl (fd, a, __VA_ARGS__) < 0) \
54  { \
55  err = clib_error_return_unix (0, "ioctl(" #a ")"); \
56  tap_log_err (vif, "%U", format_clib_error, err); \
57  goto error; \
58  }
59 
60 static u32
62  u32 flags)
63 {
64  /* nothing for now */
65  //TODO On MTU change call vnet_netlink_set_if_mtu
66  return 0;
67 }
68 
69 static int
70 open_netns_fd (char *netns)
71 {
72  u8 *s = 0;
73  int fd;
74 
75  if (strncmp (netns, "pid:", 4) == 0)
76  s = format (0, "/proc/%u/ns/net%c", atoi (netns + 4), 0);
77  else if (netns[0] == '/')
78  s = format (0, "%s%c", netns, 0);
79  else
80  s = format (0, "/var/run/netns/%s%c", netns, 0);
81 
82  fd = open ((char *) s, O_RDONLY);
83  vec_free (s);
84  return fd;
85 }
86 
87 #define TAP_MAX_INSTANCE 1024
88 
89 static void
91 {
93  tap_main_t *tm = &tap_main;
94  int i;
95 
96  /* *INDENT-OFF* */
97  vec_foreach_index (i, vif->vhost_fds) if (vif->vhost_fds[i] != -1)
98  close (vif->vhost_fds[i]);
100  virtio_vring_free_rx (vm, vif, RX_QUEUE (i));
101  vec_foreach_index (i, vif->txq_vrings)
102  virtio_vring_free_tx (vm, vif, TX_QUEUE (i));
103  /* *INDENT-ON* */
104 
105  if (vif->tap_fd != -1)
106  close (vif->tap_fd);
107 
108  vec_free (vif->vhost_fds);
109  vec_free (vif->rxq_vrings);
110  vec_free (vif->txq_vrings);
111  vec_free (vif->host_if_name);
112  vec_free (vif->net_ns);
113  vec_free (vif->host_bridge);
114  clib_error_free (vif->error);
115 
116  tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 0);
117  clib_memset (vif, 0, sizeof (*vif));
118  pool_put (mm->interfaces, vif);
119 }
120 
121 void
123 {
125  vlib_physmem_main_t *vpm = &vm->physmem_main;
126  vnet_main_t *vnm = vnet_get_main ();
127  virtio_main_t *vim = &virtio_main;
128  tap_main_t *tm = &tap_main;
131  int i;
132  int old_netns_fd = -1;
133  struct ifreq ifr = {.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR };
134  size_t hdrsz;
135  struct vhost_memory *vhost_mem = 0;
136  virtio_if_t *vif = 0;
137  clib_error_t *err = 0;
138  unsigned int tap_features;
139  int tfd, vfd, nfd = -1;
140  char *host_if_name = 0;
141  unsigned int offload = 0;
142  u16 num_q_pairs;
143 
144  if (args->id != ~0)
145  {
146  if (clib_bitmap_get (tm->tap_ids, args->id))
147  {
148  args->rv = VNET_API_ERROR_INVALID_INTERFACE;
149  args->error = clib_error_return (0, "interface already exists");
150  return;
151  }
152  }
153  else
154  {
155  args->id = clib_bitmap_first_clear (tm->tap_ids);
156  }
157 
158  if (args->id > TAP_MAX_INSTANCE)
159  {
160  args->rv = VNET_API_ERROR_UNSPECIFIED;
161  args->error = clib_error_return (0, "cannot find free interface id");
162  return;
163  }
164 
165  pool_get_zero (vim->interfaces, vif);
166  vif->type = VIRTIO_IF_TYPE_TAP;
167  vif->dev_instance = vif - vim->interfaces;
168  vif->id = args->id;
169  vif->num_txqs = thm->n_vlib_mains;
170  vif->num_rxqs = args->num_rx_queues;
171  num_q_pairs = clib_max (vif->num_rxqs, vif->num_txqs);
172 
173  if ((vif->tap_fd = tfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
174  {
175  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
176  args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
177  goto error;
178  }
179  tap_log_dbg (vif, "open tap fd %d", tfd);
180 
181  _IOCTL (tfd, TUNGETFEATURES, &tap_features);
182  tap_log_dbg (vif, "TUNGETFEATURES: features 0x%lx", tap_features);
183  if ((tap_features & IFF_VNET_HDR) == 0)
184  {
185  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
186  args->error = clib_error_return (0, "vhost-net backend not available");
187  goto error;
188  }
189 
190  if ((tap_features & IFF_MULTI_QUEUE) == 0)
191  {
192  if (args->num_rx_queues > 1)
193  {
194  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
195  args->error = clib_error_return (0, "multiqueue not supported");
196  goto error;
197  }
198  vif->num_rxqs = vif->num_txqs = num_q_pairs = 1;
199  }
200  else
201  ifr.ifr_flags |= IFF_MULTI_QUEUE;
202 
203  hdrsz = sizeof (struct virtio_net_hdr_v1);
204  if (args->tap_flags & TAP_FLAG_GSO)
205  {
206  offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
207  vif->gso_enabled = 1;
208  }
209  else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
210  {
211  offload = TUN_F_CSUM;
212  vif->csum_offload_enabled = 1;
213  }
214 
215  _IOCTL (tfd, TUNSETIFF, (void *) &ifr);
216  tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", tfd,
217  ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
218 
219  vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
220  tap_log_dbg (vif, "ifindex %d", vif->ifindex);
221 
222  if (!args->host_if_name)
223  host_if_name = ifr.ifr_ifrn.ifrn_name;
224  else
225  host_if_name = (char *) args->host_if_name;
226 
227  if (fcntl (tfd, F_SETFL, O_NONBLOCK) < 0)
228  {
229  err = clib_error_return_unix (0, "fcntl(tfd, F_SETFL, O_NONBLOCK)");
230  tap_log_err (vif, "set nonblocking: %U", format_clib_error, err);
231  goto error;
232  }
233 
234  tap_log_dbg (vif, "TUNSETVNETHDRSZ: fd %d vnet_hdr_sz %u", tfd, hdrsz);
235  _IOCTL (tfd, TUNSETVNETHDRSZ, &hdrsz);
236 
237  i = INT_MAX;
238  tap_log_dbg (vif, "TUNSETSNDBUF: fd %d sndbuf %d", tfd, i);
239  _IOCTL (tfd, TUNSETSNDBUF, &i);
240 
241  tap_log_dbg (vif, "TUNSETOFFLOAD: fd %d offload 0x%lx", tfd, offload);
242  _IOCTL (tfd, TUNSETOFFLOAD, offload);
243 
244  /* open vhost-net fd for each queue pair and set ownership */
245  for (i = 0; i < num_q_pairs; i++)
246  {
247  if ((vfd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0)
248  {
249  args->rv = VNET_API_ERROR_SYSCALL_ERROR_1;
250  args->error = clib_error_return_unix (0, "open '/dev/vhost-net'");
251  goto error;
252  }
253  vec_add1 (vif->vhost_fds, vfd);
254  virtio_log_debug (vif, "open vhost-net fd %d qpair %u", vfd, i);
255  _IOCTL (vfd, VHOST_SET_OWNER, 0);
256  virtio_log_debug (vif, "VHOST_SET_OWNER: fd %u", vfd);
257  }
258 
259  _IOCTL (vif->vhost_fds[0], VHOST_GET_FEATURES, &vif->remote_features);
260  virtio_log_debug (vif, "VHOST_GET_FEATURES: features 0x%lx",
261  vif->remote_features);
262 
263  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
264  {
265  args->rv = VNET_API_ERROR_UNSUPPORTED;
266  args->error = clib_error_return (0, "vhost-net backend doesn't support "
267  "VIRTIO_NET_F_MRG_RXBUF feature");
268  goto error;
269  }
270 
271  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
272  0)
273  {
274  args->rv = VNET_API_ERROR_UNSUPPORTED;
275  args->error = clib_error_return (0, "vhost-net backend doesn't support "
276  "VIRTIO_RING_F_INDIRECT_DESC feature");
277  goto error;
278  }
279 
280  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1)) == 0)
281  {
282  args->rv = VNET_API_ERROR_UNSUPPORTED;
283  args->error = clib_error_return (0, "vhost-net backend doesn't support "
284  "VIRTIO_F_VERSION_1 features");
285  goto error;
286  }
287 
288  vif->features |= VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
289  vif->features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
290  vif->features |= VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
291 
293 
294  /* if namespace is specified, all further netlink messages should be executed
295  after we change our net namespace */
296  if (args->host_namespace)
297  {
298  old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
299  if ((nfd = open_netns_fd ((char *) args->host_namespace)) == -1)
300  {
301  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
302  args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
303  args->host_namespace);
304  goto error;
305  }
306  args->error = vnet_netlink_set_link_netns (vif->ifindex, nfd,
307  host_if_name);
308  if (args->error)
309  {
310  args->rv = VNET_API_ERROR_NETLINK_ERROR;
311  goto error;
312  }
313  if (setns (nfd, CLONE_NEWNET) == -1)
314  {
315  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
316  args->error = clib_error_return_unix (0, "setns '%s'",
317  args->host_namespace);
318  goto error;
319  }
320  if ((vif->ifindex = if_nametoindex (host_if_name)) == 0)
321  {
322  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
323  args->error = clib_error_return_unix (0, "if_nametoindex '%s'",
324  host_if_name);
325  goto error;
326  }
327  }
328  else
329  {
330  if (host_if_name)
331  {
333  host_if_name);
334  if (args->error)
335  {
336  args->rv = VNET_API_ERROR_NETLINK_ERROR;
337  goto error;
338  }
339  }
340  }
341 
345  args->host_mac_addr.bytes);
346  if (args->error)
347  {
348  args->rv = VNET_API_ERROR_NETLINK_ERROR;
349  goto error;
350  }
351 
352  if (args->host_bridge)
353  {
355  (char *) args->host_bridge);
356  if (args->error)
357  {
358  args->rv = VNET_API_ERROR_NETLINK_ERROR;
359  goto error;
360  }
361  }
362 
363  if (args->host_ip4_prefix_len)
364  {
366  &args->host_ip4_addr,
367  args->host_ip4_prefix_len);
368  if (args->error)
369  {
370  args->rv = VNET_API_ERROR_NETLINK_ERROR;
371  goto error;
372  }
373  }
374 
375  if (args->host_ip6_prefix_len)
376  {
378  &args->host_ip6_addr,
379  args->host_ip6_prefix_len);
380  if (args->error)
381  {
382  args->rv = VNET_API_ERROR_NETLINK_ERROR;
383  goto error;
384  }
385  }
386 
387  args->error = vnet_netlink_set_link_state (vif->ifindex, 1 /* UP */ );
388  if (args->error)
389  {
390  args->rv = VNET_API_ERROR_NETLINK_ERROR;
391  goto error;
392  }
393 
394  if (args->host_ip4_gw_set)
395  {
396  args->error = vnet_netlink_add_ip4_route (0, 0, &args->host_ip4_gw);
397  if (args->error)
398  {
399  args->rv = VNET_API_ERROR_NETLINK_ERROR;
400  goto error;
401  }
402  }
403 
404  if (args->host_ip6_gw_set)
405  {
406  args->error = vnet_netlink_add_ip6_route (0, 0, &args->host_ip6_gw);
407  if (args->error)
408  {
409  args->rv = VNET_API_ERROR_NETLINK_ERROR;
410  goto error;
411  }
412  }
413 
414  if (args->host_mtu_set)
415  {
416  args->error =
418  if (args->error)
419  {
420  args->rv = VNET_API_ERROR_NETLINK_ERROR;
421  goto error;
422  }
423  }
424  else if (tm->host_mtu_size != 0)
425  {
426  args->error =
428  if (args->error)
429  {
430  args->rv = VNET_API_ERROR_NETLINK_ERROR;
431  goto error;
432  }
433  args->host_mtu_set = 1;
434  args->host_mtu_size = tm->host_mtu_size;
435  }
436 
437  /* switch back to old net namespace */
438  if (args->host_namespace)
439  {
440  if (setns (old_netns_fd, CLONE_NEWNET) == -1)
441  {
442  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
443  args->error = clib_error_return_unix (0, "setns '%s'",
444  args->host_namespace);
445  goto error;
446  }
447  }
448 
449  for (i = 0; i < num_q_pairs; i++)
450  {
451  if (i < vif->num_rxqs && (args->error =
452  virtio_vring_init (vm, vif, RX_QUEUE (i),
453  args->rx_ring_sz)))
454  {
455  args->rv = VNET_API_ERROR_INIT_FAILED;
456  goto error;
457  }
458 
459  if (i < vif->num_txqs && (args->error =
460  virtio_vring_init (vm, vif, TX_QUEUE (i),
461  args->tx_ring_sz)))
462  {
463  args->rv = VNET_API_ERROR_INIT_FAILED;
464  goto error;
465  }
466  }
467 
468  /* setup features and memtable */
469  i = sizeof (struct vhost_memory) + sizeof (struct vhost_memory_region);
470  vhost_mem = clib_mem_alloc (i);
471  clib_memset (vhost_mem, 0, i);
472  vhost_mem->nregions = 1;
473  vhost_mem->regions[0].memory_size = vpm->max_size;
474  vhost_mem->regions[0].guest_phys_addr = vpm->base_addr;
475  vhost_mem->regions[0].userspace_addr =
476  vhost_mem->regions[0].guest_phys_addr;
477 
478  for (i = 0; i < vhost_mem->nregions; i++)
479  virtio_log_debug (vif, "memtable region %u memory_size 0x%lx "
480  "guest_phys_addr 0x%lx userspace_addr 0x%lx", i,
481  vhost_mem->regions[0].memory_size,
482  vhost_mem->regions[0].guest_phys_addr,
483  vhost_mem->regions[0].userspace_addr);
484 
485 
486  for (i = 0; i < num_q_pairs; i++)
487  {
488  int fd = vif->vhost_fds[i];
489  _IOCTL (fd, VHOST_SET_FEATURES, &vif->features);
490  virtio_log_debug (vif, "VHOST_SET_FEATURES: fd %u features 0x%lx",
491  fd, vif->features);
492  _IOCTL (fd, VHOST_SET_MEM_TABLE, vhost_mem);
493  virtio_log_debug (vif, "VHOST_SET_MEM_TABLE: fd %u", fd);
494  }
495 
496  /* finish initializing queue pair */
497  for (i = 0; i < num_q_pairs * 2; i++)
498  {
499  struct vhost_vring_addr addr = { 0 };
500  struct vhost_vring_state state = { 0 };
501  struct vhost_vring_file file = { 0 };
502  virtio_vring_t *vring;
503  u16 qp = i >> 1;
504  int fd = vif->vhost_fds[qp];
505 
506  if (i & 1)
507  {
508  if (qp >= vif->num_txqs)
509  continue;
510  vring = vec_elt_at_index (vif->txq_vrings, qp);
511  }
512  else
513  {
514  if (qp >= vif->num_rxqs)
515  continue;
516  vring = vec_elt_at_index (vif->rxq_vrings, qp);
517  }
518 
519  addr.index = state.index = file.index = vring->queue_id & 1;
520  state.num = vring->size;
521  virtio_log_debug (vif, "VHOST_SET_VRING_NUM fd %d index %u num %u", fd,
522  state.index, state.num);
523  _IOCTL (fd, VHOST_SET_VRING_NUM, &state);
524 
525  addr.flags = 0;
526  addr.desc_user_addr = pointer_to_uword (vring->desc);
527  addr.avail_user_addr = pointer_to_uword (vring->avail);
528  addr.used_user_addr = pointer_to_uword (vring->used);
529 
530  virtio_log_debug (vif, "VHOST_SET_VRING_ADDR fd %d index %u flags 0x%x "
531  "desc_user_addr 0x%lx avail_user_addr 0x%lx "
532  "used_user_addr 0x%lx", fd, addr.index,
533  addr.flags, addr.desc_user_addr, addr.avail_user_addr,
534  addr.used_user_addr);
535  _IOCTL (fd, VHOST_SET_VRING_ADDR, &addr);
536 
537  file.fd = vring->call_fd;
538  virtio_log_debug (vif, "VHOST_SET_VRING_CALL fd %d index %u call_fd %d",
539  fd, file.index, file.fd);
540  _IOCTL (fd, VHOST_SET_VRING_CALL, &file);
541 
542  file.fd = vring->kick_fd;
543  virtio_log_debug (vif, "VHOST_SET_VRING_KICK fd %d index %u kick_fd %d",
544  fd, file.index, file.fd);
545  _IOCTL (fd, VHOST_SET_VRING_KICK, &file);
546 
547  file.fd = tfd;
548  virtio_log_debug (vif, "VHOST_NET_SET_BACKEND fd %d index %u tap_fd %d",
549  fd, file.index, file.fd);
550  _IOCTL (fd, VHOST_NET_SET_BACKEND, &file);
551  }
552 
553  if (!args->mac_addr_set)
555 
556  clib_memcpy (vif->mac_addr, args->mac_addr.bytes, 6);
557 
558  vif->host_if_name = format (0, "%s%c", host_if_name, 0);
559  vif->net_ns = format (0, "%s%c", args->host_namespace, 0);
560  vif->host_bridge = format (0, "%s%c", args->host_bridge, 0);
561  vif->host_mtu_size = args->host_mtu_size;
562  clib_memcpy (vif->host_mac_addr, args->host_mac_addr.bytes, 6);
565  if (args->host_ip4_prefix_len)
566  clib_memcpy (&vif->host_ip4_addr, &args->host_ip4_addr, 4);
567  if (args->host_ip6_prefix_len)
568  clib_memcpy (&vif->host_ip6_addr, &args->host_ip6_addr, 16);
569 
571  vif->dev_instance,
572  vif->mac_addr,
573  &vif->hw_if_index,
575  if (args->error)
576  {
577  args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
578  goto error;
579  }
580 
581  tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 1);
582  sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
583  vif->sw_if_index = sw->sw_if_index;
584  args->sw_if_index = vif->sw_if_index;
585  args->rv = 0;
586  hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
588  if (args->tap_flags & TAP_FLAG_GSO)
589  {
592  }
593  else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
594  {
596  }
598  virtio_input_node.index);
599 
600  for (i = 0; i < vif->num_rxqs; i++)
601  {
605  virtio_vring_set_numa_node (vm, vif, RX_QUEUE (i));
606  }
607 
608  vif->per_interface_next_index = ~0;
609  vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
612  vif->cxq_vring = NULL;
613 
614  goto done;
615 
616 error:
617  if (err)
618  {
619  ASSERT (args->error == 0);
620  args->error = err;
621  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
622  }
623 
624  tap_log_err (vif, "%U", format_clib_error, args->error);
625  tap_free (vm, vif);
626 done:
627  if (vhost_mem)
628  clib_mem_free (vhost_mem);
629  if (old_netns_fd != -1)
630  close (old_netns_fd);
631  if (nfd != -1)
632  close (nfd);
633 }
634 
635 int
637 {
638  vnet_main_t *vnm = vnet_get_main ();
639  virtio_main_t *mm = &virtio_main;
640  int i;
641  virtio_if_t *vif;
643 
644  hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
645  if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
646  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
647 
648  vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
649 
650  if (vif->type != VIRTIO_IF_TYPE_TAP)
651  return VNET_API_ERROR_INVALID_INTERFACE;
652 
653  /* bring down the interface */
656  for (i = 0; i < vif->num_rxqs; i++)
658 
660  vif->hw_if_index = ~0;
661 
662  tap_free (vm, vif);
663 
664  return 0;
665 }
666 
667 int
669  int enable_disable)
670 {
671  vnet_main_t *vnm = vnet_get_main ();
672  virtio_main_t *mm = &virtio_main;
673  virtio_if_t *vif;
675  clib_error_t *err = 0;
676 
677  hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
678 
679  if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
680  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
681 
682  vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
683 
684  const unsigned int csum_offload_on = TUN_F_CSUM;
685  const unsigned int csum_offload_off = 0;
686  unsigned int offload = enable_disable ? csum_offload_on : csum_offload_off;
687  _IOCTL (vif->tap_fd, TUNSETOFFLOAD, offload);
688  vif->gso_enabled = 0;
689  vif->csum_offload_enabled = enable_disable ? 1 : 0;
690 
692  {
694  }
695 
696  if (enable_disable)
697  {
699  0)
700  {
702  }
703  }
704  else
705  {
707  0)
708  {
710  }
711  }
712 
713 error:
714  if (err)
715  {
716  clib_warning ("Error %s checksum offload on sw_if_index %d",
717  enable_disable ? "enabling" : "disabling", sw_if_index);
718  return VNET_API_ERROR_SYSCALL_ERROR_3;
719  }
720  return 0;
721 }
722 
723 int
725 {
726  vnet_main_t *vnm = vnet_get_main ();
727  virtio_main_t *mm = &virtio_main;
728  virtio_if_t *vif;
730  clib_error_t *err = 0;
731 
732  hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
733 
734  if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
735  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
736 
737  vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
738 
739  const unsigned int gso_on = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
740  const unsigned int gso_off = 0;
741  unsigned int offload = enable_disable ? gso_on : gso_off;
742  _IOCTL (vif->tap_fd, TUNSETOFFLOAD, offload);
743  vif->gso_enabled = enable_disable ? 1 : 0;
744  vif->csum_offload_enabled = 0;
745  if (enable_disable)
746  {
748  {
751  }
752  }
753  else
754  {
756  {
759  }
760  }
761 
762 error:
763  if (err)
764  {
765  clib_warning ("Error %s gso on sw_if_index %d",
766  enable_disable ? "enabling" : "disabling", sw_if_index);
767  return VNET_API_ERROR_SYSCALL_ERROR_3;
768  }
769  return 0;
770 }
771 
772 int
774 {
775  vnet_main_t *vnm = vnet_get_main ();
776  virtio_main_t *mm = &virtio_main;
777  virtio_if_t *vif;
778  virtio_vring_t *vring;
780  tap_interface_details_t *r_tapids = NULL;
781  tap_interface_details_t *tapid = NULL;
782 
783  /* *INDENT-OFF* */
784  pool_foreach (vif, mm->interfaces,
785  if (vif->type != VIRTIO_IF_TYPE_TAP)
786  continue;
787  vec_add2(r_tapids, tapid, 1);
788  clib_memset (tapid, 0, sizeof (*tapid));
789  tapid->id = vif->id;
790  tapid->sw_if_index = vif->sw_if_index;
791  hi = vnet_get_hw_interface (vnm, vif->hw_if_index);
792  clib_memcpy(tapid->dev_name, hi->name,
793  MIN (ARRAY_LEN (tapid->dev_name) - 1,
794  strlen ((const char *) hi->name)));
795  vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS(0));
796  tapid->rx_ring_sz = vring->size;
797  vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS(0));
798  tapid->tx_ring_sz = vring->size;
799  clib_memcpy(&tapid->host_mac_addr, vif->host_mac_addr, 6);
800  if (vif->host_if_name)
801  {
803  MIN (ARRAY_LEN (tapid->host_if_name) - 1,
804  strlen ((const char *) vif->host_if_name)));
805  }
806  if (vif->net_ns)
807  {
808  clib_memcpy(tapid->host_namespace, vif->net_ns,
809  MIN (ARRAY_LEN (tapid->host_namespace) - 1,
810  strlen ((const char *) vif->net_ns)));
811  }
812  if (vif->host_bridge)
813  {
814  clib_memcpy(tapid->host_bridge, vif->host_bridge,
815  MIN (ARRAY_LEN (tapid->host_bridge) - 1,
816  strlen ((const char *) vif->host_bridge)));
817  }
818  if (vif->host_ip4_prefix_len)
819  clib_memcpy(tapid->host_ip4_addr.as_u8, &vif->host_ip4_addr, 4);
821  if (vif->host_ip6_prefix_len)
822  clib_memcpy(tapid->host_ip6_addr.as_u8, &vif->host_ip6_addr, 16);
824  tapid->host_mtu_size = vif->host_mtu_size;
825  );
826  /* *INDENT-ON* */
827 
828  *out_tapids = r_tapids;
829 
830  return 0;
831 }
832 
833 static clib_error_t *
835 {
836  tap_main_t *tm = &tap_main;
837 
839  {
840  if (unformat (input, "host-mtu %d", &tm->host_mtu_size))
841  ;
842  else
843  return clib_error_return (0, "unknown input `%U'",
844  format_unformat_error, input);
845  }
846 
847  return 0;
848 }
849 
850 /* tap { host-mtu <size> } configuration. */
852 
853 static clib_error_t *
855 {
856  tap_main_t *tm = &tap_main;
857  clib_error_t *error = 0;
858 
859  tm->log_default = vlib_log_register_class ("tap", 0);
860  vlib_log_debug (tm->log_default, "initialized");
861 
862  tm->host_mtu_size = 0;
863 
864  return error;
865 }
866 
868 
869 /*
870  * fd.io coding-style-patch-verification: ON
871  *
872  * Local Variables:
873  * eval: (c-set-style "gnu")
874  * End:
875  */
u32 per_interface_next_index
Definition: virtio.h:151
vlib_log_class_t vlib_log_register_class(char *class, char *subclass)
Definition: log.c:176
struct vring_used * used
Definition: virtio.h:105
#define vec_foreach_index(var, v)
Iterate over vector indices.
uword * tap_ids
Definition: tap.h:82
u8 * format_clib_error(u8 *s, va_list *va)
Definition: error.c:191
int host_mtu_size
Definition: tap.h:85
vlib_node_registration_t virtio_input_node
(constructor) VLIB_REGISTER_NODE (virtio_input_node)
Definition: node.c:414
void virtio_set_net_hdr_size(virtio_if_t *vif)
Definition: virtio.c:240
virtio_if_t * interfaces
Definition: virtio.h:188
static u32 virtio_eth_flag_change(vnet_main_t *vnm, vnet_hw_interface_t *hi, u32 flags)
Definition: tap.c:61
static void tap_free(vlib_main_t *vm, virtio_if_t *vif)
Definition: tap.c:90
vlib_log_class_t log_default
Definition: tap.h:79
ip4_address_t host_ip4_addr
Definition: virtio.h:172
u8 host_if_name[64]
Definition: tap.h:66
u8 host_namespace[64]
Definition: tap.h:67
ip4_address_t host_ip4_addr
Definition: tap.h:40
void ethernet_delete_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:378
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define pool_get_zero(P, E)
Allocate an object E from a pool P and zero it.
Definition: pool.h:240
int tap_gso_enable_disable(vlib_main_t *vm, u32 sw_if_index, int enable_disable)
Definition: tap.c:724
vlib_physmem_main_t physmem_main
Definition: main.h:155
u8 as_u8[16]
Definition: ip6_packet.h:48
int gso_enabled
Definition: virtio.h:177
u32 host_mtu_size
Definition: virtio.h:176
u32 dev_instance
Definition: virtio.h:140
#define NULL
Definition: clib.h:58
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u8 host_ip6_prefix_len
Definition: tap.h:45
vnet_device_class_t virtio_device_class
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
int i
void virtio_vring_set_numa_node(vlib_main_t *vm, virtio_if_t *vif, u32 idx)
Definition: virtio.c:224
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define tap_log_dbg(dev, f,...)
Definition: tap.c:49
int tap_csum_offload_enable_disable(vlib_main_t *vm, u32 sw_if_index, int enable_disable)
Definition: tap.c:668
int tap_dump_ifs(tap_interface_details_t **out_tapids)
Definition: tap.c:773
u8 host_ip4_gw_set
Definition: tap.h:43
unsigned char u8
Definition: types.h:56
clib_error_t * virtio_vring_free_tx(vlib_main_t *vm, virtio_if_t *vif, u32 idx)
Definition: virtio.c:201
static vnet_sw_interface_t * vnet_get_hw_sw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define clib_memcpy(d, s, n)
Definition: string.h:180
u8 host_bridge[64]
Definition: tap.h:68
struct vring_avail * avail
Definition: virtio.h:106
u64 features
Definition: virtio.h:158
u32 hw_if_index
Definition: virtio.h:141
u8 host_ip6_prefix_len
Definition: virtio.h:175
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:498
vl_api_interface_index_t sw_if_index
Definition: gre.api:59
#define TX_QUEUE_ACCESS(X)
Definition: virtio.h:80
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
u8 * host_bridge
Definition: virtio.h:170
int ifindex
Definition: virtio.h:179
vnet_hw_interface_flags_t flags
Definition: interface.h:523
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
int tap_delete_if(vlib_main_t *vm, u32 sw_if_index)
Definition: tap.c:636
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
#define vlib_log_debug(...)
Definition: log.h:106
#define MIN(x, y)
Definition: node.h:31
u32 id
Definition: virtio.h:148
u16 queue_id
Definition: virtio.h:114
u16 num_txqs
Definition: virtio.h:165
#define TX_QUEUE(X)
Definition: virtio.h:78
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:519
int * vhost_fds
Definition: virtio.h:152
int tap_fd
Definition: virtio.h:153
mac_address_t host_mac_addr
Definition: tap.h:65
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
#define clib_error_return_unix(e, args...)
Definition: error.h:102
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:287
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:182
ip4_address_t host_ip4_gw
Definition: tap.h:42
ip6_address_t host_ip6_addr
Definition: tap.h:44
u8 host_ip4_prefix_len
Definition: tap.h:41
vlib_main_t * vm
Definition: in2out_ed.c:1810
#define virtio_log_debug(vif, f,...)
Definition: virtio.h:229
ip4_address_t host_ip4_addr
Definition: tap.h:69
u16 num_rxqs
Definition: virtio.h:164
virtio_vring_t * rxq_vrings
Definition: virtio.h:156
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
u32 flags
Definition: vhost_user.h:141
#define TAP_MAX_INSTANCE
Definition: tap.c:87
static int open_netns_fd(char *netns)
Definition: tap.c:70
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:342
u32 host_mtu_size
Definition: tap.h:49
ip6_address_t host_ip6_addr
Definition: virtio.h:174
static vnet_hw_interface_t * vnet_get_sup_hw_interface_api_visible_or_null(vnet_main_t *vnm, u32 sw_if_index)
#define clib_warning(format, args...)
Definition: error.h:59
u8 * net_ns
Definition: virtio.h:169
u8 mac_addr[6]
Definition: virtio.h:167
u32 flags
Definition: virtio.h:138
#define ARRAY_LEN(x)
Definition: clib.h:62
static uword clib_bitmap_get(uword *ai, uword i)
Gets the ith bit value from a bitmap.
Definition: bitmap.h:197
clib_error_t * error
Definition: virtio.h:161
u8 * host_bridge
Definition: tap.h:39
virtio_if_type_t type
Definition: virtio.h:145
#define ASSERT(truth)
void vnet_hw_interface_assign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, uword thread_index)
Definition: devices.c:139
u64 remote_features
Definition: virtio.h:158
ip6_address_t host_ip6_gw
Definition: tap.h:46
#define VIRTIO_FEATURE(X)
Definition: virtio.h:76
clib_error_t * virtio_vring_init(vlib_main_t *vm, virtio_if_t *vif, u16 idx, u16 sz)
Definition: virtio.c:65
u8 * host_if_name
Definition: tap.h:37
u8 host_mac_addr[6]
Definition: virtio.h:171
static void clib_mem_free(void *p)
Definition: mem.h:226
unsigned int if_nametoindex(const char *ifname)
static void * clib_mem_alloc(uword size)
Definition: mem.h:153
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define clib_max(x, y)
Definition: clib.h:288
virtio_main_t virtio_main
Definition: virtio.c:37
vl_api_ip4_address_t hi
Definition: arp.api:37
u8 host_ip6_gw_set
Definition: tap.h:47
void tap_create_if(vlib_main_t *vm, tap_create_if_args_t *args)
Definition: tap.c:122
#define RX_QUEUE_ACCESS(X)
Definition: virtio.h:81
tap_main_t tap_main
Definition: tap.c:45
int csum_offload_enabled
Definition: virtio.h:178
#define tap_log_err(dev, f,...)
Definition: tap.c:47
static void ethernet_mac_address_generate(u8 *mac)
Definition: mac_address.h:74
clib_error_t * ethernet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, const u8 *address, u32 *hw_if_index_return, ethernet_flag_change_function_t flag_change)
Definition: interface.c:331
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, vnet_hw_interface_flags_t flags)
Definition: interface.c:492
Definition: tap.h:76
mac_address_t host_mac_addr
Definition: tap.h:38
mac_address_t mac_addr
Definition: tap.h:29
#define clib_error_free(e)
Definition: error.h:86
clib_error_t * error
Definition: tap.h:53
ip6_address_t host_ip6_addr
Definition: tap.h:71
u8 host_ip4_prefix_len
Definition: virtio.h:173
int vnet_hw_interface_unassign_rx_thread(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.c:188
u32 sw_if_index
Definition: virtio.h:142
virtio_vring_t * cxq_vring
Definition: virtio.h:180
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static int ethernet_mac_address_is_zero(const u8 *mac)
Definition: mac_address.h:68
clib_error_t * virtio_vring_free_rx(vlib_main_t *vm, virtio_if_t *vif, u32 idx)
Definition: virtio.c:153
TAP interface details struct.
Definition: tap.h:57
clib_error_t * vnet_sw_interface_set_flags(vnet_main_t *vnm, u32 sw_if_index, vnet_sw_interface_flags_t flags)
Definition: interface.c:501
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
static clib_error_t * tap_mtu_config(vlib_main_t *vm, unformat_input_t *input)
Definition: tap.c:834
struct vring_desc * desc
Definition: virtio.h:104
int vnet_hw_interface_set_rx_mode(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id, vnet_hw_interface_rx_mode mode)
Definition: devices.c:253
u8 * host_namespace
Definition: tap.h:36
static uword clib_bitmap_first_clear(uword *ai)
Return the lowest numbered clear bit in a bitmap.
Definition: bitmap.h:445
#define RX_QUEUE(X)
Definition: virtio.h:79
static void vnet_hw_interface_set_input_node(vnet_main_t *vnm, u32 hw_if_index, u32 node_index)
Definition: devices.h:79
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
virtio_vring_t * txq_vrings
Definition: virtio.h:157
static clib_error_t * tap_init(vlib_main_t *vm)
Definition: tap.c:854
u8 * host_if_name
Definition: virtio.h:168