FD.io VPP  v19.04-6-g6f05f72
Vector Packet Processing
device.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2016 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 
22 #include <vlib/vlib.h>
23 #include <vlib/unix/unix.h>
24 #include <vnet/ethernet/ethernet.h>
25 #include <vnet/ip/ip4_packet.h>
26 #include <vnet/ip/ip6_packet.h>
28 
29 #define foreach_virtio_tx_func_error \
30 _(NO_FREE_SLOTS, "no free tx slots") \
31 _(TRUNC_PACKET, "packet > buffer size -- truncated in tx ring") \
32 _(PENDING_MSGS, "pending msgs in tx ring") \
33 _(NO_TX_QUEUES, "no tx queues")
34 
35 typedef enum
36 {
37 #define _(f,s) VIRTIO_TX_ERROR_##f,
39 #undef _
42 
43 static char *virtio_tx_func_error_strings[] = {
44 #define _(n,s) s,
46 #undef _
47 };
48 
49 #ifndef CLIB_MARCH_VARIANT
50 u8 *
51 format_virtio_device_name (u8 * s, va_list * args)
52 {
53  u32 dev_instance = va_arg (*args, u32);
55  virtio_if_t *vif = pool_elt_at_index (mm->interfaces, dev_instance);
56 
57  if (vif->type == VIRTIO_IF_TYPE_TAP)
58  s = format (s, "tap%u", vif->id);
59  else if (vif->type == VIRTIO_IF_TYPE_PCI)
60  s = format (s, "virtio-%x/%x/%x/%x", vif->pci_addr.domain,
61  vif->pci_addr.bus, vif->pci_addr.slot,
62  vif->pci_addr.function);
63  else
64  s = format (s, "virtio-%lu", vif->dev_instance);
65 
66  return s;
67 }
68 #endif /* CLIB_MARCH_VARIANT */
69 
70 static u8 *
71 format_virtio_device (u8 * s, va_list * args)
72 {
73  u32 dev_instance = va_arg (*args, u32);
74  int verbose = va_arg (*args, int);
75  u32 indent = format_get_indent (s);
76 
77  s = format (s, "VIRTIO interface");
78  if (verbose)
79  {
80  s = format (s, "\n%U instance %u", format_white_space, indent + 2,
81  dev_instance);
82  }
83  return s;
84 }
85 
86 static u8 *
87 format_virtio_tx_trace (u8 * s, va_list * args)
88 {
89  s = format (s, "Unimplemented...");
90  return s;
91 }
92 
93 #ifndef CLIB_MARCH_VARIANT
94 inline void
96 {
97  u16 used = vring->desc_in_use;
98  u16 sz = vring->size;
99  u16 mask = sz - 1;
100  u16 last = vring->last_used_idx;
101  u16 n_left = vring->used->idx - last;
102 
103  if (n_left == 0)
104  return;
105 
106  while (n_left)
107  {
108  struct vring_used_elem *e = &vring->used->ring[last & mask];
109  u16 slot = e->id;
110 
111  vlib_buffer_free (vm, &vring->buffers[slot], 1);
112  used--;
113  last++;
114  n_left--;
115  }
116  vring->desc_in_use = used;
117  vring->last_used_idx = last;
118 }
119 #endif /* CLIB_MARCH_VARIANT */
120 
123  virtio_vring_t * vring, u32 bi, u16 avail, u16 next,
124  u16 mask, int do_gso)
125 {
126  u16 n_added = 0;
127  int hdr_sz = vif->virtio_net_hdr_sz;
128  struct vring_desc *d;
129  d = &vring->desc[next];
130  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
131  struct virtio_net_hdr_v1 *hdr = vlib_buffer_get_current (b) - hdr_sz;
132 
133  clib_memset (hdr, 0, hdr_sz);
134  if (do_gso && (b->flags & VNET_BUFFER_F_GSO))
135  {
136  if (b->flags & VNET_BUFFER_F_IS_IP4)
137  {
138  hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
139  hdr->gso_size = vnet_buffer2 (b)->gso_size;
140  hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
141  hdr->csum_start = vnet_buffer (b)->l4_hdr_offset; // 0x22;
142  hdr->csum_offset = 0x10;
143  }
144  else
145  {
146  hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
147  hdr->gso_size = vnet_buffer2 (b)->gso_size;
148  hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
149  hdr->csum_start = vnet_buffer (b)->l4_hdr_offset; // 0x36;
150  hdr->csum_offset = 0x10;
151  }
152  }
153 
154  if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
155  {
156  d->addr =
158  b) :
160  d->len = b->current_length + hdr_sz;
161  d->flags = 0;
162  }
163  else
164  {
165  /*
166  * We are using single vlib_buffer_t for indirect descriptor(s)
167  * chain. Single descriptor is 16 bytes and vlib_buffer_t
168  * has 2048 bytes space. So maximum long chain can have 128
169  * (=2048/16) indirect descriptors.
170  * It can easily support 65535 bytes of Jumbo frames with
171  * each data buffer size of 512 bytes minimum.
172  */
173  vlib_buffer_t *indirect_desc =
174  vlib_get_buffer (vm, vring->indirect_buffers[next]);
175  indirect_desc->current_data = 0;
176 
177  struct vring_desc *id =
178  (struct vring_desc *) vlib_buffer_get_current (indirect_desc);
179  u32 count = 1;
180  if (vif->type == VIRTIO_IF_TYPE_PCI)
181  {
182  d->addr = vlib_physmem_get_pa (vm, id);
183  id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
184 
185  /*
186  * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
187  * should be presented in separate descriptor and data will start
188  * from next descriptor.
189  */
190  if (PREDICT_TRUE
191  (vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)))
192  id->len = b->current_length + hdr_sz;
193  else
194  {
195  id->len = hdr_sz;
196  id->flags = VRING_DESC_F_NEXT;
197  id->next = count;
198  count++;
199  id++;
200  id->addr = vlib_buffer_get_current_pa (vm, b);
201  id->len = b->current_length;
202  }
203  while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
204  {
205  id->flags = VRING_DESC_F_NEXT;
206  id->next = count;
207  count++;
208  id++;
209  b = vlib_get_buffer (vm, b->next_buffer);
210  id->addr = vlib_buffer_get_current_pa (vm, b);
211  id->len = b->current_length;
212  }
213  }
214  else /* VIRTIO_IF_TYPE_TAP */
215  {
216  d->addr = pointer_to_uword (id);
217  /* first buffer in chain */
218  id->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
219  id->len = b->current_length + hdr_sz;
220 
221  while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
222  {
223  id->flags = VRING_DESC_F_NEXT;
224  id->next = count;
225  count++;
226  id++;
227  b = vlib_get_buffer (vm, b->next_buffer);
228  id->addr = pointer_to_uword (vlib_buffer_get_current (b));
229  id->len = b->current_length;
230  }
231  }
232  id->flags = 0;
233  id->next = 0;
234  d->len = count * sizeof (struct vring_desc);
235  d->flags = VRING_DESC_F_INDIRECT;
236  }
237  vring->buffers[next] = bi;
238  vring->avail->ring[avail & mask] = next;
239  n_added++;
240  return n_added;
241 }
242 
245  vlib_frame_t * frame, virtio_if_t * vif,
246  int do_gso)
247 {
248  u16 n_left = frame->n_vectors;
249  virtio_vring_t *vring;
250  u16 qid = vm->thread_index % vif->num_txqs;
251  vring = vec_elt_at_index (vif->txq_vrings, qid);
252  u16 used, next, avail;
253  u16 sz = vring->size;
254  u16 mask = sz - 1;
255  u32 *buffers = vlib_frame_vector_args (frame);
256 
258 
259  if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0 &&
260  (vring->last_kick_avail_idx != vring->avail->idx))
261  virtio_kick (vm, vring, vif);
262 
263  /* free consumed buffers */
264  virtio_free_used_desc (vm, vring);
265 
266  used = vring->desc_in_use;
267  next = vring->desc_next;
268  avail = vring->avail->idx;
269 
270  while (n_left && used < sz)
271  {
272  u16 n_added = 0;
273  n_added =
274  add_buffer_to_slot (vm, vif, vring, buffers[0], avail, next, mask,
275  do_gso);
276  if (!n_added)
277  break;
278  avail += n_added;
279  next = (next + n_added) & mask;
280  used += n_added;
281  buffers++;
282  n_left--;
283  }
284 
285  if (n_left != frame->n_vectors)
286  {
288  vring->avail->idx = avail;
289  vring->desc_next = next;
290  vring->desc_in_use = used;
291  if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0)
292  virtio_kick (vm, vring, vif);
293  }
294 
295  if (n_left)
296  {
297  vlib_error_count (vm, node->node_index, VIRTIO_TX_ERROR_NO_FREE_SLOTS,
298  n_left);
299  vlib_buffer_free (vm, buffers, n_left);
300  }
301 
303 
304  return frame->n_vectors - n_left;
305 }
306 
308  vlib_node_runtime_t * node,
309  vlib_frame_t * frame)
310 {
311  virtio_main_t *nm = &virtio_main;
312  vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
314  vnet_main_t *vnm = vnet_get_main ();
315 
316  if (vnm->interface_main.gso_interface_count > 0)
317  return virtio_interface_tx_inline (vm, node, frame, vif, 1 /* do_gso */ );
318  else
319  return virtio_interface_tx_inline (vm, node, frame, vif,
320  0 /* no do_gso */ );
321 }
322 
323 static void
325  u32 node_index)
326 {
327  virtio_main_t *apm = &virtio_main;
328  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
330 
331  /* Shut off redirection */
332  if (node_index == ~0)
333  {
334  vif->per_interface_next_index = node_index;
335  return;
336  }
337 
340  node_index);
341 }
342 
343 static void
345 {
346  /* Nothing for now */
347 }
348 
349 static clib_error_t *
352 {
353  virtio_main_t *mm = &virtio_main;
354  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
356  virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid);
357 
358  if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode))
359  {
360  vring->avail->flags |= VIRTIO_RING_FLAG_MASK_INT;
361  return clib_error_return (0, "interrupt mode is not supported");
362  }
363 
365  vring->avail->flags |= VIRTIO_RING_FLAG_MASK_INT;
366  else
367  vring->avail->flags &= ~VIRTIO_RING_FLAG_MASK_INT;
368 
369  return 0;
370 }
371 
372 static clib_error_t *
374 {
375  virtio_main_t *mm = &virtio_main;
376  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
378 
380  vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
381  else
382  vif->flags &= ~VIRTIO_IF_FLAG_ADMIN_UP;
383 
384  return 0;
385 }
386 
387 static clib_error_t *
389  u32 hw_if_index,
390  struct vnet_sw_interface_t *st, int is_add)
391 {
392  /* Nothing for now */
393  return 0;
394 }
395 
396 /* *INDENT-OFF* */
398  .name = "virtio",
399  .format_device_name = format_virtio_device_name,
400  .format_device = format_virtio_device,
401  .format_tx_trace = format_virtio_tx_trace,
402  .tx_function_n_errors = VIRTIO_TX_N_ERROR,
403  .tx_function_error_strings = virtio_tx_func_error_strings,
404  .rx_redirect_to_node = virtio_set_interface_next_node,
405  .clear_counters = virtio_clear_hw_interface_counters,
406  .admin_up_down_function = virtio_interface_admin_up_down,
407  .subif_add_del_function = virtio_subif_add_del_function,
408  .rx_mode_change_function = virtio_interface_rx_mode_change,
409 };
410 /* *INDENT-ON* */
411 
412 /*
413  * fd.io coding-style-patch-verification: ON
414  *
415  * Local Variables:
416  * eval: (c-set-style "gnu")
417  * End:
418  */
u32 per_interface_next_index
Definition: virtio.h:152
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
struct vring_used * used
Definition: virtio.h:105
static uword vlib_buffer_get_current_pa(vlib_main_t *vm, vlib_buffer_t *b)
Definition: buffer_funcs.h:427
vlib_node_registration_t virtio_input_node
(constructor) VLIB_REGISTER_NODE (virtio_input_node)
Definition: node.c:384
virtio_if_t * interfaces
Definition: virtio.h:193
u32 flags
Definition: vhost_user.h:115
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
#define foreach_virtio_tx_func_error
Definition: device.c:29
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
#define vnet_buffer2(b)
Definition: buffer.h:428
vnet_interface_main_t interface_main
Definition: vnet.h:56
#define PREDICT_TRUE(x)
Definition: clib.h:112
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:110
#define CLIB_MEMORY_STORE_BARRIER()
Definition: clib.h:118
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
u32 dev_instance
Definition: virtio.h:141
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:98
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u32 thread_index
Definition: main.h:197
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
static u32 format_get_indent(u8 *s)
Definition: format.h:72
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u16 domain
Definition: virtio.h:127
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1122
unsigned char u8
Definition: types.h:56
static char * virtio_tx_func_error_strings[]
Definition: device.c:43
virtio_tx_func_error_t
Definition: device.c:35
vnet_hw_interface_rx_mode
Definition: interface.h:52
struct vring_avail * avail
Definition: virtio.h:106
u64 features
Definition: virtio.h:165
#define static_always_inline
Definition: clib.h:99
static_always_inline uword virtio_interface_tx_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, virtio_if_t *vif, int do_gso)
Definition: device.c:244
VNET_DEVICE_CLASS_TX_FN() virtio_device_class(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: device.c:307
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:113
u8 bus
Definition: virtio.h:128
u8 support_int_mode
Definition: virtio.h:169
#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
static void virtio_clear_hw_interface_counters(u32 instance)
Definition: device.c:344
#define clib_error_return(e, args...)
Definition: error.h:99
#define VNET_DEVICE_CLASS_TX_FN(devclass)
Definition: interface.h:287
unsigned int u32
Definition: types.h:88
u32 id
Definition: virtio.h:149
static clib_error_t * virtio_interface_rx_mode_change(vnet_main_t *vnm, u32 hw_if_index, u32 qid, vnet_hw_interface_rx_mode mode)
Definition: device.c:350
u16 num_txqs
Definition: virtio.h:172
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
pci_addr_t pci_addr
Definition: virtio.h:150
u32 node_index
Node index.
Definition: node.h:495
static u8 * format_virtio_device(u8 *s, va_list *args)
Definition: device.c:71
u16 desc_next
Definition: virtio.h:109
u16 virtio_net_hdr_sz
Definition: virtio.h:145
static void virtio_set_interface_next_node(vnet_main_t *vnm, u32 hw_if_index, u32 node_index)
Definition: device.c:324
u32 * indirect_buffers
Definition: virtio.h:118
virtio_vring_t * rxq_vrings
Definition: virtio.h:163
u16 last_used_idx
Definition: virtio.h:119
u16 n_vectors
Definition: node.h:395
static u8 * format_virtio_tx_trace(u8 *s, va_list *args)
Definition: device.c:87
vlib_main_t * vm
Definition: buffer.c:312
#define VIRTIO_RING_FLAG_MASK_INT
Definition: virtio.h:99
static clib_error_t * virtio_subif_add_del_function(vnet_main_t *vnm, u32 hw_if_index, struct vnet_sw_interface_t *st, int is_add)
Definition: device.c:388
static clib_error_t * virtio_interface_admin_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: device.c:373
u32 flags
Definition: virtio.h:138
u16 last_kick_avail_idx
Definition: virtio.h:120
vl_api_vxlan_gbp_api_tunnel_mode_t mode
Definition: vxlan_gbp.api:44
virtio_if_type_t type
Definition: virtio.h:146
void virtio_free_used_desc(vlib_main_t *vm, virtio_vring_t *vring)
Definition: device.c:95
u8 is_add
Definition: ipsec_gre.api:36
#define VIRTIO_FEATURE(X)
Definition: virtio.h:76
VNET_DEVICE_CLASS(bond_dev_class)
size_t count
Definition: vapi.c:47
u8 function
Definition: virtio.h:130
static uword pointer_to_uword(const void *p)
Definition: types.h:131
virtio_main_t virtio_main
Definition: virtio.c:37
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static_always_inline u16 add_buffer_to_slot(vlib_main_t *vm, virtio_if_t *vif, virtio_vring_t *vring, u32 bi, u16 avail, u16 next, u16 mask, int do_gso)
Definition: device.c:122
static u64 vlib_physmem_get_pa(vlib_main_t *vm, void *mem)
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:140
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
u32 * buffers
Definition: virtio.h:117
#define vnet_buffer(b)
Definition: buffer.h:369
struct vring_desc * desc
Definition: virtio.h:104
u8 * format_virtio_device_name(u8 *s, va_list *args)
Definition: device.c:51
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:82
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
u16 desc_in_use
Definition: virtio.h:108
virtio_vring_t * txq_vrings
Definition: virtio.h:164
static_always_inline void virtio_kick(vlib_main_t *vm, virtio_vring_t *vring, virtio_if_t *vif)
Definition: virtio.h:218
u8 slot
Definition: virtio.h:129