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