FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
virtio.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 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <net/if.h>
22 #include <linux/if_tun.h>
23 #include <sys/ioctl.h>
24 #include <linux/virtio_net.h>
25 #include <linux/vhost.h>
26 #include <sys/eventfd.h>
27 
28 #include <vlib/vlib.h>
29 #include <vlib/pci/pci.h>
30 #include <vlib/unix/unix.h>
31 #include <vnet/ethernet/ethernet.h>
32 #include <vnet/ip/ip4_packet.h>
33 #include <vnet/ip/ip6_packet.h>
36 
38 
39 #define _IOCTL(fd,a,...) \
40  if (ioctl (fd, a, __VA_ARGS__) < 0) \
41  { \
42  err = clib_error_return_unix (0, "ioctl(" #a ")"); \
43  goto error; \
44  }
45 
46 static clib_error_t *
48 {
50  vnet_main_t *vnm = vnet_get_main ();
51  u16 qid = uf->private_data & 0xFFFF;
52  virtio_if_t *vif =
53  vec_elt_at_index (nm->interfaces, uf->private_data >> 16);
54  u64 b;
55 
56  CLIB_UNUSED (ssize_t size) = read (uf->file_descriptor, &b, sizeof (b));
57  if ((qid & 1) == 0)
59  RX_QUEUE_ACCESS (qid));
60 
61  return 0;
62 }
63 
64 
67 {
68  clib_error_t *err = 0;
69  virtio_vring_t *vring;
70  struct vhost_vring_state state = { 0 };
71  struct vhost_vring_addr addr = { 0 };
72  struct vhost_vring_file file = { 0 };
73  clib_file_t t = { 0 };
74  int i;
75 
76  if (!is_pow2 (sz))
77  return clib_error_return (0, "ring size must be power of 2");
78 
79  if (sz > 32768)
80  return clib_error_return (0, "ring size must be 32768 or lower");
81 
82  if (sz == 0)
83  sz = 256;
84 
85  if (idx % 2)
86  {
90  vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (idx));
91  if (thm->n_vlib_mains > 1)
92  clib_spinlock_init (&vring->lockp);
93  }
94  else
95  {
98  vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (idx));
99  }
100  i = sizeof (struct vring_desc) * sz;
103  clib_memset (vring->desc, 0, i);
104 
105  i = sizeof (struct vring_avail) + sz * sizeof (vring->avail->ring[0]);
108  clib_memset (vring->avail, 0, i);
109  // tell kernel that we don't need interrupt
110  vring->avail->flags = VIRTIO_RING_FLAG_MASK_INT;
111 
112  i = sizeof (struct vring_used) + sz * sizeof (struct vring_used_elem);
115  clib_memset (vring->used, 0, i);
116 
117  vring->queue_id = idx;
118  ASSERT (vring->buffers == 0);
120 
121  if (idx & 1)
122  {
123  clib_memset_u32 (vring->buffers, ~0, sz);
124  }
125 
126  vring->size = sz;
127  vring->call_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
128  vring->kick_fd = eventfd (0, EFD_CLOEXEC);
129 
131  t.file_descriptor = vring->call_fd;
132  t.private_data = vif->dev_instance << 16 | idx;
133  t.description = format (0, "%U vring %u", format_virtio_device_name,
134  vif->dev_instance, idx);
135  vring->call_file_index = clib_file_add (&file_main, &t);
136 
137  state.index = idx;
138  state.num = sz;
139  _IOCTL (vif->fd, VHOST_SET_VRING_NUM, &state);
140 
141  addr.index = idx;
142  addr.flags = 0;
143  addr.desc_user_addr = pointer_to_uword (vring->desc);
144  addr.avail_user_addr = pointer_to_uword (vring->avail);
145  addr.used_user_addr = pointer_to_uword (vring->used);
146  _IOCTL (vif->fd, VHOST_SET_VRING_ADDR, &addr);
147 
148  file.index = idx;
149  file.fd = vring->kick_fd;
150  _IOCTL (vif->fd, VHOST_SET_VRING_KICK, &file);
151  file.fd = vring->call_fd;
152  _IOCTL (vif->fd, VHOST_SET_VRING_CALL, &file);
153  file.fd = vif->tap_fd;
154  _IOCTL (vif->fd, VHOST_NET_SET_BACKEND, &file);
155 
156 error:
157  return err;
158 }
159 
160 inline void
162 {
163  u16 used = vring->desc_in_use;
164  u16 last = vring->last_used_idx;
165  u16 mask = vring->size - 1;
166 
167  while (used)
168  {
169  vlib_buffer_free (vm, &vring->buffers[last & mask], 1);
170  last++;
171  used--;
172  }
173 }
174 
175 clib_error_t *
177 {
178  virtio_vring_t *vring =
180 
182  close (vring->kick_fd);
183  close (vring->call_fd);
184  if (vring->used)
185  {
186  virtio_free_rx_buffers (vm, vring);
187  clib_mem_free (vring->used);
188  }
189  if (vring->desc)
190  clib_mem_free (vring->desc);
191  if (vring->avail)
192  clib_mem_free (vring->avail);
193  vec_free (vring->buffers);
194  return 0;
195 }
196 
197 inline void
199 {
200  u16 used = vring->desc_in_use;
201  u16 sz = vring->size;
202  u16 mask = sz - 1;
203  u16 last = vring->last_used_idx;
204  u16 n_left = vring->used->idx - last;
205 
206  if (n_left == 0)
207  return;
208 
209  while (n_left)
210  {
211  struct vring_used_elem *e = &vring->used->ring[last & mask];
212  u16 slot = e->id;
213 
214  vlib_buffer_free (vm, &vring->buffers[slot], 1);
215  used--;
216  last++;
217  n_left--;
218  }
219  vring->desc_in_use = used;
220  vring->last_used_idx = last;
221 }
222 
223 clib_error_t *
225 {
226  virtio_vring_t *vring =
228 
230  close (vring->kick_fd);
231  close (vring->call_fd);
232  if (vring->used)
233  {
234  virtio_free_used_desc (vm, vring);
235  clib_mem_free (vring->used);
236  }
237  if (vring->desc)
238  clib_mem_free (vring->desc);
239  if (vring->avail)
240  clib_mem_free (vring->avail);
241  vec_free (vring->buffers);
242  clib_spinlock_free (&vring->lockp);
243  return 0;
244 }
245 
246 void
248 {
249  vnet_main_t *vnm = vnet_get_main ();
250  u32 thread_index;
251  virtio_vring_t *vring =
253  thread_index =
255  RX_QUEUE_ACCESS (idx));
256  vring->buffer_pool_index =
258  vlib_mains
259  [thread_index]->numa_node);
260 }
261 
262 inline void
264 {
265  if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF) ||
266  vif->features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1))
267  vif->virtio_net_hdr_sz = sizeof (struct virtio_net_hdr_v1);
268  else
269  vif->virtio_net_hdr_sz = sizeof (struct virtio_net_hdr);
270 }
271 
272 inline void
273 virtio_show (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr, u32 type)
274 {
275  u32 i, j, hw_if_index;
276  virtio_if_t *vif;
277  vnet_main_t *vnm = &vnet_main;
278  virtio_main_t *mm = &virtio_main;
279  virtio_vring_t *vring;
280  struct feat_struct
281  {
282  u8 bit;
283  char *str;
284  };
285  struct feat_struct *feat_entry;
286 
287  static struct feat_struct feat_array[] = {
288 #define _(s,b) { .str = #s, .bit = b, },
290 #undef _
291  {.str = NULL}
292  };
293 
294  struct feat_struct *flag_entry;
295  static struct feat_struct flags_array[] = {
296 #define _(b,e,s) { .bit = b, .str = s, },
298 #undef _
299  {.str = NULL}
300  };
301 
302  if (!hw_if_indices)
303  return;
304 
305  for (hw_if_index = 0; hw_if_index < vec_len (hw_if_indices); hw_if_index++)
306  {
308  vnet_get_hw_interface (vnm, hw_if_indices[hw_if_index]);
309  vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
310  if (vif->type != type)
311  continue;
312  vlib_cli_output (vm, "Interface: %U (ifindex %d)",
314  hw_if_indices[hw_if_index], vif->hw_if_index);
315  if (type == VIRTIO_IF_TYPE_PCI)
316  {
317  vlib_cli_output (vm, " PCI Address: %U", format_vlib_pci_addr,
318  &vif->pci_addr);
319  }
320  if (type == VIRTIO_IF_TYPE_TAP)
321  {
322  if (vif->host_if_name)
323  vlib_cli_output (vm, " name \"%s\"", vif->host_if_name);
324  if (vif->net_ns)
325  vlib_cli_output (vm, " host-ns \"%s\"", vif->net_ns);
326  vlib_cli_output (vm, " host-mac-addr %U", format_ethernet_address,
327  vif->host_mac_addr);
328  if (vif->host_mtu_size)
329  vlib_cli_output (vm, " host-mtu-size \"%d\"",
330  vif->host_mtu_size);
331  vlib_cli_output (vm, " fd %d", vif->fd);
332  vlib_cli_output (vm, " tap-fd %d", vif->tap_fd);
333  }
334  vlib_cli_output (vm, " gso-enabled %d", vif->gso_enabled);
335  vlib_cli_output (vm, " Mac Address: %U", format_ethernet_address,
336  vif->mac_addr);
337  vlib_cli_output (vm, " Device instance: %u", vif->dev_instance);
338  vlib_cli_output (vm, " flags 0x%x", vif->flags);
339  flag_entry = (struct feat_struct *) &flags_array;
340  while (flag_entry->str)
341  {
342  if (vif->flags & (1ULL << flag_entry->bit))
343  vlib_cli_output (vm, " %s (%d)", flag_entry->str,
344  flag_entry->bit);
345  flag_entry++;
346  }
347  if (type == VIRTIO_IF_TYPE_PCI)
348  {
349  device_status (vm, vif);
350  }
351  vlib_cli_output (vm, " features 0x%lx", vif->features);
352  feat_entry = (struct feat_struct *) &feat_array;
353  while (feat_entry->str)
354  {
355  if (vif->features & (1ULL << feat_entry->bit))
356  vlib_cli_output (vm, " %s (%d)", feat_entry->str,
357  feat_entry->bit);
358  feat_entry++;
359  }
360  vlib_cli_output (vm, " remote-features 0x%lx", vif->remote_features);
361  feat_entry = (struct feat_struct *) &feat_array;
362  while (feat_entry->str)
363  {
364  if (vif->remote_features & (1ULL << feat_entry->bit))
365  vlib_cli_output (vm, " %s (%d)", feat_entry->str,
366  feat_entry->bit);
367  feat_entry++;
368  }
369  vlib_cli_output (vm, " Number of RX Virtqueue %u", vif->num_rxqs);
370  vlib_cli_output (vm, " Number of TX Virtqueue %u", vif->num_txqs);
371  if (vif->cxq_vring != NULL
372  && vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
373  vlib_cli_output (vm, " Number of CTRL Virtqueue 1");
374  vec_foreach_index (i, vif->rxq_vrings)
375  {
376  vring = vec_elt_at_index (vif->rxq_vrings, i);
377  vlib_cli_output (vm, " Virtqueue (RX) %d", vring->queue_id);
378  vlib_cli_output (vm,
379  " qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
380  vring->size, vring->last_used_idx, vring->desc_next,
381  vring->desc_in_use);
382  vlib_cli_output (vm,
383  " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
384  vring->avail->flags, vring->avail->idx,
385  vring->used->flags, vring->used->idx);
386  if (type == VIRTIO_IF_TYPE_TAP)
387  {
388  vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd,
389  vring->call_fd);
390  }
391  if (show_descr)
392  {
393  vlib_cli_output (vm, "\n descriptor table:\n");
394  vlib_cli_output (vm,
395  " id addr len flags next user_addr\n");
396  vlib_cli_output (vm,
397  " ===== ================== ===== ====== ===== ==================\n");
398  for (j = 0; j < vring->size; j++)
399  {
400  struct vring_desc *desc = &vring->desc[j];
401  vlib_cli_output (vm,
402  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
403  j, desc->addr,
404  desc->len,
405  desc->flags, desc->next, desc->addr);
406  }
407  }
408  }
409  vec_foreach_index (i, vif->txq_vrings)
410  {
411  vring = vec_elt_at_index (vif->txq_vrings, i);
412  vlib_cli_output (vm, " Virtqueue (TX) %d", vring->queue_id);
413  vlib_cli_output (vm,
414  " qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
415  vring->size, vring->last_used_idx, vring->desc_next,
416  vring->desc_in_use);
417  vlib_cli_output (vm,
418  " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
419  vring->avail->flags, vring->avail->idx,
420  vring->used->flags, vring->used->idx);
421  if (type == VIRTIO_IF_TYPE_TAP)
422  {
423  vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd,
424  vring->call_fd);
425  }
426  if (show_descr)
427  {
428  vlib_cli_output (vm, "\n descriptor table:\n");
429  vlib_cli_output (vm,
430  " id addr len flags next user_addr\n");
431  vlib_cli_output (vm,
432  " ===== ================== ===== ====== ===== ==================\n");
433  for (j = 0; j < vring->size; j++)
434  {
435  struct vring_desc *desc = &vring->desc[j];
436  vlib_cli_output (vm,
437  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
438  j, desc->addr,
439  desc->len,
440  desc->flags, desc->next, desc->addr);
441  }
442  }
443  }
444  if (vif->cxq_vring != NULL
445  && vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
446  {
447  vring = vif->cxq_vring;
448  vlib_cli_output (vm, " Virtqueue (CTRL) %d", vring->queue_id);
449  vlib_cli_output (vm,
450  " qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
451  vring->size, vring->last_used_idx,
452  vring->desc_next, vring->desc_in_use);
453  vlib_cli_output (vm,
454  " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
455  vring->avail->flags, vring->avail->idx,
456  vring->used->flags, vring->used->idx);
457  if (type == VIRTIO_IF_TYPE_TAP)
458  {
459  vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd,
460  vring->call_fd);
461  }
462  if (show_descr)
463  {
464  vlib_cli_output (vm, "\n descriptor table:\n");
465  vlib_cli_output (vm,
466  " id addr len flags next user_addr\n");
467  vlib_cli_output (vm,
468  " ===== ================== ===== ====== ===== ==================\n");
469  for (j = 0; j < vring->size; j++)
470  {
471  struct vring_desc *desc = &vring->desc[j];
472  vlib_cli_output (vm,
473  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
474  j, desc->addr,
475  desc->len,
476  desc->flags, desc->next, desc->addr);
477  }
478  }
479  }
480 
481  }
482 
483 }
484 
485 /*
486  * fd.io coding-style-patch-verification: ON
487  *
488  * Local Variables:
489  * eval: (c-set-style "gnu")
490  * End:
491  */
struct vring_used * used
Definition: virtio.h:105
vmrglw vmrglh hi
#define vec_foreach_index(var, v)
Iterate over vector indices.
format_function_t format_vnet_hw_if_index_name
void virtio_set_net_hdr_size(virtio_if_t *vif)
Definition: virtio.c:263
virtio_if_t * interfaces
Definition: virtio.h:193
#define CLIB_UNUSED(x)
Definition: clib.h:83
void virtio_show(vlib_main_t *vm, u32 *hw_if_indices, u8 show_descr, u32 type)
Definition: virtio.c:273
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:865
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
unsigned long u64
Definition: types.h:89
int gso_enabled
Definition: virtio.h:183
u32 host_mtu_size
Definition: virtio.h:182
u32 dev_instance
Definition: virtio.h:140
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
#define foreach_virtio_net_features
Definition: virtio.h:26
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u32 file_descriptor
Definition: file.h:54
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
int i
void virtio_vring_set_numa_node(vlib_main_t *vm, virtio_if_t *vif, u32 idx)
Definition: virtio.c:247
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:450
vlib_main_t ** vlib_mains
Definition: buffer.c:332
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:224
clib_file_function_t * read_function
Definition: file.h:67
static void clib_spinlock_free(clib_spinlock_t *p)
Definition: lock.h:70
struct vring_avail * avail
Definition: virtio.h:106
u64 features
Definition: virtio.h:164
u32 hw_if_index
Definition: virtio.h:141
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define TX_QUEUE_ACCESS(X)
Definition: virtio.h:80
void device_status(vlib_main_t *vm, virtio_if_t *vif)
Definition: pci.c:362
static_always_inline void vnet_device_input_set_interrupt_pending(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.h:136
void virtio_free_rx_buffers(vlib_main_t *vm, virtio_vring_t *vring)
Definition: virtio.c:161
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
clib_spinlock_t lockp
Definition: virtio.h:107
#define clib_error_return(e, args...)
Definition: error.h:99
clib_file_main_t file_main
Definition: main.c:63
unsigned int u32
Definition: types.h:88
u16 queue_id
Definition: virtio.h:114
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:63
u16 num_txqs
Definition: virtio.h:171
vl_api_fib_path_type_t type
Definition: fib_types.api:123
u8 * description
Definition: file.h:70
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
uword size
static_always_inline uword vnet_get_device_input_thread_index(vnet_main_t *vnm, u32 hw_if_index, u16 queue_id)
Definition: devices.h:127
int tap_fd
Definition: virtio.h:159
unsigned short u16
Definition: types.h:57
pci_addr_t pci_addr
Definition: virtio.h:149
vnet_main_t vnet_main
Definition: misc.c:43
u8 buffer_pool_index
Definition: virtio.h:112
u16 desc_next
Definition: virtio.h:109
u16 virtio_net_hdr_sz
Definition: virtio.h:144
u16 num_rxqs
Definition: virtio.h:170
virtio_vring_t * rxq_vrings
Definition: virtio.h:162
format_function_t format_virtio_device_name
Definition: virtio.h:215
u16 last_used_idx
Definition: virtio.h:119
vlib_main_t * vm
Definition: buffer.c:323
#define VIRTIO_RING_FLAG_MASK_INT
Definition: virtio.h:99
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
u32 call_file_index
Definition: virtio.h:117
u8 * net_ns
Definition: virtio.h:175
u8 mac_addr[6]
Definition: virtio.h:173
u32 flags
Definition: virtio.h:138
static uword round_pow2(uword x, uword pow2)
Definition: clib.h:248
virtio_if_type_t type
Definition: virtio.h:145
void virtio_free_used_desc(vlib_main_t *vm, virtio_vring_t *vring)
Definition: virtio.c:198
#define ASSERT(truth)
u64 remote_features
Definition: virtio.h:164
static uword clib_file_add(clib_file_main_t *um, clib_file_t *template)
Definition: file.h:96
static void clib_file_del_by_index(clib_file_main_t *um, uword index)
Definition: file.h:119
#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:66
u8 host_mac_addr[6]
Definition: virtio.h:177
static void clib_mem_free(void *p)
Definition: mem.h:226
static uword pointer_to_uword(const void *p)
Definition: types.h:131
virtio_main_t virtio_main
Definition: virtio.c:37
static uword is_pow2(uword x)
Definition: clib.h:236
#define RX_QUEUE_ACCESS(X)
Definition: virtio.h:81
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
int fd
Definition: virtio.h:154
u32 * buffers
Definition: virtio.h:118
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:161
virtio_vring_t * cxq_vring
Definition: virtio.h:185
clib_error_t * virtio_vring_free_rx(vlib_main_t *vm, virtio_if_t *vif, u32 idx)
Definition: virtio.c:176
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
uword private_data
Definition: file.h:64
struct vring_desc * desc
Definition: virtio.h:104
Definition: file.h:51
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
static u8 vlib_buffer_pool_get_default_for_numa(vlib_main_t *vm, u32 numa_node)
Definition: buffer_funcs.h:163
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:772
format_function_t format_vlib_pci_addr
Definition: pci.h:324
u16 desc_in_use
Definition: virtio.h:108
virtio_vring_t * txq_vrings
Definition: virtio.h:163
static clib_error_t * call_read_ready(clib_file_t *uf)
Definition: virtio.c:47
u8 * host_if_name
Definition: virtio.h:174
static_always_inline void clib_memset_u32(void *p, u32 val, uword count)
Definition: string.h:332