blob: aa816e2e17d53ceb590e2ac306f0b4444f41592f [file] [log] [blame]
Damjan Marion8389fb92017-10-13 18:29:53 +02001/*
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>
Damjan Marion8389fb92017-10-13 18:29:53 +020021
22#include <vlib/vlib.h>
23#include <vlib/unix/unix.h>
Mohsin Kazmi206acf82020-04-06 14:19:54 +020024#include <vnet/vnet.h>
Damjan Marion8389fb92017-10-13 18:29:53 +020025#include <vnet/ethernet/ethernet.h>
Mohsin Kazmi9e2a7852020-08-13 18:57:26 +020026#include <vnet/gso/gro_func.h>
Mohsin Kazmi0b042092020-04-17 16:50:56 +000027#include <vnet/gso/hdr_offset_parser.h>
Milan Lenco73e7f422017-12-14 10:04:25 +010028#include <vnet/ip/ip4_packet.h>
29#include <vnet/ip/ip6_packet.h>
Mohsin Kazmi6d4af892020-01-03 15:11:53 +000030#include <vnet/tcp/tcp_packet.h>
31#include <vnet/udp/udp_packet.h>
Damjan Marion8389fb92017-10-13 18:29:53 +020032#include <vnet/devices/virtio/virtio.h>
33
Mohsin Kazmi637c97c2021-05-12 14:51:29 +020034#define VIRTIO_TX_MAX_CHAIN_LEN 127
35
Damjan Marion8389fb92017-10-13 18:29:53 +020036#define foreach_virtio_tx_func_error \
37_(NO_FREE_SLOTS, "no free tx slots") \
38_(TRUNC_PACKET, "packet > buffer size -- truncated in tx ring") \
39_(PENDING_MSGS, "pending msgs in tx ring") \
Mohsin Kazmif50ef402020-04-09 22:11:29 +020040_(INDIRECT_DESC_ALLOC_FAILED, "indirect descriptor allocation failed - packet drop") \
41_(OUT_OF_ORDER, "out-of-order buffers in used ring") \
42_(GSO_PACKET_DROP, "gso disabled on itf -- gso packet drop") \
43_(CSUM_OFFLOAD_PACKET_DROP, "checksum offload disabled on itf -- csum offload packet drop")
Damjan Marion8389fb92017-10-13 18:29:53 +020044
45typedef enum
46{
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020047#define _(f,s) VIRTIO_TX_ERROR_##f,
Damjan Marion8389fb92017-10-13 18:29:53 +020048 foreach_virtio_tx_func_error
49#undef _
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020050 VIRTIO_TX_N_ERROR,
Damjan Marion8389fb92017-10-13 18:29:53 +020051} virtio_tx_func_error_t;
52
53static char *virtio_tx_func_error_strings[] = {
54#define _(n,s) s,
55 foreach_virtio_tx_func_error
56#undef _
57};
58
Damjan Marion8389fb92017-10-13 18:29:53 +020059static u8 *
60format_virtio_device (u8 * s, va_list * args)
61{
62 u32 dev_instance = va_arg (*args, u32);
63 int verbose = va_arg (*args, int);
64 u32 indent = format_get_indent (s);
65
66 s = format (s, "VIRTIO interface");
67 if (verbose)
68 {
69 s = format (s, "\n%U instance %u", format_white_space, indent + 2,
70 dev_instance);
71 }
72 return s;
73}
74
Mohsin Kazmib5ca5592020-06-26 13:48:26 +000075typedef struct
Damjan Marion8389fb92017-10-13 18:29:53 +020076{
Mohsin Kazmib5ca5592020-06-26 13:48:26 +000077 u32 buffer_index;
78 u32 sw_if_index;
Mohsin Kazmib5ca5592020-06-26 13:48:26 +000079 generic_header_offset_t gho;
Damjan Marion8c698872020-10-10 19:17:58 +020080 vlib_buffer_t buffer;
Mohsin Kazmib5ca5592020-06-26 13:48:26 +000081} virtio_tx_trace_t;
82
83static u8 *
84format_virtio_tx_trace (u8 * s, va_list * va)
85{
86 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
87 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
88 virtio_tx_trace_t *t = va_arg (*va, virtio_tx_trace_t *);
89 u32 indent = format_get_indent (s);
90
Mohsin Kazmib3a8f4e2020-09-15 16:41:44 +000091 s = format (s, "%Ubuffer 0x%x: %U\n",
Mohsin Kazmib5ca5592020-06-26 13:48:26 +000092 format_white_space, indent,
93 t->buffer_index, format_vnet_buffer, &t->buffer);
Mohsin Kazmib3a8f4e2020-09-15 16:41:44 +000094 s =
95 format (s, "%U%U\n", format_white_space, indent,
96 format_generic_header_offset, &t->gho);
97 s =
98 format (s, "%U%U", format_white_space, indent,
99 format_ethernet_header_with_length, t->buffer.pre_data,
100 sizeof (t->buffer.pre_data));
Damjan Marion8389fb92017-10-13 18:29:53 +0200101 return s;
102}
103
Damjan Marion809d5c92021-03-24 12:24:58 +0100104static void
105virtio_tx_trace (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b0,
106 u32 bi, int is_tun)
Mohsin Kazmi03b26952020-09-16 16:53:16 +0000107{
108 virtio_tx_trace_t *t;
109 t = vlib_add_trace (vm, node, b0, sizeof (t[0]));
110 t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
111 t->buffer_index = bi;
Damjan Mariond4a54712020-10-31 23:40:51 +0100112 if (is_tun)
Mohsin Kazmi03b26952020-09-16 16:53:16 +0000113 {
114 int is_ip4 = 0, is_ip6 = 0;
115
116 switch (((u8 *) vlib_buffer_get_current (b0))[0] & 0xf0)
117 {
118 case 0x40:
119 is_ip4 = 1;
120 break;
121 case 0x60:
122 is_ip6 = 1;
123 break;
124 default:
125 break;
126 }
127 vnet_generic_header_offset_parser (b0, &t->gho, 0, is_ip4, is_ip6);
128 }
129 else
130 vnet_generic_header_offset_parser (b0, &t->gho, 1,
131 b0->flags &
132 VNET_BUFFER_F_IS_IP4,
133 b0->flags & VNET_BUFFER_F_IS_IP6);
134
135 clib_memcpy_fast (&t->buffer, b0, sizeof (*b0) - sizeof (b0->pre_data));
136 clib_memcpy_fast (t->buffer.pre_data, vlib_buffer_get_current (b0),
137 sizeof (t->buffer.pre_data));
138}
139
Damjan Marion809d5c92021-03-24 12:24:58 +0100140static void
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200141virtio_interface_drop_inline (vlib_main_t *vm, virtio_if_t *vif,
142 uword node_index, u32 *buffers, u16 n,
143 virtio_tx_func_error_t error)
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200144{
145 vlib_error_count (vm, node_index, error, n);
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200146 vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
147 VNET_INTERFACE_COUNTER_DROP,
148 vm->thread_index, vif->sw_if_index, n);
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200149 vlib_buffer_free (vm, buffers, n);
150}
151
Damjan Marion809d5c92021-03-24 12:24:58 +0100152static void
153virtio_memset_ring_u32 (u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100154{
155 ASSERT (n_buffers <= ring_size);
156
157 if (PREDICT_TRUE (start + n_buffers <= ring_size))
158 {
159 clib_memset_u32 (ring + start, ~0, n_buffers);
160 }
161 else
162 {
163 clib_memset_u32 (ring + start, ~0, ring_size - start);
164 clib_memset_u32 (ring, ~0, n_buffers - (ring_size - start));
165 }
166}
167
Damjan Marion809d5c92021-03-24 12:24:58 +0100168static void
169virtio_free_used_device_desc_split (vlib_main_t *vm, virtio_vring_t *vring,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100170 uword node_index)
Damjan Marion8389fb92017-10-13 18:29:53 +0200171{
172 u16 used = vring->desc_in_use;
173 u16 sz = vring->size;
174 u16 mask = sz - 1;
175 u16 last = vring->last_used_idx;
176 u16 n_left = vring->used->idx - last;
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100177 u16 out_of_order_count = 0;
Damjan Marion8389fb92017-10-13 18:29:53 +0200178
179 if (n_left == 0)
180 return;
181
182 while (n_left)
183 {
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200184 vring_used_elem_t *e = &vring->used->ring[last & mask];
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200185 u16 slot, n_buffers;
186 slot = n_buffers = e->id;
Damjan Marion8389fb92017-10-13 18:29:53 +0200187
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100188 while (e->id == (n_buffers & mask))
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200189 {
190 n_left--;
191 last++;
192 n_buffers++;
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200193 vring_desc_t *d = &vring->desc[e->id];
Mohsin Kazmice215992020-04-10 14:57:06 +0000194 u16 next;
195 while (d->flags & VRING_DESC_F_NEXT)
196 {
197 n_buffers++;
198 next = d->next;
199 d = &vring->desc[next];
200 }
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200201 if (n_left == 0)
202 break;
203 e = &vring->used->ring[last & mask];
204 }
205 vlib_buffer_free_from_ring (vm, vring->buffers, slot,
206 sz, (n_buffers - slot));
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100207 virtio_memset_ring_u32 (vring->buffers, slot, sz, (n_buffers - slot));
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200208 used -= (n_buffers - slot);
209
210 if (n_left > 0)
211 {
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100212 vlib_buffer_free (vm, &vring->buffers[e->id], 1);
213 vring->buffers[e->id] = ~0;
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200214 used--;
215 last++;
216 n_left--;
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100217 out_of_order_count++;
218 vring->flags |= VRING_TX_OUT_OF_ORDER;
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200219 }
Damjan Marion8389fb92017-10-13 18:29:53 +0200220 }
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100221
222 /*
223 * Some vhost-backends give buffers back in out-of-order fashion in used ring.
224 * It impacts the overall virtio-performance.
225 */
226 if (out_of_order_count)
227 vlib_error_count (vm, node_index, VIRTIO_TX_ERROR_OUT_OF_ORDER,
228 out_of_order_count);
229
Damjan Marion8389fb92017-10-13 18:29:53 +0200230 vring->desc_in_use = used;
231 vring->last_used_idx = last;
232}
233
Damjan Marion809d5c92021-03-24 12:24:58 +0100234static void
235virtio_free_used_device_desc_packed (vlib_main_t *vm, virtio_vring_t *vring,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100236 uword node_index)
237{
238 vring_packed_desc_t *d;
239 u16 sz = vring->size;
240 u16 last = vring->last_used_idx;
241 u16 n_buffers = 0, start;
242 u16 flags;
243
244 if (vring->desc_in_use == 0)
245 return;
246
247 d = &vring->packed_desc[last];
248 flags = d->flags;
249 start = d->id;
250
251 while ((flags & VRING_DESC_F_AVAIL) == (vring->used_wrap_counter << 7) &&
252 (flags & VRING_DESC_F_USED) == (vring->used_wrap_counter << 15))
253 {
254 last++;
255 n_buffers++;
256
257 if (last >= sz)
258 {
259 last = 0;
260 vring->used_wrap_counter ^= 1;
261 }
262 d = &vring->packed_desc[last];
263 flags = d->flags;
264 }
265
266 if (n_buffers)
267 {
268 vlib_buffer_free_from_ring (vm, vring->buffers, start, sz, n_buffers);
269 virtio_memset_ring_u32 (vring->buffers, start, sz, n_buffers);
270 vring->desc_in_use -= n_buffers;
271 vring->last_used_idx = last;
272 }
273}
274
Damjan Marion809d5c92021-03-24 12:24:58 +0100275static void
276virtio_free_used_device_desc (vlib_main_t *vm, virtio_vring_t *vring,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100277 uword node_index, int packed)
278{
279 if (packed)
280 virtio_free_used_device_desc_packed (vm, vring, node_index);
281 else
282 virtio_free_used_device_desc_split (vm, vring, node_index);
283
284}
285
Damjan Marion809d5c92021-03-24 12:24:58 +0100286static void
287set_checksum_offsets (vlib_buffer_t *b, virtio_net_hdr_v1_t *hdr,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100288 const int is_l2)
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000289{
Mohsin Kazmi36f7a6a2021-05-05 14:26:38 +0200290 vnet_buffer_oflags_t oflags = vnet_buffer (b)->oflags;
Mohsin Kazmi68095382021-02-10 11:26:24 +0100291
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000292 if (b->flags & VNET_BUFFER_F_IS_IP4)
293 {
294 ip4_header_t *ip4;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000295 generic_header_offset_t gho = { 0 };
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200296 vnet_generic_header_offset_parser (b, &gho, is_l2, 1 /* ip4 */ ,
297 0 /* ip6 */ );
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000298 hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
299 hdr->csum_start = gho.l4_hdr_offset; // 0x22;
Mohsin Kazmi68095382021-02-10 11:26:24 +0100300 if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000301 {
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000302 hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
303 }
Mohsin Kazmi68095382021-02-10 11:26:24 +0100304 else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000305 {
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000306 hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
307 }
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000308
309 /*
310 * virtio devices do not support IP4 checksum offload. So driver takes care
311 * of it while doing tx.
312 */
313 ip4 =
314 (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
Mohsin Kazmi68095382021-02-10 11:26:24 +0100315 if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000316 ip4->checksum = ip4_header_checksum (ip4);
317 }
318 else if (b->flags & VNET_BUFFER_F_IS_IP6)
319 {
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000320 generic_header_offset_t gho = { 0 };
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200321 vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
322 1 /* ip6 */ );
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000323 hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
324 hdr->csum_start = gho.l4_hdr_offset; // 0x36;
Mohsin Kazmi68095382021-02-10 11:26:24 +0100325 if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000326 {
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000327 hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
328 }
Mohsin Kazmi68095382021-02-10 11:26:24 +0100329 else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000330 {
Mohsin Kazmi0937fdf2020-03-25 20:37:16 +0000331 hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
332 }
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000333 }
334}
335
Damjan Marion809d5c92021-03-24 12:24:58 +0100336static void
337set_gso_offsets (vlib_buffer_t *b, virtio_net_hdr_v1_t *hdr, const int is_l2)
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200338{
Mohsin Kazmi36f7a6a2021-05-05 14:26:38 +0200339 vnet_buffer_oflags_t oflags = vnet_buffer (b)->oflags;
Mohsin Kazmi68095382021-02-10 11:26:24 +0100340
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200341 if (b->flags & VNET_BUFFER_F_IS_IP4)
342 {
343 ip4_header_t *ip4;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000344 generic_header_offset_t gho = { 0 };
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200345 vnet_generic_header_offset_parser (b, &gho, is_l2, 1 /* ip4 */ ,
346 0 /* ip6 */ );
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200347 hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
348 hdr->gso_size = vnet_buffer2 (b)->gso_size;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000349 hdr->hdr_len = gho.hdr_sz;
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200350 hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
351 hdr->csum_start = gho.l4_hdr_offset; // 0x22;
352 hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
353 ip4 =
354 (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
355 /*
356 * virtio devices do not support IP4 checksum offload. So driver takes care
357 * of it while doing tx.
358 */
Mohsin Kazmi68095382021-02-10 11:26:24 +0100359 if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200360 ip4->checksum = ip4_header_checksum (ip4);
361 }
362 else if (b->flags & VNET_BUFFER_F_IS_IP6)
363 {
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000364 generic_header_offset_t gho = { 0 };
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200365 vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
366 1 /* ip6 */ );
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200367 hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
368 hdr->gso_size = vnet_buffer2 (b)->gso_size;
Mohsin Kazmi0b042092020-04-17 16:50:56 +0000369 hdr->hdr_len = gho.hdr_sz;
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200370 hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
371 hdr->csum_start = gho.l4_hdr_offset; // 0x36;
372 hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
373 }
374}
375
Damjan Marion809d5c92021-03-24 12:24:58 +0100376static u16
377add_buffer_to_slot (vlib_main_t *vm, vlib_node_runtime_t *node,
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200378 virtio_if_t *vif, virtio_vring_t *vring, u32 bi,
379 u16 free_desc_count, u16 avail, u16 next, u16 mask,
380 int hdr_sz, int do_gso, int csum_offload, int is_pci,
381 int is_tun, int is_indirect, int is_any_layout)
Damjan Marion8389fb92017-10-13 18:29:53 +0200382{
383 u16 n_added = 0;
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200384 vring_desc_t *d;
Damjan Mariond4a54712020-10-31 23:40:51 +0100385 int is_l2 = !is_tun;
Damjan Marion8389fb92017-10-13 18:29:53 +0200386 d = &vring->desc[next];
387 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200388 virtio_net_hdr_v1_t *hdr = vlib_buffer_get_current (b) - hdr_sz;
Damjan Mariond4a54712020-10-31 23:40:51 +0100389 u32 drop_inline = ~0;
Damjan Marion508cabc2018-02-08 19:49:22 +0100390
Damjan Mariond4a54712020-10-31 23:40:51 +0100391 clib_memset_u8 (hdr, 0, hdr_sz);
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000392
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200393 if (b->flags & VNET_BUFFER_F_GSO)
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +0200394 {
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200395 if (do_gso)
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200396 set_gso_offsets (b, hdr, is_l2);
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200397 else
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +0200398 {
Damjan Mariond4a54712020-10-31 23:40:51 +0100399 drop_inline = VIRTIO_TX_ERROR_GSO_PACKET_DROP;
400 goto done;
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +0200401 }
402 }
Mohsin Kazmi68095382021-02-10 11:26:24 +0100403 else if (b->flags & VNET_BUFFER_F_OFFLOAD)
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000404 {
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200405 if (csum_offload)
Mohsin Kazmi84f91fa2020-04-23 17:59:49 +0200406 set_checksum_offsets (b, hdr, is_l2);
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200407 else
408 {
Damjan Mariond4a54712020-10-31 23:40:51 +0100409 drop_inline = VIRTIO_TX_ERROR_CSUM_OFFLOAD_PACKET_DROP;
410 goto done;
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200411 }
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000412 }
Damjan Marion8389fb92017-10-13 18:29:53 +0200413
Mohsin Kazmi83143712020-10-07 13:23:55 +0200414 if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
415 {
Damjan Mariond4a54712020-10-31 23:40:51 +0100416 virtio_tx_trace (vm, node, b, bi, is_tun);
Mohsin Kazmi83143712020-10-07 13:23:55 +0200417 }
418
Damjan Marion8389fb92017-10-13 18:29:53 +0200419 if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
420 {
Damjan Mariond4a54712020-10-31 23:40:51 +0100421 d->addr = ((is_pci) ? vlib_buffer_get_current_pa (vm, b) :
422 pointer_to_uword (vlib_buffer_get_current (b))) - hdr_sz;
Damjan Marion8389fb92017-10-13 18:29:53 +0200423 d->len = b->current_length + hdr_sz;
424 d->flags = 0;
425 }
Damjan Mariond4a54712020-10-31 23:40:51 +0100426 else if (is_indirect)
Damjan Marion8389fb92017-10-13 18:29:53 +0200427 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200428 /*
429 * We are using single vlib_buffer_t for indirect descriptor(s)
430 * chain. Single descriptor is 16 bytes and vlib_buffer_t
431 * has 2048 bytes space. So maximum long chain can have 128
432 * (=2048/16) indirect descriptors.
433 * It can easily support 65535 bytes of Jumbo frames with
434 * each data buffer size of 512 bytes minimum.
435 */
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200436 u32 indirect_buffer = 0;
437 if (PREDICT_FALSE (vlib_buffer_alloc (vm, &indirect_buffer, 1) == 0))
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200438 {
Damjan Mariond4a54712020-10-31 23:40:51 +0100439 drop_inline = VIRTIO_TX_ERROR_INDIRECT_DESC_ALLOC_FAILED;
440 goto done;
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200441 }
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200442
443 vlib_buffer_t *indirect_desc = vlib_get_buffer (vm, indirect_buffer);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200444 indirect_desc->current_data = 0;
Mohsin Kazmiaea0df32019-05-23 14:32:58 +0200445 indirect_desc->flags |= VLIB_BUFFER_NEXT_PRESENT;
446 indirect_desc->next_buffer = bi;
447 bi = indirect_buffer;
Damjan Marion8389fb92017-10-13 18:29:53 +0200448
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200449 vring_desc_t *id =
450 (vring_desc_t *) vlib_buffer_get_current (indirect_desc);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200451 u32 count = 1;
Damjan Mariond4a54712020-10-31 23:40:51 +0100452 if (is_pci)
Damjan Marion8389fb92017-10-13 18:29:53 +0200453 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200454 d->addr = vlib_physmem_get_pa (vm, id);
455 id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
Damjan Marion8389fb92017-10-13 18:29:53 +0200456
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200457 /*
458 * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
459 * should be presented in separate descriptor and data will start
460 * from next descriptor.
461 */
Damjan Mariond4a54712020-10-31 23:40:51 +0100462 if (is_any_layout)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200463 id->len = b->current_length + hdr_sz;
464 else
465 {
466 id->len = hdr_sz;
467 id->flags = VRING_DESC_F_NEXT;
468 id->next = count;
469 count++;
470 id++;
471 id->addr = vlib_buffer_get_current_pa (vm, b);
472 id->len = b->current_length;
473 }
474 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
475 {
476 id->flags = VRING_DESC_F_NEXT;
477 id->next = count;
478 count++;
479 id++;
480 b = vlib_get_buffer (vm, b->next_buffer);
481 id->addr = vlib_buffer_get_current_pa (vm, b);
482 id->len = b->current_length;
Mohsin Kazmi637c97c2021-05-12 14:51:29 +0200483 if (PREDICT_FALSE (count == VIRTIO_TX_MAX_CHAIN_LEN))
484 {
485 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
486 vlib_error_count (vm, node->node_index,
487 VIRTIO_TX_ERROR_TRUNC_PACKET, 1);
488 break;
489 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200490 }
491 }
Mohsin Kazmi206acf82020-04-06 14:19:54 +0200492 else /* VIRTIO_IF_TYPE_[TAP | TUN] */
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200493 {
494 d->addr = pointer_to_uword (id);
495 /* first buffer in chain */
496 id->addr = pointer_to_uword (vlib_buffer_get_current (b)) - hdr_sz;
497 id->len = b->current_length + hdr_sz;
498
499 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
500 {
501 id->flags = VRING_DESC_F_NEXT;
502 id->next = count;
503 count++;
504 id++;
505 b = vlib_get_buffer (vm, b->next_buffer);
506 id->addr = pointer_to_uword (vlib_buffer_get_current (b));
507 id->len = b->current_length;
Mohsin Kazmi637c97c2021-05-12 14:51:29 +0200508 if (PREDICT_FALSE (count == VIRTIO_TX_MAX_CHAIN_LEN))
509 {
510 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
511 vlib_error_count (vm, node->node_index,
512 VIRTIO_TX_ERROR_TRUNC_PACKET, 1);
513 break;
514 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200515 }
516 }
517 id->flags = 0;
518 id->next = 0;
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200519 d->len = count * sizeof (vring_desc_t);
Damjan Marion8389fb92017-10-13 18:29:53 +0200520 d->flags = VRING_DESC_F_INDIRECT;
521 }
Damjan Mariond4a54712020-10-31 23:40:51 +0100522 else if (is_pci)
Mohsin Kazmice215992020-04-10 14:57:06 +0000523 {
524 u16 count = next;
525 vlib_buffer_t *b_temp = b;
526 u16 n_buffers_in_chain = 1;
527
528 /*
529 * Check the length of the chain for the required number of
530 * descriptors. Return from here, retry to get more descriptors,
531 * if chain length is greater than available descriptors.
532 */
533 while (b_temp->flags & VLIB_BUFFER_NEXT_PRESENT)
534 {
535 n_buffers_in_chain++;
536 b_temp = vlib_get_buffer (vm, b_temp->next_buffer);
537 }
538
539 if (n_buffers_in_chain > free_desc_count)
540 return n_buffers_in_chain;
541
542 d->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
543 d->len = b->current_length + hdr_sz;
544
545 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
546 {
547 d->flags = VRING_DESC_F_NEXT;
548 vring->buffers[count] = bi;
549 b->flags &=
550 ~(VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID);
551 bi = b->next_buffer;
552 b->next_buffer = 0;
553 n_added++;
554 count = (count + 1) & mask;
555 d->next = count;
556 d = &vring->desc[count];
557 b = vlib_get_buffer (vm, bi);
558 d->addr = vlib_buffer_get_current_pa (vm, b);
559 d->len = b->current_length;
560 }
561 d->flags = 0;
562 vring->buffers[count] = bi;
563 vring->avail->ring[avail & mask] = next;
564 n_added++;
565 return n_added;
566 }
567 else
568 {
569 ASSERT (0);
570 }
Damjan Marion8389fb92017-10-13 18:29:53 +0200571 vring->buffers[next] = bi;
572 vring->avail->ring[avail & mask] = next;
573 n_added++;
Damjan Mariond4a54712020-10-31 23:40:51 +0100574
575done:
576 if (drop_inline != ~0)
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200577 virtio_interface_drop_inline (vm, vif, node->node_index, &bi, 1,
578 drop_inline);
Damjan Mariond4a54712020-10-31 23:40:51 +0100579
Damjan Marion8389fb92017-10-13 18:29:53 +0200580 return n_added;
581}
582
Damjan Marion809d5c92021-03-24 12:24:58 +0100583static u16
584add_buffer_to_slot_packed (vlib_main_t *vm, vlib_node_runtime_t *node,
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200585 virtio_if_t *vif, virtio_vring_t *vring, u32 bi,
586 u16 next, int hdr_sz, int do_gso, int csum_offload,
587 int is_pci, int is_tun, int is_indirect,
588 int is_any_layout)
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100589{
590 u16 n_added = 0, flags = 0;
591 int is_l2 = !is_tun;
592 vring_packed_desc_t *d = &vring->packed_desc[next];
593 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
594 virtio_net_hdr_v1_t *hdr = vlib_buffer_get_current (b) - hdr_sz;
595 u32 drop_inline = ~0;
596
597 clib_memset (hdr, 0, hdr_sz);
598
599 if (b->flags & VNET_BUFFER_F_GSO)
600 {
601 if (do_gso)
602 set_gso_offsets (b, hdr, is_l2);
603 else
604 {
605 drop_inline = VIRTIO_TX_ERROR_GSO_PACKET_DROP;
606 goto done;
607 }
608 }
Mohsin Kazmi68095382021-02-10 11:26:24 +0100609 else if (b->flags & VNET_BUFFER_F_OFFLOAD)
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100610 {
611 if (csum_offload)
612 set_checksum_offsets (b, hdr, is_l2);
613 else
614 {
615 drop_inline = VIRTIO_TX_ERROR_CSUM_OFFLOAD_PACKET_DROP;
616 goto done;
617 }
618 }
619 if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
620 {
621 virtio_tx_trace (vm, node, b, bi, is_tun);
622 }
623
624 if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
625 {
626 d->addr =
627 ((is_pci) ? vlib_buffer_get_current_pa (vm,
628 b) :
629 pointer_to_uword (vlib_buffer_get_current (b))) - hdr_sz;
630 d->len = b->current_length + hdr_sz;
631 }
632 else if (is_indirect)
633 {
634 /*
635 * We are using single vlib_buffer_t for indirect descriptor(s)
636 * chain. Single descriptor is 16 bytes and vlib_buffer_t
637 * has 2048 bytes space. So maximum long chain can have 128
638 * (=2048/16) indirect descriptors.
639 * It can easily support 65535 bytes of Jumbo frames with
640 * each data buffer size of 512 bytes minimum.
641 */
642 u32 indirect_buffer = 0;
643 if (PREDICT_FALSE (vlib_buffer_alloc (vm, &indirect_buffer, 1) == 0))
644 {
645 drop_inline = VIRTIO_TX_ERROR_INDIRECT_DESC_ALLOC_FAILED;
646 goto done;
647 }
648
649 vlib_buffer_t *indirect_desc = vlib_get_buffer (vm, indirect_buffer);
650 indirect_desc->current_data = 0;
651 indirect_desc->flags |= VLIB_BUFFER_NEXT_PRESENT;
652 indirect_desc->next_buffer = bi;
653 bi = indirect_buffer;
654
655 vring_packed_desc_t *id =
656 (vring_packed_desc_t *) vlib_buffer_get_current (indirect_desc);
657 u32 count = 1;
658 if (is_pci)
659 {
660 d->addr = vlib_physmem_get_pa (vm, id);
661 id->addr = vlib_buffer_get_current_pa (vm, b) - hdr_sz;
662
663 /*
664 * If VIRTIO_F_ANY_LAYOUT is not negotiated, then virtio_net_hdr
665 * should be presented in separate descriptor and data will start
666 * from next descriptor.
667 */
668 if (is_any_layout)
669 id->len = b->current_length + hdr_sz;
670 else
671 {
672 id->len = hdr_sz;
673 id->flags = 0;
674 id->id = 0;
675 count++;
676 id++;
677 id->addr = vlib_buffer_get_current_pa (vm, b);
678 id->len = b->current_length;
679 }
680 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
681 {
682 id->flags = 0;
683 id->id = 0;
684 count++;
685 id++;
686 b = vlib_get_buffer (vm, b->next_buffer);
687 id->addr = vlib_buffer_get_current_pa (vm, b);
688 id->len = b->current_length;
Mohsin Kazmi637c97c2021-05-12 14:51:29 +0200689 if (PREDICT_FALSE (count == VIRTIO_TX_MAX_CHAIN_LEN))
690 {
691 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
692 vlib_error_count (vm, node->node_index,
693 VIRTIO_TX_ERROR_TRUNC_PACKET, 1);
694 break;
695 }
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100696 }
697 }
698 id->flags = 0;
699 id->id = 0;
700 d->len = count * sizeof (vring_packed_desc_t);
701 flags = VRING_DESC_F_INDIRECT;
702 }
703 else
704 {
705 ASSERT (0);
706 }
707 if (vring->avail_wrap_counter)
708 {
709 flags |= VRING_DESC_F_AVAIL;
710 flags &= ~VRING_DESC_F_USED;
711 }
712 else
713 {
714 flags &= ~VRING_DESC_F_AVAIL;
715 flags |= VRING_DESC_F_USED;
716 }
717
718 d->id = next;
719 d->flags = flags;
720 vring->buffers[next] = bi;
721 n_added++;
722
723done:
724 if (drop_inline != ~0)
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200725 virtio_interface_drop_inline (vm, vif, node->node_index, &bi, 1,
726 drop_inline);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100727
728 return n_added;
729}
730
Damjan Marion809d5c92021-03-24 12:24:58 +0100731static uword
732virtio_interface_tx_packed_gso_inline (vlib_main_t *vm,
733 vlib_node_runtime_t *node,
734 virtio_if_t *vif, virtio_if_type_t type,
735 virtio_vring_t *vring, u32 *buffers,
736 u16 n_left, const int do_gso,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100737 const int csum_offload)
738{
739 int is_pci = (type == VIRTIO_IF_TYPE_PCI);
740 int is_tun = (type == VIRTIO_IF_TYPE_TUN);
741 int is_indirect =
742 ((vif->features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) != 0);
743 int is_any_layout =
744 ((vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)) != 0);
745 const int hdr_sz = vif->virtio_net_hdr_sz;
746 u16 sz = vring->size;
747 u16 used, next, n_buffers = 0, n_buffers_left = 0;
748 u16 n_vectors = n_left;
749
750
751 used = vring->desc_in_use;
752 next = vring->desc_next;
753
754 if (vif->packet_buffering)
755 {
756 n_buffers = n_buffers_left = virtio_vring_n_buffers (vring->buffering);
757
758 while (n_buffers_left && used < sz)
759 {
760 u16 n_added = 0;
761
762 u32 bi = virtio_vring_buffering_read_from_front (vring->buffering);
763 if (bi == ~0)
764 break;
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200765 n_added = add_buffer_to_slot_packed (
766 vm, node, vif, vring, bi, next, hdr_sz, do_gso, csum_offload,
767 is_pci, is_tun, is_indirect, is_any_layout);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100768 n_buffers_left--;
769 if (PREDICT_FALSE (n_added == 0))
770 continue;
771
772 used++;
773 next++;
774 if (next >= sz)
775 {
776 next = 0;
777 vring->avail_wrap_counter ^= 1;
778 }
779 }
780 }
781
782 while (n_left && used < sz)
783 {
784 u16 n_added = 0;
785
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200786 n_added = add_buffer_to_slot_packed (
787 vm, node, vif, vring, buffers[0], next, hdr_sz, do_gso, csum_offload,
788 is_pci, is_tun, is_indirect, is_any_layout);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100789 buffers++;
790 n_left--;
791 if (PREDICT_FALSE (n_added == 0))
792 continue;
793
794 used++;
795 next++;
796 if (next >= sz)
797 {
798 next = 0;
799 vring->avail_wrap_counter ^= 1;
800 }
801 }
802
803 if (n_left != n_vectors || n_buffers != n_buffers_left)
804 {
805 CLIB_MEMORY_STORE_BARRIER ();
806 vring->desc_next = next;
807 vring->desc_in_use = used;
808 CLIB_MEMORY_BARRIER ();
809 if (vring->device_event->flags != VRING_EVENT_F_DISABLE)
810 virtio_kick (vm, vring, vif);
811 }
812
813 return n_left;
814}
815
Damjan Marion809d5c92021-03-24 12:24:58 +0100816static void
817virtio_find_free_desc (virtio_vring_t *vring, u16 size, u16 mask, u16 req,
818 u16 next, u32 *first_free_desc_index,
819 u16 *free_desc_count)
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100820{
821 u16 start = 0;
822 /* next is used as hint: from where to start looking */
823 for (u16 i = 0; i < size; i++, next++)
824 {
825 if (vring->buffers[next & mask] == ~0)
826 {
827 if (*first_free_desc_index == ~0)
828 {
829 *first_free_desc_index = (next & mask);
830 start = i;
831 (*free_desc_count)++;
832 req--;
833 if (req == 0)
834 break;
835 }
836 else
837 {
838 if (start + *free_desc_count == i)
839 {
840 (*free_desc_count)++;
841 req--;
842 if (req == 0)
843 break;
844 }
845 else
846 break;
847 }
848 }
849 }
850}
851
Damjan Marion809d5c92021-03-24 12:24:58 +0100852static u16
853virtio_interface_tx_split_gso_inline (vlib_main_t *vm,
854 vlib_node_runtime_t *node,
855 virtio_if_t *vif, virtio_if_type_t type,
856 virtio_vring_t *vring, u32 *buffers,
857 u16 n_left, int do_gso, int csum_offload)
Damjan Marion8389fb92017-10-13 18:29:53 +0200858{
Mohsin Kazmie347acb2020-09-28 10:26:33 +0000859 u16 used, next, avail, n_buffers = 0, n_buffers_left = 0;
Damjan Mariond4a54712020-10-31 23:40:51 +0100860 int is_pci = (type == VIRTIO_IF_TYPE_PCI);
861 int is_tun = (type == VIRTIO_IF_TYPE_TUN);
862 int is_indirect =
863 ((vif->features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) != 0);
864 int is_any_layout =
865 ((vif->features & VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)) != 0);
Damjan Marion8389fb92017-10-13 18:29:53 +0200866 u16 sz = vring->size;
Damjan Mariond4a54712020-10-31 23:40:51 +0100867 int hdr_sz = vif->virtio_net_hdr_sz;
Damjan Marion8389fb92017-10-13 18:29:53 +0200868 u16 mask = sz - 1;
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +0100869 u16 n_vectors = n_left;
Damjan Marion8389fb92017-10-13 18:29:53 +0200870
871 used = vring->desc_in_use;
872 next = vring->desc_next;
873 avail = vring->avail->idx;
874
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100875 u16 free_desc_count = 0;
876
877 if (PREDICT_FALSE (vring->flags & VRING_TX_OUT_OF_ORDER))
878 {
879 u32 first_free_desc_index = ~0;
880
881 virtio_find_free_desc (vring, sz, mask, n_left, next,
882 &first_free_desc_index, &free_desc_count);
883
884 if (free_desc_count)
885 next = first_free_desc_index;
886 }
887 else
888 free_desc_count = sz - used;
889
Mohsin Kazmie347acb2020-09-28 10:26:33 +0000890 if (vif->packet_buffering)
891 {
892 n_buffers = n_buffers_left = virtio_vring_n_buffers (vring->buffering);
893
894 while (n_buffers_left && free_desc_count)
895 {
896 u16 n_added = 0;
897
898 u32 bi = virtio_vring_buffering_read_from_front (vring->buffering);
899 if (bi == ~0)
900 break;
Mohsin Kazmi83143712020-10-07 13:23:55 +0200901
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200902 n_added = add_buffer_to_slot (vm, node, vif, vring, bi,
903 free_desc_count, avail, next, mask,
904 hdr_sz, do_gso, csum_offload, is_pci,
905 is_tun, is_indirect, is_any_layout);
Mohsin Kazmie347acb2020-09-28 10:26:33 +0000906 if (PREDICT_FALSE (n_added == 0))
907 {
908 n_buffers_left--;
909 continue;
910 }
911 else if (PREDICT_FALSE (n_added > free_desc_count))
912 break;
913
914 avail++;
915 next = (next + n_added) & mask;
916 used += n_added;
917 n_buffers_left--;
918 free_desc_count -= n_added;
919 }
920 }
921
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100922 while (n_left && free_desc_count)
Damjan Marion8389fb92017-10-13 18:29:53 +0200923 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200924 u16 n_added = 0;
Mohsin Kazmib5ca5592020-06-26 13:48:26 +0000925
Mohsin Kazmia02ad342021-05-04 16:36:09 +0200926 n_added =
927 add_buffer_to_slot (vm, node, vif, vring, buffers[0], free_desc_count,
928 avail, next, mask, hdr_sz, do_gso, csum_offload,
929 is_pci, is_tun, is_indirect, is_any_layout);
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200930
931 if (PREDICT_FALSE (n_added == 0))
932 {
933 buffers++;
934 n_left--;
935 continue;
936 }
Mohsin Kazmice215992020-04-10 14:57:06 +0000937 else if (PREDICT_FALSE (n_added > free_desc_count))
938 break;
Mohsin Kazmif50ef402020-04-09 22:11:29 +0200939
Mohsin Kazmice215992020-04-10 14:57:06 +0000940 avail++;
Damjan Marion8389fb92017-10-13 18:29:53 +0200941 next = (next + n_added) & mask;
942 used += n_added;
943 buffers++;
944 n_left--;
Mohsin Kazmice215992020-04-10 14:57:06 +0000945 free_desc_count -= n_added;
Damjan Marion8389fb92017-10-13 18:29:53 +0200946 }
947
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +0100948 if (n_left != n_vectors || n_buffers != n_buffers_left)
Damjan Marion8389fb92017-10-13 18:29:53 +0200949 {
Mohsin Kazmid8b7dec2020-12-10 09:49:21 +0000950 clib_atomic_store_seq_cst (&vring->avail->idx, avail);
Damjan Marion8389fb92017-10-13 18:29:53 +0200951 vring->desc_next = next;
952 vring->desc_in_use = used;
Mohsin Kazmid8b7dec2020-12-10 09:49:21 +0000953 if ((clib_atomic_load_seq_cst (&vring->used->flags) &
954 VRING_USED_F_NO_NOTIFY) == 0)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200955 virtio_kick (vm, vring, vif);
Damjan Marion8389fb92017-10-13 18:29:53 +0200956 }
957
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +0100958 return n_left;
Damjan Marion8389fb92017-10-13 18:29:53 +0200959}
960
Damjan Marion809d5c92021-03-24 12:24:58 +0100961static u16
962virtio_interface_tx_gso_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
963 virtio_if_t *vif, virtio_if_type_t type,
964 virtio_vring_t *vring, u32 *buffers,
965 u16 n_left, int packed, int do_gso,
966 int csum_offload)
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100967{
968 if (packed)
969 return virtio_interface_tx_packed_gso_inline (vm, node, vif, type, vring,
970 buffers, n_left,
Mohsin Kazmib18b1902020-12-03 16:35:20 +0100971 do_gso, csum_offload);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100972 else
973 return virtio_interface_tx_split_gso_inline (vm, node, vif, type, vring,
974 buffers, n_left,
Mohsin Kazmib18b1902020-12-03 16:35:20 +0100975 do_gso, csum_offload);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100976}
977
Damjan Marion809d5c92021-03-24 12:24:58 +0100978static u16
979virtio_interface_tx_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
980 virtio_if_t *vif, virtio_vring_t *vring,
981 virtio_if_type_t type, u32 *buffers, u16 n_left,
982 int packed)
Mohsin Kazmi38b09682020-06-03 18:20:17 +0200983{
984 vnet_main_t *vnm = vnet_get_main ();
985 vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
986
Mohsin Kazmi5b3f5232021-02-10 12:03:53 +0100987 if (hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO)
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +0100988 return virtio_interface_tx_gso_inline (vm, node, vif, type, vring,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100989 buffers, n_left, packed,
990 1 /* do_gso */ ,
Damjan Mariondc181242020-10-20 12:11:06 +0200991 1 /* checksum offload */ );
Mohsin Kazmi5b3f5232021-02-10 12:03:53 +0100992 else if (hw->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_L4_TX_CKSUM)
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +0100993 return virtio_interface_tx_gso_inline (vm, node, vif, type, vring,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100994 buffers, n_left, packed,
Mohsin Kazmi38b09682020-06-03 18:20:17 +0200995 0 /* no do_gso */ ,
Damjan Mariondc181242020-10-20 12:11:06 +0200996 1 /* checksum offload */ );
Mohsin Kazmi38b09682020-06-03 18:20:17 +0200997 else
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +0100998 return virtio_interface_tx_gso_inline (vm, node, vif, type, vring,
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100999 buffers, n_left, packed,
Mohsin Kazmi38b09682020-06-03 18:20:17 +02001000 0 /* no do_gso */ ,
Damjan Mariondc181242020-10-20 12:11:06 +02001001 0 /* no checksum offload */ );
Mohsin Kazmi38b09682020-06-03 18:20:17 +02001002}
1003
Filip Tehlaraee73642019-03-13 05:50:44 -07001004VNET_DEVICE_CLASS_TX_FN (virtio_device_class) (vlib_main_t * vm,
1005 vlib_node_runtime_t * node,
1006 vlib_frame_t * frame)
Damjan Marion8389fb92017-10-13 18:29:53 +02001007{
1008 virtio_main_t *nm = &virtio_main;
1009 vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
1010 virtio_if_t *vif = pool_elt_at_index (nm->interfaces, rund->dev_instance);
Damjan Mariondc181242020-10-20 12:11:06 +02001011 u16 qid = vm->thread_index % vif->num_txqs;
1012 virtio_vring_t *vring = vec_elt_at_index (vif->txq_vrings, qid);
Mohsin Kazmiee1e30f2020-10-23 11:23:52 +02001013 u16 n_left = frame->n_vectors;
1014 u32 *buffers = vlib_frame_vector_args (frame);
1015 u32 to[GRO_TO_VECTOR_SIZE (n_left)];
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001016 int packed = vif->is_packed;
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001017 u16 n_vectors = frame->n_vectors;
Damjan Mariondc181242020-10-20 12:11:06 +02001018
1019 clib_spinlock_lock_if_init (&vring->lockp);
1020
Mohsin Kazmiee1e30f2020-10-23 11:23:52 +02001021 if (vif->packet_coalesce)
1022 {
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001023 n_vectors = n_left =
1024 vnet_gro_inline (vm, vring->flow_table, buffers, n_left, to);
Mohsin Kazmiee1e30f2020-10-23 11:23:52 +02001025 buffers = to;
1026 }
1027
Damjan Marion587f9132020-10-31 22:47:01 +01001028 u16 retry_count = 2;
1029
1030retry:
1031 /* free consumed buffers */
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001032 virtio_free_used_device_desc (vm, vring, node->node_index, packed);
Damjan Marion587f9132020-10-31 22:47:01 +01001033
Mohsin Kazmi38b09682020-06-03 18:20:17 +02001034 if (vif->type == VIRTIO_IF_TYPE_TAP)
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001035 n_left = virtio_interface_tx_inline (vm, node, vif, vring,
Mohsin Kazmi81dac062020-11-11 20:28:35 +01001036 VIRTIO_IF_TYPE_TAP,
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001037 &buffers[n_vectors - n_left],
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001038 n_left, packed);
Mohsin Kazmi38b09682020-06-03 18:20:17 +02001039 else if (vif->type == VIRTIO_IF_TYPE_PCI)
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001040 n_left = virtio_interface_tx_inline (vm, node, vif, vring,
Mohsin Kazmi81dac062020-11-11 20:28:35 +01001041 VIRTIO_IF_TYPE_PCI,
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001042 &buffers[n_vectors - n_left],
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001043 n_left, packed);
Mohsin Kazmi38b09682020-06-03 18:20:17 +02001044 else if (vif->type == VIRTIO_IF_TYPE_TUN)
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001045 n_left = virtio_interface_tx_inline (vm, node, vif, vring,
Mohsin Kazmi81dac062020-11-11 20:28:35 +01001046 VIRTIO_IF_TYPE_TUN,
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001047 &buffers[n_vectors - n_left],
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001048 n_left, packed);
Andrew Yourtchenko6a7cff72018-10-12 16:09:22 +02001049 else
Mohsin Kazmi38b09682020-06-03 18:20:17 +02001050 ASSERT (0);
1051
Damjan Marion587f9132020-10-31 22:47:01 +01001052 if (n_left && retry_count--)
1053 goto retry;
1054
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001055 if (vif->packet_buffering && n_left)
1056 {
Mohsin Kazmi81dac062020-11-11 20:28:35 +01001057 u16 n_buffered = virtio_vring_buffering_store_packets (vring->buffering,
1058 &buffers
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001059 [n_vectors
Mohsin Kazmi81dac062020-11-11 20:28:35 +01001060 - n_left],
1061 n_left);
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001062 n_left -= n_buffered;
1063 }
1064 if (n_left)
Mohsin Kazmia02ad342021-05-04 16:36:09 +02001065 virtio_interface_drop_inline (vm, vif, node->node_index,
Mohsin Kazmie2e9fe52020-12-17 15:54:03 +01001066 &buffers[n_vectors - n_left], n_left,
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001067 VIRTIO_TX_ERROR_NO_FREE_SLOTS);
1068
Damjan Mariondc181242020-10-20 12:11:06 +02001069 clib_spinlock_unlock_if_init (&vring->lockp);
1070
Mohsin Kazmi2e6f6242020-10-26 12:41:41 +01001071 return frame->n_vectors - n_left;
Damjan Marion8389fb92017-10-13 18:29:53 +02001072}
1073
1074static void
1075virtio_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
1076 u32 node_index)
1077{
1078 virtio_main_t *apm = &virtio_main;
1079 vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1080 virtio_if_t *vif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
1081
1082 /* Shut off redirection */
1083 if (node_index == ~0)
1084 {
1085 vif->per_interface_next_index = node_index;
1086 return;
1087 }
1088
1089 vif->per_interface_next_index =
1090 vlib_node_add_next (vlib_get_main (), virtio_input_node.index,
1091 node_index);
1092}
1093
1094static void
1095virtio_clear_hw_interface_counters (u32 instance)
1096{
1097 /* Nothing for now */
1098}
1099
Damjan Marion809d5c92021-03-24 12:24:58 +01001100static void
1101virtio_set_rx_interrupt (virtio_if_t *vif, virtio_vring_t *vring)
Mohsin Kazmi24841862020-12-02 16:39:42 +01001102{
1103 if (vif->is_packed)
1104 vring->driver_event->flags &= ~VRING_EVENT_F_DISABLE;
1105 else
1106 vring->avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
1107}
1108
Damjan Marion809d5c92021-03-24 12:24:58 +01001109static void
1110virtio_set_rx_polling (virtio_if_t *vif, virtio_vring_t *vring)
Mohsin Kazmi24841862020-12-02 16:39:42 +01001111{
1112 if (vif->is_packed)
1113 vring->driver_event->flags |= VRING_EVENT_F_DISABLE;
1114 else
1115 vring->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
1116}
1117
Damjan Marion8389fb92017-10-13 18:29:53 +02001118static clib_error_t *
1119virtio_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
Damjan Marioneabd4242020-10-07 20:59:07 +02001120 vnet_hw_if_rx_mode mode)
Damjan Marion8389fb92017-10-13 18:29:53 +02001121{
Mohsin Kazmia5203b52020-10-12 13:01:24 +02001122 vlib_main_t *vm = vnm->vlib_main;
Damjan Marion8389fb92017-10-13 18:29:53 +02001123 virtio_main_t *mm = &virtio_main;
1124 vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1125 virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
Mohsin Kazmi1017a1d2020-09-25 15:36:19 +02001126 virtio_vring_t *rx_vring = vec_elt_at_index (vif->rxq_vrings, qid);
Damjan Marion8389fb92017-10-13 18:29:53 +02001127
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001128 if (vif->type == VIRTIO_IF_TYPE_PCI && !(vif->support_int_mode))
1129 {
Mohsin Kazmi24841862020-12-02 16:39:42 +01001130 virtio_set_rx_polling (vif, rx_vring);
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001131 return clib_error_return (0, "interrupt mode is not supported");
1132 }
1133
Damjan Marioneabd4242020-10-07 20:59:07 +02001134 if (mode == VNET_HW_IF_RX_MODE_POLLING)
Mohsin Kazmi9e2a7852020-08-13 18:57:26 +02001135 {
Mohsin Kazmia5203b52020-10-12 13:01:24 +02001136 if (vif->packet_coalesce || vif->packet_buffering)
1137 {
1138 if (mm->interrupt_queues_count > 0)
1139 mm->interrupt_queues_count--;
1140 if (mm->interrupt_queues_count == 0)
1141 vlib_process_signal_event (vm,
1142 virtio_send_interrupt_node.index,
1143 VIRTIO_EVENT_STOP_TIMER, 0);
1144 }
Mohsin Kazmi24841862020-12-02 16:39:42 +01001145 virtio_set_rx_polling (vif, rx_vring);
Mohsin Kazmi9e2a7852020-08-13 18:57:26 +02001146 }
Damjan Marion8389fb92017-10-13 18:29:53 +02001147 else
Mohsin Kazmi9e2a7852020-08-13 18:57:26 +02001148 {
Mohsin Kazmie347acb2020-09-28 10:26:33 +00001149 if (vif->packet_coalesce || vif->packet_buffering)
Mohsin Kazmi1017a1d2020-09-25 15:36:19 +02001150 {
Mohsin Kazmia5203b52020-10-12 13:01:24 +02001151 mm->interrupt_queues_count++;
1152 if (mm->interrupt_queues_count == 1)
1153 vlib_process_signal_event (vm,
1154 virtio_send_interrupt_node.index,
1155 VIRTIO_EVENT_START_TIMER, 0);
Mohsin Kazmi1017a1d2020-09-25 15:36:19 +02001156 }
Mohsin Kazmi24841862020-12-02 16:39:42 +01001157 virtio_set_rx_interrupt (vif, rx_vring);
Mohsin Kazmi9e2a7852020-08-13 18:57:26 +02001158 }
Damjan Marion8389fb92017-10-13 18:29:53 +02001159
Mohsin Kazmia5203b52020-10-12 13:01:24 +02001160 rx_vring->mode = mode;
1161
Damjan Marion8389fb92017-10-13 18:29:53 +02001162 return 0;
1163}
1164
1165static clib_error_t *
1166virtio_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1167{
1168 virtio_main_t *mm = &virtio_main;
1169 vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1170 virtio_if_t *vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
Damjan Marion8389fb92017-10-13 18:29:53 +02001171
1172 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
Mohsin Kazmi529f0e92020-03-19 14:03:31 +01001173 {
1174 vif->flags |= VIRTIO_IF_FLAG_ADMIN_UP;
1175 vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
1176 VNET_HW_INTERFACE_FLAG_LINK_UP);
1177 }
Damjan Marion8389fb92017-10-13 18:29:53 +02001178 else
Mohsin Kazmi529f0e92020-03-19 14:03:31 +01001179 {
1180 vif->flags &= ~VIRTIO_IF_FLAG_ADMIN_UP;
1181 vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
1182 }
Damjan Marion8389fb92017-10-13 18:29:53 +02001183 return 0;
1184}
1185
1186static clib_error_t *
1187virtio_subif_add_del_function (vnet_main_t * vnm,
1188 u32 hw_if_index,
1189 struct vnet_sw_interface_t *st, int is_add)
1190{
1191 /* Nothing for now */
1192 return 0;
1193}
1194
1195/* *INDENT-OFF* */
1196VNET_DEVICE_CLASS (virtio_device_class) = {
1197 .name = "virtio",
Damjan Marion8389fb92017-10-13 18:29:53 +02001198 .format_device_name = format_virtio_device_name,
1199 .format_device = format_virtio_device,
1200 .format_tx_trace = format_virtio_tx_trace,
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001201 .tx_function_n_errors = VIRTIO_TX_N_ERROR,
Damjan Marion8389fb92017-10-13 18:29:53 +02001202 .tx_function_error_strings = virtio_tx_func_error_strings,
1203 .rx_redirect_to_node = virtio_set_interface_next_node,
1204 .clear_counters = virtio_clear_hw_interface_counters,
1205 .admin_up_down_function = virtio_interface_admin_up_down,
1206 .subif_add_del_function = virtio_subif_add_del_function,
1207 .rx_mode_change_function = virtio_interface_rx_mode_change,
1208};
Mohsin Kazmi206acf82020-04-06 14:19:54 +02001209
Damjan Marion8389fb92017-10-13 18:29:53 +02001210/* *INDENT-ON* */
1211
1212/*
1213 * fd.io coding-style-patch-verification: ON
1214 *
1215 * Local Variables:
1216 * eval: (c-set-style "gnu")
1217 * End:
1218 */