FD.io VPP  v20.09-64-g4f7b92f0a
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 <sys/eventfd.h>
26 #include <net/if_arp.h>
27 #include <sched.h>
28 #include <limits.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>
41 #include <vnet/devices/tap/tap.h>
42 
44 
45 #define tap_log_err(dev, f, ...) \
46  vlib_log (VLIB_LOG_LEVEL_ERR, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
47 #define tap_log_dbg(dev, f, ...) \
48  vlib_log (VLIB_LOG_LEVEL_DEBUG, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
49 
50 #define _IOCTL(fd,a,...) \
51  if (ioctl (fd, a, __VA_ARGS__) < 0) \
52  { \
53  err = clib_error_return_unix (0, "ioctl(" #a ")"); \
54  tap_log_err (vif, "%U", format_clib_error, err); \
55  goto error; \
56  }
57 
58  /* *INDENT-OFF* */
59 VNET_HW_INTERFACE_CLASS (tun_device_hw_interface_class, static) =
60 {
61  .name = "tun-device",
63 };
64  /* *INDENT-ON* */
65 
66 static u32
68  u32 flags)
69 {
70  /* nothing for now */
71  //TODO On MTU change call vnet_netlink_set_if_mtu
72  return 0;
73 }
74 
75 static int
76 open_netns_fd (char *netns)
77 {
78  u8 *s = 0;
79  int fd;
80 
81  if (strncmp (netns, "pid:", 4) == 0)
82  s = format (0, "/proc/%u/ns/net%c", atoi (netns + 4), 0);
83  else if (netns[0] == '/')
84  s = format (0, "%s%c", netns, 0);
85  else
86  s = format (0, "/var/run/netns/%s%c", netns, 0);
87 
88  fd = open ((char *) s, O_RDONLY);
89  vec_free (s);
90  return fd;
91 }
92 
93 #define TAP_MAX_INSTANCE 1024
94 
95 static void
97 {
99  tap_main_t *tm = &tap_main;
100  clib_error_t *err = 0;
101  int i;
102 
103  /* *INDENT-OFF* */
104  vec_foreach_index (i, vif->vhost_fds) if (vif->vhost_fds[i] != -1)
105  close (vif->vhost_fds[i]);
106  vec_foreach_index (i, vif->rxq_vrings)
107  virtio_vring_free_rx (vm, vif, RX_QUEUE (i));
108  vec_foreach_index (i, vif->txq_vrings)
109  virtio_vring_free_tx (vm, vif, TX_QUEUE (i));
110  /* *INDENT-ON* */
111 
112  _IOCTL (vif->tap_fds[0], TUNSETPERSIST, (void *) (uintptr_t) 0);
113  tap_log_dbg (vif, "TUNSETPERSIST: unset");
114 error:
115  vec_foreach_index (i, vif->tap_fds) close (vif->tap_fds[i]);
116 
117  vec_free (vif->vhost_fds);
118  vec_free (vif->rxq_vrings);
119  vec_free (vif->txq_vrings);
120  vec_free (vif->host_if_name);
121  vec_free (vif->net_ns);
122  vec_free (vif->host_bridge);
123  clib_error_free (vif->error);
124 
125  tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 0);
126  clib_memset (vif, 0, sizeof (*vif));
127  pool_put (mm->interfaces, vif);
128 }
129 
130 void
132 {
134  vlib_physmem_main_t *vpm = &vm->physmem_main;
135  vnet_main_t *vnm = vnet_get_main ();
136  virtio_main_t *vim = &virtio_main;
137  tap_main_t *tm = &tap_main;
140  int i, num_vhost_queues;
141  int old_netns_fd = -1;
142  struct ifreq ifr = {.ifr_flags = IFF_NO_PI | IFF_VNET_HDR };
143  struct ifreq get_ifr = {.ifr_flags = 0 };
144  size_t hdrsz;
145  vhost_memory_t *vhost_mem = 0;
146  virtio_if_t *vif = 0;
147  clib_error_t *err = 0;
148  unsigned int tap_features;
149  int tfd = -1, qfd = -1, vfd = -1, nfd = -1;
150  char *host_if_name = 0;
151  unsigned int offload = 0;
152  int sndbuf = 0;
153 
154  if (args->id != ~0)
155  {
156  if (clib_bitmap_get (tm->tap_ids, args->id))
157  {
158  args->rv = VNET_API_ERROR_INVALID_INTERFACE;
159  args->error = clib_error_return (0, "interface already exists");
160  return;
161  }
162  }
163  else
164  {
165  args->id = clib_bitmap_first_clear (tm->tap_ids);
166  }
167 
168  if (args->id > TAP_MAX_INSTANCE)
169  {
170  args->rv = VNET_API_ERROR_UNSPECIFIED;
171  args->error = clib_error_return (0, "cannot find free interface id");
172  return;
173  }
174 
175  pool_get_zero (vim->interfaces, vif);
176 
177  if (args->tap_flags & TAP_FLAG_TUN)
178  {
179  vif->type = VIRTIO_IF_TYPE_TUN;
180  ifr.ifr_flags |= IFF_TUN;
181 
182  /*
183  * From kernel 4.20, xdp support has been added in tun_sendmsg.
184  * If sndbuf == INT_MAX, vhost batches the packet and processes
185  * them using xdp data path for tun driver. It assumes packets
186  * are ethernet frames (It needs to be fixed).
187  * To avoid xdp data path in tun driver, sndbuf value should
188  * be < INT_MAX.
189  */
190  sndbuf = INT_MAX - 1;
191  }
192  else
193  {
194  vif->type = VIRTIO_IF_TYPE_TAP;
195  ifr.ifr_flags |= IFF_TAP;
196  sndbuf = INT_MAX;
197  }
198 
199  vif->dev_instance = vif - vim->interfaces;
200  vif->id = args->id;
201  vif->num_txqs = thm->n_vlib_mains;
202  vif->num_rxqs = clib_max (args->num_rx_queues, 1);
203 
204  if (args->tap_flags & TAP_FLAG_ATTACH)
205  {
206  if (args->host_if_name != NULL)
207  {
208  host_if_name = (char *) args->host_if_name;
209  clib_memcpy (ifr.ifr_name, host_if_name,
210  clib_min (IFNAMSIZ, strlen (host_if_name)));
211  }
212  else
213  {
214  args->rv = VNET_API_ERROR_NO_MATCHING_INTERFACE;
215  err = clib_error_return (0, "host_if_name is not provided");
216  goto error;
217  }
218  if (args->host_namespace)
219  {
220  old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
221  if ((nfd = open_netns_fd ((char *) args->host_namespace)) == -1)
222  {
223  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
224  args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
225  args->host_namespace);
226  goto error;
227  }
228  if (setns (nfd, CLONE_NEWNET) == -1)
229  {
230  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
231  args->error = clib_error_return_unix (0, "setns '%s'",
232  args->host_namespace);
233  goto error;
234  }
235  }
236  }
237 
238  if ((tfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
239  {
240  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
241  args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
242  goto error;
243  }
244  vec_add1 (vif->tap_fds, tfd);
245  tap_log_dbg (vif, "open tap fd %d", tfd);
246 
247  _IOCTL (tfd, TUNGETFEATURES, &tap_features);
248  tap_log_dbg (vif, "TUNGETFEATURES: features 0x%lx", tap_features);
249  if ((tap_features & IFF_VNET_HDR) == 0)
250  {
251  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
252  args->error = clib_error_return (0, "vhost-net backend not available");
253  goto error;
254  }
255 
256  if ((tap_features & IFF_MULTI_QUEUE) == 0)
257  {
258  if (vif->num_rxqs > 1)
259  {
260  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
261  args->error = clib_error_return (0, "multiqueue not supported");
262  goto error;
263  }
264  vif->num_rxqs = vif->num_txqs = 1;
265  }
266  else
267  ifr.ifr_flags |= IFF_MULTI_QUEUE;
268 
269  hdrsz = sizeof (virtio_net_hdr_v1_t);
270  if (args->tap_flags & TAP_FLAG_GSO)
271  {
272  offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
273  vif->gso_enabled = 1;
274  }
275  else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
276  {
277  offload = TUN_F_CSUM;
278  vif->csum_offload_enabled = 1;
279  }
280 
281  _IOCTL (tfd, TUNSETIFF, (void *) &ifr);
282  tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", tfd,
283  ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
284 
285  vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
286  tap_log_dbg (vif, "ifindex %d", vif->ifindex);
287 
288  if (!args->host_if_name)
289  host_if_name = ifr.ifr_ifrn.ifrn_name;
290  else
291  host_if_name = (char *) args->host_if_name;
292 
293  /*
294  * unset the persistence when attaching to existing
295  * interface
296  */
297  if (args->tap_flags & TAP_FLAG_ATTACH)
298  {
299  _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 0);
300  tap_log_dbg (vif, "TUNSETPERSIST: unset");
301  }
302 
303  /* set the persistence */
304  if (args->tap_flags & TAP_FLAG_PERSIST)
305  {
306  _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 1);
307  tap_log_dbg (vif, "TUNSETPERSIST: set");
308 
309  /* verify persistence is set, read the flags */
310  _IOCTL (tfd, TUNGETIFF, (void *) &get_ifr);
311  tap_log_dbg (vif, "TUNGETIFF: flags 0x%lx", get_ifr.ifr_flags);
312  if ((get_ifr.ifr_flags & IFF_PERSIST) == 0)
313  {
314  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
315  args->error = clib_error_return (0, "persistence not supported");
316  goto error;
317  }
318  }
319 
320  /* create additional queues on the linux side.
321  * we create as many linux queue pairs as we have rx queues
322  */
323  for (i = 1; i < vif->num_rxqs; i++)
324  {
325  if ((qfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
326  {
327  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
328  args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
329  goto error;
330  }
331  _IOCTL (qfd, TUNSETIFF, (void *) &ifr);
332  tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", qfd,
333  ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
334  vec_add1 (vif->tap_fds, qfd);
335  }
336 
337  for (i = 0; i < vif->num_rxqs; i++)
338  {
339  tap_log_dbg (vif, "TUNSETVNETHDRSZ: fd %d vnet_hdr_sz %u",
340  vif->tap_fds[i], hdrsz);
341  _IOCTL (vif->tap_fds[i], TUNSETVNETHDRSZ, &hdrsz);
342 
343  tap_log_dbg (vif, "TUNSETSNDBUF: fd %d sndbuf %d", vif->tap_fds[i],
344  sndbuf);
345  _IOCTL (vif->tap_fds[i], TUNSETSNDBUF, &sndbuf);
346 
347  tap_log_dbg (vif, "TUNSETOFFLOAD: fd %d offload 0x%lx", vif->tap_fds[i],
348  offload);
349  _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
350 
351  if (fcntl (vif->tap_fds[i], F_SETFL, O_NONBLOCK) < 0)
352  {
353  err = clib_error_return_unix (0, "fcntl(tfd, F_SETFL, O_NONBLOCK)");
354  tap_log_err (vif, "set nonblocking: %U", format_clib_error, err);
355  goto error;
356  }
357  }
358 
359  /* open as many vhost-net fds as required and set ownership */
360  num_vhost_queues = clib_max (vif->num_rxqs, vif->num_txqs);
361  for (i = 0; i < num_vhost_queues; i++)
362  {
363  if ((vfd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0)
364  {
365  args->rv = VNET_API_ERROR_SYSCALL_ERROR_1;
366  args->error = clib_error_return_unix (0, "open '/dev/vhost-net'");
367  goto error;
368  }
369  vec_add1 (vif->vhost_fds, vfd);
370  virtio_log_debug (vif, "open vhost-net fd %d qpair %u", vfd, i);
371  _IOCTL (vfd, VHOST_SET_OWNER, 0);
372  virtio_log_debug (vif, "VHOST_SET_OWNER: fd %u", vfd);
373  }
374 
375  _IOCTL (vif->vhost_fds[0], VHOST_GET_FEATURES, &vif->remote_features);
376  virtio_log_debug (vif, "VHOST_GET_FEATURES: features 0x%lx",
377  vif->remote_features);
378 
379  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
380  {
381  args->rv = VNET_API_ERROR_UNSUPPORTED;
382  args->error = clib_error_return (0, "vhost-net backend doesn't support "
383  "VIRTIO_NET_F_MRG_RXBUF feature");
384  goto error;
385  }
386 
387  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
388  0)
389  {
390  args->rv = VNET_API_ERROR_UNSUPPORTED;
391  args->error = clib_error_return (0, "vhost-net backend doesn't support "
392  "VIRTIO_RING_F_INDIRECT_DESC feature");
393  goto error;
394  }
395 
396  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1)) == 0)
397  {
398  args->rv = VNET_API_ERROR_UNSUPPORTED;
399  args->error = clib_error_return (0, "vhost-net backend doesn't support "
400  "VIRTIO_F_VERSION_1 features");
401  goto error;
402  }
403 
404  vif->features |= VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
405  vif->features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
406  vif->features |= VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
407 
409 
410  if (!(args->tap_flags & TAP_FLAG_ATTACH))
411  {
412  /* if namespace is specified, all further netlink messages should be executed
413  after we change our net namespace */
414  if (args->host_namespace)
415  {
416  old_netns_fd = open ("/proc/self/ns/net", O_RDONLY);
417  if ((nfd = open_netns_fd ((char *) args->host_namespace)) == -1)
418  {
419  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
420  args->error = clib_error_return_unix (0, "open_netns_fd '%s'",
421  args->host_namespace);
422  goto error;
423  }
424  args->error = vnet_netlink_set_link_netns (vif->ifindex, nfd,
425  host_if_name);
426  if (args->error)
427  {
428  args->rv = VNET_API_ERROR_NETLINK_ERROR;
429  goto error;
430  }
431  if (setns (nfd, CLONE_NEWNET) == -1)
432  {
433  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
434  args->error = clib_error_return_unix (0, "setns '%s'",
435  args->host_namespace);
436  goto error;
437  }
438  if ((vif->ifindex = if_nametoindex (host_if_name)) == 0)
439  {
440  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
441  args->error = clib_error_return_unix (0, "if_nametoindex '%s'",
442  host_if_name);
443  goto error;
444  }
445  }
446  else if (host_if_name)
447  {
448  args->error =
449  vnet_netlink_set_link_name (vif->ifindex, host_if_name);
450  if (args->error)
451  {
452  args->rv = VNET_API_ERROR_NETLINK_ERROR;
453  goto error;
454  }
455  }
456  }
457 
458  if (vif->type == VIRTIO_IF_TYPE_TAP)
459  {
463  args->host_mac_addr.bytes);
464  if (args->error)
465  {
466  args->rv = VNET_API_ERROR_NETLINK_ERROR;
467  goto error;
468  }
469 
470  if (args->host_bridge)
471  {
473  (char *)
474  args->host_bridge);
475  if (args->error)
476  {
477  args->rv = VNET_API_ERROR_NETLINK_ERROR;
478  goto error;
479  }
480  }
481  }
482 
483  if (args->host_ip4_prefix_len)
484  {
486  &args->host_ip4_addr,
487  args->host_ip4_prefix_len);
488  if (args->error)
489  {
490  args->rv = VNET_API_ERROR_NETLINK_ERROR;
491  goto error;
492  }
493  }
494 
495  if (args->host_ip6_prefix_len)
496  {
498  &args->host_ip6_addr,
499  args->host_ip6_prefix_len);
500  if (args->error)
501  {
502  args->rv = VNET_API_ERROR_NETLINK_ERROR;
503  goto error;
504  }
505  }
506 
507  args->error = vnet_netlink_set_link_state (vif->ifindex, 1 /* UP */ );
508  if (args->error)
509  {
510  args->rv = VNET_API_ERROR_NETLINK_ERROR;
511  goto error;
512  }
513 
514  if (args->host_ip4_gw_set)
515  {
516  args->error = vnet_netlink_add_ip4_route (0, 0, &args->host_ip4_gw);
517  if (args->error)
518  {
519  args->rv = VNET_API_ERROR_NETLINK_ERROR;
520  goto error;
521  }
522  }
523 
524  if (args->host_ip6_gw_set)
525  {
526  args->error = vnet_netlink_add_ip6_route (0, 0, &args->host_ip6_gw);
527  if (args->error)
528  {
529  args->rv = VNET_API_ERROR_NETLINK_ERROR;
530  goto error;
531  }
532  }
533 
534  if (args->host_mtu_set)
535  {
536  args->error =
538  if (args->error)
539  {
540  args->rv = VNET_API_ERROR_NETLINK_ERROR;
541  goto error;
542  }
543  }
544  else if (tm->host_mtu_size != 0)
545  {
546  args->error =
548  if (args->error)
549  {
550  args->rv = VNET_API_ERROR_NETLINK_ERROR;
551  goto error;
552  }
553  args->host_mtu_set = 1;
554  args->host_mtu_size = tm->host_mtu_size;
555  }
556 
557  /* switch back to old net namespace */
558  if (args->host_namespace)
559  {
560  if (setns (old_netns_fd, CLONE_NEWNET) == -1)
561  {
562  args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
563  args->error = clib_error_return_unix (0, "setns '%s'",
564  args->host_namespace);
565  goto error;
566  }
567  }
568 
569  for (i = 0; i < num_vhost_queues; i++)
570  {
571  if (i < vif->num_rxqs && (args->error =
572  virtio_vring_init (vm, vif, RX_QUEUE (i),
573  args->rx_ring_sz)))
574  {
575  args->rv = VNET_API_ERROR_INIT_FAILED;
576  goto error;
577  }
578 
579  if (i < vif->num_txqs && (args->error =
580  virtio_vring_init (vm, vif, TX_QUEUE (i),
581  args->tx_ring_sz)))
582  {
583  args->rv = VNET_API_ERROR_INIT_FAILED;
584  goto error;
585  }
586  }
587 
588  /* setup features and memtable */
589  i = sizeof (vhost_memory_t) + sizeof (vhost_memory_region_t);
590  vhost_mem = clib_mem_alloc (i);
591  clib_memset (vhost_mem, 0, i);
592  vhost_mem->nregions = 1;
593  vhost_mem->regions[0].memory_size = vpm->max_size;
594  vhost_mem->regions[0].guest_phys_addr = vpm->base_addr;
595  vhost_mem->regions[0].userspace_addr =
596  vhost_mem->regions[0].guest_phys_addr;
597 
598  for (i = 0; i < vhost_mem->nregions; i++)
599  virtio_log_debug (vif, "memtable region %u memory_size 0x%lx "
600  "guest_phys_addr 0x%lx userspace_addr 0x%lx", i,
601  vhost_mem->regions[0].memory_size,
602  vhost_mem->regions[0].guest_phys_addr,
603  vhost_mem->regions[0].userspace_addr);
604 
605 
606  for (i = 0; i < num_vhost_queues; i++)
607  {
608  int fd = vif->vhost_fds[i];
609  _IOCTL (fd, VHOST_SET_FEATURES, &vif->features);
610  virtio_log_debug (vif, "VHOST_SET_FEATURES: fd %u features 0x%lx",
611  fd, vif->features);
612  _IOCTL (fd, VHOST_SET_MEM_TABLE, vhost_mem);
613  virtio_log_debug (vif, "VHOST_SET_MEM_TABLE: fd %u", fd);
614  }
615 
616  /* finish initializing queue pair */
617  for (i = 0; i < num_vhost_queues * 2; i++)
618  {
619  vhost_vring_addr_t addr = { 0 };
620  vhost_vring_state_t state = { 0 };
621  vhost_vring_file_t file = { 0 };
622  virtio_vring_t *vring;
623  u16 qp = i >> 1;
624  int fd = vif->vhost_fds[qp];
625 
626  if (i & 1)
627  {
628  if (qp >= vif->num_txqs)
629  continue;
630  vring = vec_elt_at_index (vif->txq_vrings, qp);
631  }
632  else
633  {
634  if (qp >= vif->num_rxqs)
635  continue;
636  vring = vec_elt_at_index (vif->rxq_vrings, qp);
637  }
638 
639  addr.index = state.index = file.index = vring->queue_id & 1;
640  state.num = vring->size;
641  virtio_log_debug (vif, "VHOST_SET_VRING_NUM fd %d index %u num %u", fd,
642  state.index, state.num);
643  _IOCTL (fd, VHOST_SET_VRING_NUM, &state);
644 
645  addr.flags = 0;
646  addr.desc_user_addr = pointer_to_uword (vring->desc);
647  addr.avail_user_addr = pointer_to_uword (vring->avail);
648  addr.used_user_addr = pointer_to_uword (vring->used);
649 
650  virtio_log_debug (vif, "VHOST_SET_VRING_ADDR fd %d index %u flags 0x%x "
651  "desc_user_addr 0x%lx avail_user_addr 0x%lx "
652  "used_user_addr 0x%lx", fd, addr.index,
653  addr.flags, addr.desc_user_addr, addr.avail_user_addr,
654  addr.used_user_addr);
655  _IOCTL (fd, VHOST_SET_VRING_ADDR, &addr);
656 
657  file.fd = vring->call_fd;
658  virtio_log_debug (vif, "VHOST_SET_VRING_CALL fd %d index %u call_fd %d",
659  fd, file.index, file.fd);
660  _IOCTL (fd, VHOST_SET_VRING_CALL, &file);
661 
662  file.fd = vring->kick_fd;
663  virtio_log_debug (vif, "VHOST_SET_VRING_KICK fd %d index %u kick_fd %d",
664  fd, file.index, file.fd);
665  _IOCTL (fd, VHOST_SET_VRING_KICK, &file);
666 
667  file.fd = vif->tap_fds[qp % vif->num_rxqs];
668  virtio_log_debug (vif, "VHOST_NET_SET_BACKEND fd %d index %u tap_fd %d",
669  fd, file.index, file.fd);
670  _IOCTL (fd, VHOST_NET_SET_BACKEND, &file);
671  }
672 
673  if (vif->type == VIRTIO_IF_TYPE_TAP)
674  {
675  if (!args->mac_addr_set)
677 
678  clib_memcpy (vif->mac_addr, args->mac_addr.bytes, 6);
679  vif->host_bridge = format (0, "%s%c", args->host_bridge, 0);
680  }
681  vif->host_if_name = format (0, "%s%c", host_if_name, 0);
682  vif->net_ns = format (0, "%s%c", args->host_namespace, 0);
683  vif->host_mtu_size = args->host_mtu_size;
684  vif->tap_flags = args->tap_flags;
685  clib_memcpy (vif->host_mac_addr, args->host_mac_addr.bytes, 6);
688  if (args->host_ip4_prefix_len)
689  clib_memcpy (&vif->host_ip4_addr, &args->host_ip4_addr, 4);
690  if (args->host_ip6_prefix_len)
691  clib_memcpy (&vif->host_ip6_addr, &args->host_ip6_addr, 16);
692 
693  if (vif->type != VIRTIO_IF_TYPE_TUN)
694  {
695  args->error =
697  vif->dev_instance, vif->mac_addr,
698  &vif->hw_if_index,
700  if (args->error)
701  {
702  args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
703  goto error;
704  }
705 
706  }
707  else
708  {
710  (vnm, virtio_device_class.index,
711  vif->dev_instance /* device instance */ ,
712  tun_device_hw_interface_class.index, vif->dev_instance);
713 
714  }
715  tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 1);
716  sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
717  vif->sw_if_index = sw->sw_if_index;
718  args->sw_if_index = vif->sw_if_index;
719  args->rv = 0;
720  hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
722  if (args->tap_flags & TAP_FLAG_GSO)
723  {
726  }
727  else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
728  {
730  }
731  if ((args->tap_flags & TAP_FLAG_GSO)
732  && (args->tap_flags & TAP_FLAG_GRO_COALESCE))
733  {
735  }
737  virtio_input_node.index);
738 
739  for (i = 0; i < vif->num_rxqs; i++)
740  {
744  virtio_vring_set_numa_node (vm, vif, RX_QUEUE (i));
745  }
746 
747  vif->per_interface_next_index = ~0;
748  vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
751  vif->cxq_vring = NULL;
752 
753  goto done;
754 
755 error:
756  if (err)
757  {
758  ASSERT (args->error == 0);
759  args->error = err;
760  args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
761  }
762 
763  tap_log_err (vif, "%U", format_clib_error, args->error);
764  tap_free (vm, vif);
765 done:
766  if (vhost_mem)
767  clib_mem_free (vhost_mem);
768  if (old_netns_fd != -1)
769  close (old_netns_fd);
770  if (nfd != -1)
771  close (nfd);
772 }
773 
774 int
776 {
777  vnet_main_t *vnm = vnet_get_main ();
778  virtio_main_t *mm = &virtio_main;
779  int i;
780  virtio_if_t *vif;
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 */
795  for (i = 0; i < vif->num_rxqs; i++)
797 
798  if (vif->type == VIRTIO_IF_TYPE_TAP)
800  else /* VIRTIO_IF_TYPE_TUN */
802  vif->hw_if_index = ~0;
803 
804  tap_free (vm, vif);
805 
806  return 0;
807 }
808 
809 int
811  int enable_disable)
812 {
813  vnet_main_t *vnm = vnet_get_main ();
814  virtio_main_t *mm = &virtio_main;
815  virtio_if_t *vif;
817  clib_error_t *err = 0;
818  int i = 0;
819 
820  hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
821 
822  if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
823  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
824 
825  vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
826 
827  const unsigned int csum_offload_on = TUN_F_CSUM;
828  const unsigned int csum_offload_off = 0;
829  unsigned int offload = enable_disable ? csum_offload_on : csum_offload_off;
830  vec_foreach_index (i, vif->tap_fds)
831  _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
832  vif->gso_enabled = 0;
833  vif->packet_coalesce = 0;
834  vif->csum_offload_enabled = enable_disable ? 1 : 0;
835 
837  {
839  }
840 
841  if (enable_disable)
842  {
844  0)
845  {
847  }
848  }
849  else
850  {
852  0)
853  {
855  }
856  }
857 
858 error:
859  if (err)
860  {
861  clib_warning ("Error %s checksum offload on sw_if_index %d",
862  enable_disable ? "enabling" : "disabling", sw_if_index);
863  return VNET_API_ERROR_SYSCALL_ERROR_3;
864  }
865  return 0;
866 }
867 
868 int
870  int is_packet_coalesce)
871 {
872  vnet_main_t *vnm = vnet_get_main ();
873  virtio_main_t *mm = &virtio_main;
874  virtio_if_t *vif;
876  clib_error_t *err = 0;
877  int i = 0;
878 
879  hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
880 
881  if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
882  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
883 
884  vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
885 
886  const unsigned int gso_on = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
887  const unsigned int gso_off = 0;
888  unsigned int offload = enable_disable ? gso_on : gso_off;
889  vec_foreach_index (i, vif->tap_fds)
890  _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
891  vif->gso_enabled = enable_disable ? 1 : 0;
892  vif->csum_offload_enabled = 0;
893  if (enable_disable)
894  {
896  {
899  }
900  if (is_packet_coalesce)
901  {
903  }
904  }
905  else
906  {
908  {
911  }
912  vif->packet_coalesce = 0;
913  }
914 
915 error:
916  if (err)
917  {
918  clib_warning ("Error %s gso on sw_if_index %d",
919  enable_disable ? "enabling" : "disabling", sw_if_index);
920  return VNET_API_ERROR_SYSCALL_ERROR_3;
921  }
922  return 0;
923 }
924 
925 int
927 {
928  vnet_main_t *vnm = vnet_get_main ();
929  virtio_main_t *mm = &virtio_main;
930  virtio_if_t *vif;
931  virtio_vring_t *vring;
933  tap_interface_details_t *r_tapids = NULL;
934  tap_interface_details_t *tapid = NULL;
935 
936  /* *INDENT-OFF* */
937  pool_foreach (vif, mm->interfaces,
938  if ((vif->type != VIRTIO_IF_TYPE_TAP)
939  && (vif->type != VIRTIO_IF_TYPE_TUN))
940  continue;
941  vec_add2(r_tapids, tapid, 1);
942  clib_memset (tapid, 0, sizeof (*tapid));
943  tapid->id = vif->id;
944  tapid->sw_if_index = vif->sw_if_index;
945  hi = vnet_get_hw_interface (vnm, vif->hw_if_index);
946  clib_memcpy(tapid->dev_name, hi->name,
947  MIN (ARRAY_LEN (tapid->dev_name) - 1, vec_len (hi->name)));
948  vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS(0));
949  tapid->rx_ring_sz = vring->size;
950  vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS(0));
951  tapid->tx_ring_sz = vring->size;
952  tapid->tap_flags = vif->tap_flags;
953  clib_memcpy(&tapid->host_mac_addr, vif->host_mac_addr, 6);
954  if (vif->host_if_name)
955  {
957  MIN (ARRAY_LEN (tapid->host_if_name) - 1,
958  strlen ((const char *) vif->host_if_name)));
959  }
960  if (vif->net_ns)
961  {
962  clib_memcpy(tapid->host_namespace, vif->net_ns,
963  MIN (ARRAY_LEN (tapid->host_namespace) - 1,
964  strlen ((const char *) vif->net_ns)));
965  }
966  if (vif->host_bridge)
967  {
968  clib_memcpy(tapid->host_bridge, vif->host_bridge,
969  MIN (ARRAY_LEN (tapid->host_bridge) - 1,
970  strlen ((const char *) vif->host_bridge)));
971  }
972  if (vif->host_ip4_prefix_len)
973  clib_memcpy(tapid->host_ip4_addr.as_u8, &vif->host_ip4_addr, 4);
975  if (vif->host_ip6_prefix_len)
976  clib_memcpy(tapid->host_ip6_addr.as_u8, &vif->host_ip6_addr, 16);
978  tapid->host_mtu_size = vif->host_mtu_size;
979  );
980  /* *INDENT-ON* */
981 
982  *out_tapids = r_tapids;
983 
984  return 0;
985 }
986 
987 static clib_error_t *
989 {
990  tap_main_t *tm = &tap_main;
991 
993  {
994  if (unformat (input, "host-mtu %d", &tm->host_mtu_size))
995  ;
996  else
997  return clib_error_return (0, "unknown input `%U'",
998  format_unformat_error, input);
999  }
1000 
1001  return 0;
1002 }
1003 
1004 /* tap { host-mtu <size> } configuration. */
1006 
1007 static clib_error_t *
1009 {
1010  tap_main_t *tm = &tap_main;
1011  clib_error_t *error = 0;
1012 
1013  tm->log_default = vlib_log_register_class ("tap", 0);
1014  vlib_log_debug (tm->log_default, "initialized");
1015 
1016  tm->host_mtu_size = 0;
1017 
1018  return error;
1019 }
1020 
1022 
1023 /*
1024  * fd.io coding-style-patch-verification: ON
1025  *
1026  * Local Variables:
1027  * eval: (c-set-style "gnu")
1028  * End:
1029  */
u32 per_interface_next_index
Definition: virtio.h:109
vlib_log_class_t vlib_log_register_class(char *class, char *subclass)
Definition: log.c:209
vlib_node_registration_t virtio_input_node
(constructor) VLIB_REGISTER_NODE (virtio_input_node)
Definition: node.c:490
#define vec_foreach_index(var, v)
Iterate over vector indices.
uword * tap_ids
Definition: tap.h:97
u8 * format_clib_error(u8 *s, va_list *va)
Definition: error.c:191
int host_mtu_size
Definition: tap.h:100
void virtio_set_net_hdr_size(virtio_if_t *vif)
Definition: virtio.c:255
virtio_if_t * interfaces
Definition: virtio.h:192
#define clib_min(x, y)
Definition: clib.h:327
static u32 virtio_eth_flag_change(vnet_main_t *vnm, vnet_hw_interface_t *hi, u32 flags)
Definition: tap.c:67
static void tap_free(vlib_main_t *vm, virtio_if_t *vif)
Definition: tap.c:96
VNET_HW_INTERFACE_CLASS(tun_device_hw_interface_class, static)
vlib_log_class_t log_default
Definition: tap.h:94
ip4_address_t host_ip4_addr
Definition: virtio.h:162
u8 host_if_name[64]
Definition: tap.h:81
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:103
u8 host_namespace[64]
Definition: tap.h:82
ip4_address_t host_ip4_addr
Definition: tap.h:55
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:255
vlib_physmem_main_t physmem_main
Definition: main.h:186
#define VHOST_SET_OWNER
Definition: vhost_std.h:65
int gso_enabled
Definition: virtio.h:114
u32 host_mtu_size
Definition: virtio.h:159
u32 dev_instance
Definition: virtio.h:133
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
int kick_fd
Definition: virtio.h:72
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:60
vnet_device_class_t virtio_device_class
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:630
void virtio_vring_set_numa_node(vlib_main_t *vm, virtio_if_t *vif, u32 idx)
Definition: virtio.c:239
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
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define tap_log_dbg(dev, f,...)
Definition: tap.c:47
int tap_csum_offload_enable_disable(vlib_main_t *vm, u32 sw_if_index, int enable_disable)
Definition: tap.c:810
#define VHOST_SET_MEM_TABLE
Definition: vhost_std.h:67
int call_fd
Definition: virtio.h:73
vhost_vring_addr_t addr
Definition: vhost_user.h:111
int tap_dump_ifs(tap_interface_details_t **out_tapids)
Definition: tap.c:926
u8 host_ip4_gw_set
Definition: tap.h:58
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:200
#define VIRTIO_FEATURE(X)
Definition: virtio_std.h:69
vring_desc_t * desc
Definition: virtio.h:63
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:83
u64 features
Definition: virtio.h:107
u32 hw_if_index
Definition: virtio.h:128
u8 host_ip6_prefix_len
Definition: virtio.h:164
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:513
#define TX_QUEUE_ACCESS(X)
Definition: virtio.h:38
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
u8 * host_bridge
Definition: virtio.h:156
int ifindex
Definition: virtio.h:161
vnet_hw_interface_flags_t flags
Definition: interface.h:537
#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:775
#define clib_error_return(e, args...)
Definition: error.h:99
#define VHOST_SET_VRING_ADDR
Definition: vhost_std.h:71
unsigned int u32
Definition: types.h:88
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:768
#define vlib_log_debug(...)
Definition: log.h:109
#define MIN(x, y)
Definition: node.h:31
u32 id
Definition: virtio.h:158
u16 queue_id
Definition: virtio.h:79
u16 num_txqs
Definition: virtio.h:111
#define TX_QUEUE(X)
Definition: virtio.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
int * vhost_fds
Definition: virtio.h:153
mac_address_t host_mac_addr
Definition: tap.h:80
vring_avail_t * avail
Definition: virtio.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:302
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:182
ip4_address_t host_ip4_gw
Definition: tap.h:57
ip6_address_t host_ip6_addr
Definition: tap.h:59
u8 host_ip4_prefix_len
Definition: tap.h:56
#define virtio_log_debug(vif, f,...)
Definition: virtio.h:244
int packet_coalesce
Definition: virtio.h:132
vring_used_t * used
Definition: virtio.h:64
ip4_address_t host_ip4_addr
Definition: tap.h:84
u16 num_rxqs
Definition: virtio.h:110
virtio_vring_t * rxq_vrings
Definition: virtio.h:112
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
#define TAP_MAX_INSTANCE
Definition: tap.c:93
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
static int open_netns_fd(char *netns)
Definition: tap.c:76
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
u32 host_mtu_size
Definition: tap.h:64
ip6_address_t host_ip6_addr
Definition: virtio.h:152
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:155
#define VHOST_NET_SET_BACKEND
Definition: vhost_std.h:77
u8 mac_addr[6]
Definition: virtio.h:146
u32 flags
Definition: virtio.h:108
#define ARRAY_LEN(x)
Definition: clib.h:67
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:138
u32 tap_flags
Definition: virtio.h:160
#define VHOST_SET_VRING_CALL
Definition: vhost_std.h:75
u8 * host_bridge
Definition: tap.h:54
virtio_if_type_t type
Definition: virtio.h:126
#define VHOST_GET_FEATURES
Definition: vhost_std.h:63
#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:135
ip6_address_t host_ip6_gw
Definition: tap.h:61
clib_error_t * virtio_vring_init(vlib_main_t *vm, virtio_if_t *vif, u16 idx, u16 sz)
Definition: virtio.c:64
u8 * host_if_name
Definition: tap.h:52
u8 host_mac_addr[6]
Definition: virtio.h:157
static void clib_mem_free(void *p)
Definition: mem.h:215
void virtio_set_packet_coalesce(virtio_if_t *vif)
Definition: virtio.c:224
unsigned int if_nametoindex(const char *ifname)
static void * clib_mem_alloc(uword size)
Definition: mem.h:157
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define clib_max(x, y)
Definition: clib.h:320
virtio_main_t virtio_main
Definition: virtio.c:35
vl_api_ip4_address_t hi
Definition: arp.api:37
void vnet_delete_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:984
u8 host_ip6_gw_set
Definition: tap.h:62
void tap_create_if(vlib_main_t *vm, tap_create_if_args_t *args)
Definition: tap.c:131
#define RX_QUEUE_ACCESS(X)
Definition: virtio.h:39
tap_main_t tap_main
Definition: tap.c:43
int csum_offload_enabled
Definition: virtio.h:115
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define tap_log_err(dev, f,...)
Definition: tap.c:45
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:498
Definition: tap.h:91
mac_address_t host_mac_addr
Definition: tap.h:53
int tap_gso_enable_disable(vlib_main_t *vm, u32 sw_if_index, int enable_disable, int is_packet_coalesce)
Definition: tap.c:869
a point 2 point interface
Definition: interface.h:386
mac_address_t mac_addr
Definition: tap.h:46
#define clib_error_free(e)
Definition: error.h:86
clib_error_t * error
Definition: tap.h:68
ip6_address_t host_ip6_addr
Definition: tap.h:86
u8 host_ip4_prefix_len
Definition: virtio.h:163
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:129
virtio_vring_t * cxq_vring
Definition: virtio.h:169
#define VHOST_SET_VRING_NUM
Definition: vhost_std.h:70
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:152
TAP interface details struct.
Definition: tap.h:72
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:507
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
vl_api_dhcp_client_state_t state
Definition: dhcp.api:201
static clib_error_t * tap_mtu_config(vlib_main_t *vm, unformat_input_t *input)
Definition: tap.c:988
vhost_memory_region_t regions[0]
Definition: vhost_std.h:30
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:51
#define VHOST_SET_VRING_KICK
Definition: vhost_std.h:74
#define VHOST_SET_FEATURES
Definition: vhost_std.h:64
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:37
int * tap_fds
Definition: virtio.h:118
static void vnet_hw_interface_set_input_node(vnet_main_t *vnm, u32 hw_if_index, u32 node_index)
Definition: devices.h:79
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
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:113
static clib_error_t * tap_init(vlib_main_t *vm)
Definition: tap.c:1008
u8 * host_if_name
Definition: virtio.h:154