FD.io VPP  v19.08.1-401-g8e4ed521a
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 
60  return 0;
61 }
62 
63 
66 {
67  clib_error_t *err = 0;
68  virtio_vring_t *vring;
69  struct vhost_vring_state state = { 0 };
70  struct vhost_vring_addr addr = { 0 };
71  struct vhost_vring_file file = { 0 };
72  clib_file_t t = { 0 };
73  int i;
74 
75  if (!is_pow2 (sz))
76  return clib_error_return (0, "ring size must be power of 2");
77 
78  if (sz > 32768)
79  return clib_error_return (0, "ring size must be 32768 or lower");
80 
81  if (sz == 0)
82  sz = 256;
83 
84  if (idx % 2)
85  {
89  vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (idx));
90  if (thm->n_vlib_mains > 1)
91  clib_spinlock_init (&vring->lockp);
92  }
93  else
94  {
97  vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (idx));
98  }
99  i = sizeof (struct vring_desc) * sz;
102  clib_memset (vring->desc, 0, i);
103 
104  i = sizeof (struct vring_avail) + sz * sizeof (vring->avail->ring[0]);
107  clib_memset (vring->avail, 0, i);
108  // tell kernel that we don't need interrupt
109  vring->avail->flags = VIRTIO_RING_FLAG_MASK_INT;
110 
111  i = sizeof (struct vring_used) + sz * sizeof (struct vring_used_elem);
114  clib_memset (vring->used, 0, i);
115 
116  vring->queue_id = idx;
117  ASSERT (vring->buffers == 0);
119 
120  if (idx & 1)
121  {
122  clib_memset_u32 (vring->buffers, ~0, sz);
123  }
124 
125  vring->size = sz;
126  vring->call_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
127  vring->kick_fd = eventfd (0, EFD_CLOEXEC);
128 
130  t.file_descriptor = vring->call_fd;
131  t.private_data = vif->dev_instance << 16 | idx;
132  t.description = format (0, "%U vring %u", format_virtio_device_name,
133  vif->dev_instance, idx);
134  vring->call_file_index = clib_file_add (&file_main, &t);
135 
136  state.index = idx;
137  state.num = sz;
138  _IOCTL (vif->fd, VHOST_SET_VRING_NUM, &state);
139 
140  addr.index = idx;
141  addr.flags = 0;
142  addr.desc_user_addr = pointer_to_uword (vring->desc);
143  addr.avail_user_addr = pointer_to_uword (vring->avail);
144  addr.used_user_addr = pointer_to_uword (vring->used);
145  _IOCTL (vif->fd, VHOST_SET_VRING_ADDR, &addr);
146 
147  file.index = idx;
148  file.fd = vring->kick_fd;
149  _IOCTL (vif->fd, VHOST_SET_VRING_KICK, &file);
150  file.fd = vring->call_fd;
151  _IOCTL (vif->fd, VHOST_SET_VRING_CALL, &file);
152  file.fd = vif->tap_fd;
153  _IOCTL (vif->fd, VHOST_NET_SET_BACKEND, &file);
154 
155 error:
156  return err;
157 }
158 
159 inline void
161 {
162  u16 used = vring->desc_in_use;
163  u16 last = vring->last_used_idx;
164  u16 mask = vring->size - 1;
165 
166  while (used)
167  {
168  vlib_buffer_free (vm, &vring->buffers[last & mask], 1);
169  last++;
170  used--;
171  }
172 }
173 
174 clib_error_t *
176 {
177  virtio_vring_t *vring =
179 
181  close (vring->kick_fd);
182  close (vring->call_fd);
183  if (vring->used)
184  {
185  virtio_free_rx_buffers (vm, vring);
186  clib_mem_free (vring->used);
187  }
188  if (vring->desc)
189  clib_mem_free (vring->desc);
190  if (vring->avail)
191  clib_mem_free (vring->avail);
192  vec_free (vring->buffers);
193  return 0;
194 }
195 
196 inline void
198 {
199  u16 used = vring->desc_in_use;
200  u16 sz = vring->size;
201  u16 mask = sz - 1;
202  u16 last = vring->last_used_idx;
203  u16 n_left = vring->used->idx - last;
204 
205  if (n_left == 0)
206  return;
207 
208  while (n_left)
209  {
210  struct vring_used_elem *e = &vring->used->ring[last & mask];
211  u16 slot = e->id;
212 
213  vlib_buffer_free (vm, &vring->buffers[slot], 1);
214  used--;
215  last++;
216  n_left--;
217  }
218  vring->desc_in_use = used;
219  vring->last_used_idx = last;
220 }
221 
222 clib_error_t *
224 {
225  virtio_vring_t *vring =
227 
229  close (vring->kick_fd);
230  close (vring->call_fd);
231  if (vring->used)
232  {
233  virtio_free_used_desc (vm, vring);
234  clib_mem_free (vring->used);
235  }
236  if (vring->desc)
237  clib_mem_free (vring->desc);
238  if (vring->avail)
239  clib_mem_free (vring->avail);
240  vec_free (vring->buffers);
241  clib_spinlock_free (&vring->lockp);
242  return 0;
243 }
244 
245 void
247 {
248  vnet_main_t *vnm = vnet_get_main ();
249  u32 thread_index;
250  virtio_vring_t *vring =
252  thread_index =
254  RX_QUEUE_ACCESS (idx));
255  vring->buffer_pool_index =
257  vlib_mains
258  [thread_index]->numa_node);
259 }
260 
261 inline void
263 {
264  if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF) ||
265  vif->features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1))
266  vif->virtio_net_hdr_sz = sizeof (struct virtio_net_hdr_v1);
267  else
268  vif->virtio_net_hdr_sz = sizeof (struct virtio_net_hdr);
269 }
270 
271 inline void
272 virtio_show (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr, u32 type)
273 {
274  u32 i, j, hw_if_index;
275  virtio_if_t *vif;
276  vnet_main_t *vnm = &vnet_main;
277  virtio_main_t *mm = &virtio_main;
278  virtio_vring_t *vring;
279  struct feat_struct
280  {
281  u8 bit;
282  char *str;
283  };
284  struct feat_struct *feat_entry;
285 
286  static struct feat_struct feat_array[] = {
287 #define _(s,b) { .str = #s, .bit = b, },
289 #undef _
290  {.str = NULL}
291  };
292 
293  struct feat_struct *flag_entry;
294  static struct feat_struct flags_array[] = {
295 #define _(b,e,s) { .bit = b, .str = s, },
297 #undef _
298  {.str = NULL}
299  };
300 
301  if (!hw_if_indices)
302  return;
303 
304  for (hw_if_index = 0; hw_if_index < vec_len (hw_if_indices); hw_if_index++)
305  {
307  vnet_get_hw_interface (vnm, hw_if_indices[hw_if_index]);
308  vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
309  if (vif->type != type)
310  continue;
311  vlib_cli_output (vm, "Interface: %U (ifindex %d)",
313  hw_if_indices[hw_if_index], vif->hw_if_index);
314  if (type == VIRTIO_IF_TYPE_PCI)
315  {
316  vlib_cli_output (vm, " PCI Address: %U", format_vlib_pci_addr,
317  &vif->pci_addr);
318  }
319  if (type == VIRTIO_IF_TYPE_TAP)
320  {
321  if (vif->host_if_name)
322  vlib_cli_output (vm, " name \"%s\"", vif->host_if_name);
323  if (vif->net_ns)
324  vlib_cli_output (vm, " host-ns \"%s\"", vif->net_ns);
325  vlib_cli_output (vm, " host-mac-addr %U", format_ethernet_address,
326  vif->host_mac_addr);
327  if (vif->host_mtu_size)
328  vlib_cli_output (vm, " host-mtu-size \"%d\"",
329  vif->host_mtu_size);
330  vlib_cli_output (vm, " fd %d", vif->fd);
331  vlib_cli_output (vm, " tap-fd %d", vif->tap_fd);
332  }
333  vlib_cli_output (vm, " gso-enabled %d", vif->gso_enabled);
334  vlib_cli_output (vm, " Mac Address: %U", format_ethernet_address,
335  vif->mac_addr);
336  vlib_cli_output (vm, " Device instance: %u", vif->dev_instance);
337  vlib_cli_output (vm, " flags 0x%x", vif->flags);
338  flag_entry = (struct feat_struct *) &flags_array;
339  while (flag_entry->str)
340  {
341  if (vif->flags & (1ULL << flag_entry->bit))
342  vlib_cli_output (vm, " %s (%d)", flag_entry->str,
343  flag_entry->bit);
344  flag_entry++;
345  }
346  if (type == VIRTIO_IF_TYPE_PCI)
347  {
348  device_status (vm, vif);
349  }
350  vlib_cli_output (vm, " features 0x%lx", vif->features);
351  feat_entry = (struct feat_struct *) &feat_array;
352  while (feat_entry->str)
353  {
354  if (vif->features & (1ULL << feat_entry->bit))
355  vlib_cli_output (vm, " %s (%d)", feat_entry->str,
356  feat_entry->bit);
357  feat_entry++;
358  }
359  vlib_cli_output (vm, " remote-features 0x%lx", vif->remote_features);
360  feat_entry = (struct feat_struct *) &feat_array;
361  while (feat_entry->str)
362  {
363  if (vif->remote_features & (1ULL << feat_entry->bit))
364  vlib_cli_output (vm, " %s (%d)", feat_entry->str,
365  feat_entry->bit);
366  feat_entry++;
367  }
368  vlib_cli_output (vm, " Number of RX Virtqueue %u", vif->num_rxqs);
369  vlib_cli_output (vm, " Number of TX Virtqueue %u", vif->num_txqs);
370  if (vif->cxq_vring != NULL
371  && vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
372  vlib_cli_output (vm, " Number of CTRL Virtqueue 1");
373  vec_foreach_index (i, vif->rxq_vrings)
374  {
375  vring = vec_elt_at_index (vif->rxq_vrings, i);
376  vlib_cli_output (vm, " Virtqueue (RX) %d", vring->queue_id);
377  vlib_cli_output (vm,
378  " qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
379  vring->size, vring->last_used_idx, vring->desc_next,
380  vring->desc_in_use);
381  vlib_cli_output (vm,
382  " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
383  vring->avail->flags, vring->avail->idx,
384  vring->used->flags, vring->used->idx);
385  if (type == VIRTIO_IF_TYPE_TAP)
386  {
387  vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd,
388  vring->call_fd);
389  }
390  if (show_descr)
391  {
392  vlib_cli_output (vm, "\n descriptor table:\n");
393  vlib_cli_output (vm,
394  " id addr len flags next user_addr\n");
395  vlib_cli_output (vm,
396  " ===== ================== ===== ====== ===== ==================\n");
397  for (j = 0; j < vring->size; j++)
398  {
399  struct vring_desc *desc = &vring->desc[j];
400  vlib_cli_output (vm,
401  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
402  j, desc->addr,
403  desc->len,
404  desc->flags, desc->next, desc->addr);
405  }
406  }
407  }
408  vec_foreach_index (i, vif->txq_vrings)
409  {
410  vring = vec_elt_at_index (vif->txq_vrings, i);
411  vlib_cli_output (vm, " Virtqueue (TX) %d", vring->queue_id);
412  vlib_cli_output (vm,
413  " qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
414  vring->size, vring->last_used_idx, vring->desc_next,
415  vring->desc_in_use);
416  vlib_cli_output (vm,
417  " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
418  vring->avail->flags, vring->avail->idx,
419  vring->used->flags, vring->used->idx);
420  if (type == VIRTIO_IF_TYPE_TAP)
421  {
422  vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd,
423  vring->call_fd);
424  }
425  if (show_descr)
426  {
427  vlib_cli_output (vm, "\n descriptor table:\n");
428  vlib_cli_output (vm,
429  " id addr len flags next user_addr\n");
430  vlib_cli_output (vm,
431  " ===== ================== ===== ====== ===== ==================\n");
432  for (j = 0; j < vring->size; j++)
433  {
434  struct vring_desc *desc = &vring->desc[j];
435  vlib_cli_output (vm,
436  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
437  j, desc->addr,
438  desc->len,
439  desc->flags, desc->next, desc->addr);
440  }
441  }
442  }
443  if (vif->cxq_vring != NULL
444  && vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
445  {
446  vring = vif->cxq_vring;
447  vlib_cli_output (vm, " Virtqueue (CTRL) %d", vring->queue_id);
448  vlib_cli_output (vm,
449  " qsz %d, last_used_idx %d, desc_next %d, desc_in_use %d",
450  vring->size, vring->last_used_idx,
451  vring->desc_next, vring->desc_in_use);
452  vlib_cli_output (vm,
453  " avail.flags 0x%x avail.idx %d used.flags 0x%x used.idx %d",
454  vring->avail->flags, vring->avail->idx,
455  vring->used->flags, vring->used->idx);
456  if (type == VIRTIO_IF_TYPE_TAP)
457  {
458  vlib_cli_output (vm, " kickfd %d, callfd %d", vring->kick_fd,
459  vring->call_fd);
460  }
461  if (show_descr)
462  {
463  vlib_cli_output (vm, "\n descriptor table:\n");
464  vlib_cli_output (vm,
465  " id addr len flags next user_addr\n");
466  vlib_cli_output (vm,
467  " ===== ================== ===== ====== ===== ==================\n");
468  for (j = 0; j < vring->size; j++)
469  {
470  struct vring_desc *desc = &vring->desc[j];
471  vlib_cli_output (vm,
472  " %-5d 0x%016lx %-5d 0x%04x %-5d 0x%016lx\n",
473  j, desc->addr,
474  desc->len,
475  desc->flags, desc->next, desc->addr);
476  }
477  }
478  }
479 
480  }
481 
482 }
483 
484 /*
485  * fd.io coding-style-patch-verification: ON
486  *
487  * Local Variables:
488  * eval: (c-set-style "gnu")
489  * End:
490  */
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:262
virtio_if_t * interfaces
Definition: virtio.h:193
#define CLIB_UNUSED(x)
Definition: clib.h:82
void virtio_show(vlib_main_t *vm, u32 *hw_if_indices, u8 show_descr, u32 type)
Definition: virtio.c:272
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
#define NULL
Definition: clib.h:58
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:246
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:223
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:160
#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:241
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:197
#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:65
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:235
#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:175
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