fib: set the value of the sw_if_index for DROP route
[vpp.git] / src / plugins / rdma / input.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 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 <vlib/vlib.h>
19 #include <vlib/unix/unix.h>
20 #include <vlib/pci/pci.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/devices/devices.h>
23 #include <vnet/interface/rx_queue_funcs.h>
24
25 #include <rdma/rdma.h>
26
27 #define foreach_rdma_input_error \
28   _(BUFFER_ALLOC, "buffer alloc error")
29
30 typedef enum
31 {
32 #define _(f,s) RDMA_INPUT_ERROR_##f,
33   foreach_rdma_input_error
34 #undef _
35     RDMA_INPUT_N_ERROR,
36 } rdma_input_error_t;
37
38 static __clib_unused char *rdma_input_error_strings[] = {
39 #define _(n,s) s,
40   foreach_rdma_input_error
41 #undef _
42 };
43
44
45 static_always_inline void
46 ibv_set_recv_wr_and_sge (struct ibv_recv_wr *w, struct ibv_sge *s, u64 va,
47                          u32 data_size, u32 lkey)
48 {
49   s[0].addr = va;
50   s[0].length = data_size;
51   s[0].lkey = lkey;
52   w[0].next = w + 1;
53   w[0].sg_list = s;
54   w[0].num_sge = 1;
55 }
56
57 static_always_inline u32
58 rdma_device_legacy_input_refill_additional (vlib_main_t * vm,
59                                             rdma_device_t * rd,
60                                             rdma_rxq_t * rxq,
61                                             rdma_per_thread_data_t * ptd,
62                                             vlib_buffer_t * bt,
63                                             u32 first_slot, u32 n_alloc)
64 {
65   int i;
66   u8 log_wqe_sz = rxq->log_wqe_sz;
67   u32 *bi = ptd->tmp_bi;
68   vlib_buffer_t **bufs = ptd->tmp_bufs;
69
70   for (i = 0; i < n_alloc; i++)
71     {
72       u8 chain_sz = rxq->n_used_per_chain[first_slot + i];
73       u8 chain_sz_alloc;
74       mlx5dv_wqe_ds_t *current_wqe =
75         rxq->wqes + ((first_slot + i) << log_wqe_sz);
76       if (chain_sz == 0)
77         continue;
78       if (PREDICT_FALSE ((chain_sz_alloc =
79                           vlib_buffer_alloc_from_pool (vm, bi, chain_sz,
80                                                        rd->pool)) !=
81                          chain_sz))
82         {
83           vlib_buffer_free (vm, bi, chain_sz_alloc);
84           break;
85         }
86       /*Build the chain */
87       vlib_get_buffers (vm, bi, bufs, chain_sz);
88       for (int j = 0; j < chain_sz - 1; j++)
89         {
90           vlib_buffer_copy_template (bufs[j], bt);
91           bufs[j]->next_buffer = bi[j + 1];
92           bufs[j]->flags |= VLIB_BUFFER_NEXT_PRESENT;
93         }
94       /* The chain starting at the second buffer is pre-initialised */
95       vlib_buffer_copy_template (bufs[chain_sz - 1], bt);
96       /* Stick with the already existing chain */
97       if (chain_sz < rxq->n_ds_per_wqe - 1)
98         {
99           bufs[chain_sz - 1]->next_buffer = rxq->second_bufs[first_slot + i];
100           bufs[chain_sz - 1]->flags |= VLIB_BUFFER_NEXT_PRESENT;
101         }
102       else
103         {
104           bufs[chain_sz - 1]->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
105         }
106
107       /* Update the wqes */
108       for (int j = 0; j < chain_sz; j++)
109         {
110           u64 addr;
111           vlib_get_buffers_with_offset (vm, bi + j,
112                                         (void *) &addr, 1,
113                                         sizeof (vlib_buffer_t));
114           current_wqe[j + 1].addr = clib_host_to_net_u64 (addr);
115         }
116       rxq->n_used_per_chain[first_slot + i] = 0;
117       rxq->n_total_additional_segs -= chain_sz;
118       rxq->second_bufs[first_slot + i] = bi[0];
119     }
120   return i;
121 }
122
123 static_always_inline void
124 rdma_device_input_refill (vlib_main_t * vm, rdma_device_t * rd,
125                           rdma_rxq_t * rxq, vlib_buffer_t * bt,
126                           const int is_mlx5dv, const int is_striding)
127 {
128   u32 n_alloc, n;
129   u16 ring_space;
130   struct ibv_recv_wr wr[VLIB_FRAME_SIZE], *w = wr;
131   struct ibv_sge sge[VLIB_FRAME_SIZE], *s = sge;
132   rdma_per_thread_data_t *ptd =
133     &rdma_main.per_thread_data[vlib_get_thread_index ()];
134   u32 mask = rxq->size - 1;
135   u32 slot = rxq->tail & mask;
136   u32 *bufs = rxq->bufs + slot;
137   u32 data_size = rxq->buf_sz;
138   u32 lkey = rd->lkey;
139   const int log_stride_per_wqe = is_striding ? rxq->log_stride_per_wqe : 0;
140   const int log_wqe_sz = rxq->log_wqe_sz;
141
142   /*In legacy mode, maybe some buffers chains are incomplete? */
143   if (PREDICT_FALSE
144       (is_mlx5dv && !is_striding && (rxq->incomplete_tail != rxq->tail)))
145     {
146       int n_incomplete = rxq->incomplete_tail - rxq->tail;
147       int n_completed =
148         rdma_device_legacy_input_refill_additional (vm, rd, rxq, ptd, bt,
149                                                     slot,
150                                                     n_incomplete);
151       rxq->tail += n_completed;
152       slot = rxq->tail & mask;
153       /* Don't start recycling head buffers if there are incomplete chains */
154       if (n_completed != n_incomplete)
155         return;
156     }
157
158   /* refilled buffers must be a multiple of 8 and of strides per WQE */
159   u32 alloc_multiple = 1 << (clib_max (3, log_stride_per_wqe));
160
161   ring_space = rxq->size - (rxq->tail - rxq->head);
162
163   n_alloc = clib_min (VLIB_FRAME_SIZE, ring_space);
164
165   /* do not bother to allocate if too small */
166   if (n_alloc < 2 * alloc_multiple)
167     return;
168
169   /* avoid wrap-around logic in core loop */
170   n_alloc = clib_min (n_alloc, rxq->size - slot);
171
172   n_alloc &= ~(alloc_multiple - 1);     /* round to alloc_multiple */
173
174   n = vlib_buffer_alloc_to_ring_from_pool (vm, rxq->bufs, slot, rxq->size,
175                                            n_alloc, rd->pool);
176
177   if (PREDICT_FALSE (n != n_alloc))
178     {
179       u32 n_free;
180       if (n < alloc_multiple)
181         {
182           if (n)
183             vlib_buffer_free_from_ring (vm, rxq->bufs, slot, rxq->size, n);
184           return;
185         }
186
187       /* partial allocation, round and return rest */
188       n_free = n & (alloc_multiple - 1);
189       n -= n_free;
190       if (n_free)
191         vlib_buffer_free_from_ring (vm, rxq->bufs, (slot + n) & mask,
192                                     rxq->size, n_free);
193     }
194
195   n_alloc = n;
196
197   if (is_mlx5dv)
198     {
199       u64 __clib_aligned (32) va[8];
200
201       /* slot does not necessarily correspond to the slot
202          in the wqes ring (in 16B words) */
203       u32 wqes_slot = slot << (log_wqe_sz - log_stride_per_wqe);
204       const u32 wqe_cnt = rxq->wqe_cnt;
205       mlx5dv_wqe_ds_t *wqe = rxq->wqes + wqes_slot;
206       const int wqe_sz = 1 << log_wqe_sz;
207       const int stride_per_wqe = 1 << log_stride_per_wqe;
208       int current_data_seg = 0;
209
210       /* In legacy mode, this function only refills head descriptors for each
211          WQE, so RDMA_RXQ_MAX_CHAIN_SZ-1 data segments are skipped per WQE */
212       const int log_skip_wqe = is_striding ? 0 : log_wqe_sz;
213
214       while (n >= 1)
215         {
216           vlib_get_buffers_with_offset (vm, rxq->bufs + slot, (void **) va, 8,
217                                         sizeof (vlib_buffer_t));
218 #ifdef CLIB_HAVE_VEC256
219           *(u64x4 *) va = u64x4_byte_swap (*(u64x4 *) va);
220           *(u64x4 *) (va + 4) = u64x4_byte_swap (*(u64x4 *) (va + 4));
221 #else
222           for (int i = 0; i < 8; i++)
223             va[i] = clib_host_to_net_u64 (va[i]);
224 #endif
225
226           /*In striding RQ mode, the first 16B-word of the WQE is the SRQ header.
227              It is initialised as if it were a LINKED_LIST, as we have no guarantee
228              about what RDMA core does (CYCLIC_RQ or LINKED_LIST_RQ). In cyclic
229              mode, the SRQ header is ignored anyways... */
230
231           if (is_striding && !(current_data_seg & (wqe_sz - 1)))
232             *(mlx5dv_wqe_srq_next_t *) wqe = (mlx5dv_wqe_srq_next_t)
233             {
234               .rsvd0 = {0},
235               .next_wqe_index = clib_host_to_net_u16 (((wqes_slot >> log_wqe_sz) + 1) & (wqe_cnt - 1)),
236               .signature = 0,
237               .rsvd1 = {0}
238             };
239
240           /* TODO: when log_skip_wqe > 2, hw_prefetcher doesn't work, lots of LLC store
241              misses occur for wqes, to be fixed... */
242           if (!is_striding || !(current_data_seg & ~(stride_per_wqe - 1)))
243             {
244               wqe[(0 << log_skip_wqe) + is_striding].addr = va[0];
245               wqe[(1 << log_skip_wqe) + is_striding].addr = va[1];
246               wqe[(2 << log_skip_wqe) + is_striding].addr = va[2];
247               wqe[(3 << log_skip_wqe) + is_striding].addr = va[3];
248               wqe[(4 << log_skip_wqe) + is_striding].addr = va[4];
249               wqe[(5 << log_skip_wqe) + is_striding].addr = va[5];
250               wqe[(6 << log_skip_wqe) + is_striding].addr = va[6];
251               wqe[(7 << log_skip_wqe) + is_striding].addr = va[7];
252               slot += 8;
253               n -= 8;
254             }
255           wqe += 8 << log_skip_wqe;
256           wqes_slot += 8 << log_skip_wqe;
257           current_data_seg += 8;
258           current_data_seg &= wqe_sz - 1;
259         }
260
261       /* In legacy mode, there is some work required to finish building the SG lists */
262       if (!is_striding)
263         {
264           int first_slot = slot - n_alloc;
265           rxq->incomplete_tail += n_alloc;
266           if (PREDICT_FALSE (rxq->n_total_additional_segs))
267             n_alloc =
268               rdma_device_legacy_input_refill_additional (vm, rd, rxq, ptd,
269                                                           bt, first_slot,
270                                                           n_alloc);
271         }
272       CLIB_MEMORY_STORE_BARRIER ();
273       rxq->tail += n_alloc;
274       if (is_striding)
275         {
276           rxq->striding_wqe_tail += n_alloc >> log_stride_per_wqe;
277           rxq->wq_db[MLX5_RCV_DBR] =
278             clib_host_to_net_u32 (rxq->striding_wqe_tail);
279         }
280       else
281         rxq->wq_db[MLX5_RCV_DBR] = clib_host_to_net_u32 (rxq->tail);
282       return;
283     }
284
285   while (n >= 8)
286     {
287       u64 va[8];
288       if (PREDICT_TRUE (n >= 16))
289         {
290           clib_prefetch_store (s + 16);
291           clib_prefetch_store (w + 16);
292         }
293
294       vlib_get_buffers_with_offset (vm, bufs, (void **) va, 8,
295                                     sizeof (vlib_buffer_t));
296
297       ibv_set_recv_wr_and_sge (w++, s++, va[0], data_size, lkey);
298       ibv_set_recv_wr_and_sge (w++, s++, va[1], data_size, lkey);
299       ibv_set_recv_wr_and_sge (w++, s++, va[2], data_size, lkey);
300       ibv_set_recv_wr_and_sge (w++, s++, va[3], data_size, lkey);
301       ibv_set_recv_wr_and_sge (w++, s++, va[4], data_size, lkey);
302       ibv_set_recv_wr_and_sge (w++, s++, va[5], data_size, lkey);
303       ibv_set_recv_wr_and_sge (w++, s++, va[6], data_size, lkey);
304       ibv_set_recv_wr_and_sge (w++, s++, va[7], data_size, lkey);
305
306       bufs += 8;
307       n -= 8;
308     }
309
310   w[-1].next = 0;               /* fix next pointer in WR linked-list last item */
311
312   n = n_alloc;
313   if (ibv_post_wq_recv (rxq->wq, wr, &w) != 0)
314     {
315       n = w - wr;
316       vlib_buffer_free_from_ring (vm, rxq->bufs, slot + n, rxq->size,
317                                   n_alloc - n);
318     }
319
320   rxq->tail += n;
321 }
322
323 static_always_inline void
324 rdma_device_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
325                          const rdma_device_t * rd, u32 n_left,
326                          const u32 * bi, u32 next_index, u16 * cqe_flags,
327                          int is_mlx5dv)
328 {
329   u32 n_trace = vlib_get_trace_count (vm, node);
330
331   if (PREDICT_TRUE (0 == n_trace))
332     return;
333
334   while (n_trace && n_left)
335     {
336       vlib_buffer_t *b = vlib_get_buffer (vm, bi[0]);
337       if (PREDICT_TRUE
338           (vlib_trace_buffer (vm, node, next_index, b, /* follow_chain */ 0)))
339         {
340           rdma_input_trace_t *tr = vlib_add_trace (vm, node, b, sizeof (*tr));
341           tr->next_index = next_index;
342           tr->hw_if_index = rd->hw_if_index;
343           tr->cqe_flags = is_mlx5dv ? clib_net_to_host_u16 (cqe_flags[0]) : 0;
344           n_trace--;
345         }
346       /* next */
347       n_left--;
348       cqe_flags++;
349       bi++;
350     }
351   vlib_set_trace_count (vm, node, n_trace);
352 }
353
354 static_always_inline void
355 rdma_device_input_ethernet (vlib_main_t * vm, vlib_node_runtime_t * node,
356                             const rdma_device_t * rd, u32 next_index,
357                             int skip_ip4_cksum)
358 {
359   vlib_next_frame_t *nf;
360   vlib_frame_t *f;
361   ethernet_input_frame_t *ef;
362
363   if (PREDICT_FALSE (VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT != next_index))
364     return;
365
366   nf =
367     vlib_node_runtime_get_next_frame (vm, node,
368                                       VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT);
369   f = vlib_get_frame (vm, nf->frame);
370   f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
371   if (skip_ip4_cksum)
372     f->flags |= ETH_INPUT_FRAME_F_IP4_CKSUM_OK;
373
374   ef = vlib_frame_scalar_args (f);
375   ef->sw_if_index = rd->sw_if_index;
376   ef->hw_if_index = rd->hw_if_index;
377 }
378
379 static_always_inline u32
380 rdma_device_input_bufs (vlib_main_t * vm, const rdma_device_t * rd,
381                         vlib_buffer_t ** b, struct ibv_wc *wc,
382                         u32 n_left_from, vlib_buffer_t * bt)
383 {
384   u32 n_rx_bytes = 0;
385
386   while (n_left_from >= 4)
387     {
388       if (PREDICT_TRUE (n_left_from >= 8))
389         {
390           clib_prefetch_load (&wc[4 + 0]);
391           clib_prefetch_load (&wc[4 + 1]);
392           clib_prefetch_load (&wc[4 + 2]);
393           clib_prefetch_load (&wc[4 + 3]);
394           vlib_prefetch_buffer_header (b[4 + 0], STORE);
395           vlib_prefetch_buffer_header (b[4 + 1], STORE);
396           vlib_prefetch_buffer_header (b[4 + 2], STORE);
397           vlib_prefetch_buffer_header (b[4 + 3], STORE);
398         }
399
400       vlib_buffer_copy_template (b[0], bt);
401       vlib_buffer_copy_template (b[1], bt);
402       vlib_buffer_copy_template (b[2], bt);
403       vlib_buffer_copy_template (b[3], bt);
404
405       n_rx_bytes += b[0]->current_length = wc[0].byte_len;
406       n_rx_bytes += b[1]->current_length = wc[1].byte_len;
407       n_rx_bytes += b[2]->current_length = wc[2].byte_len;
408       n_rx_bytes += b[3]->current_length = wc[3].byte_len;
409
410       b += 4;
411       wc += 4;
412       n_left_from -= 4;
413     }
414
415   while (n_left_from >= 1)
416     {
417       vlib_buffer_copy_template (b[0], bt);
418       n_rx_bytes += b[0]->current_length = wc[0].byte_len;
419
420       b += 1;
421       wc += 1;
422       n_left_from -= 1;
423     }
424
425   return n_rx_bytes;
426 }
427
428 static_always_inline void
429 process_mini_cqes (rdma_rxq_t * rxq, u32 skip, u32 n_left, u32 cq_ci,
430                    u32 mask, u32 * byte_cnt)
431 {
432   mlx5dv_mini_cqe_t *mcqe;
433   u32 mcqe_array_index = (cq_ci + 1) & mask;
434   mcqe = (mlx5dv_mini_cqe_t *) (rxq->cqes + mcqe_array_index);
435
436   mcqe_array_index = cq_ci;
437
438   if (skip)
439     {
440       u32 n = skip & ~7;
441
442       if (n)
443         {
444           mcqe_array_index = (mcqe_array_index + n) & mask;
445           mcqe = (mlx5dv_mini_cqe_t *) (rxq->cqes + mcqe_array_index);
446           skip -= n;
447         }
448
449       if (skip)
450         {
451           n = clib_min (8 - skip, n_left);
452           for (int i = 0; i < n; i++)
453             byte_cnt[i] = mcqe[skip + i].byte_count;
454           mcqe_array_index = (mcqe_array_index + 8) & mask;
455           mcqe = (mlx5dv_mini_cqe_t *) (rxq->cqes + mcqe_array_index);
456           n_left -= n;
457           byte_cnt += n;
458         }
459
460     }
461
462   while (n_left >= 8)
463     {
464       for (int i = 0; i < 8; i++)
465         byte_cnt[i] = mcqe[i].byte_count;
466
467       n_left -= 8;
468       byte_cnt += 8;
469       mcqe_array_index = (mcqe_array_index + 8) & mask;
470       mcqe = (mlx5dv_mini_cqe_t *) (rxq->cqes + mcqe_array_index);
471     }
472
473   if (n_left)
474     {
475       for (int i = 0; i < n_left; i++)
476         byte_cnt[i] = mcqe[i].byte_count;
477     }
478 }
479
480 static_always_inline void
481 cqe_set_owner (mlx5dv_cqe_t * cqe, u32 n_left, u8 owner)
482 {
483   while (n_left >= 8)
484     {
485       cqe[0].opcode_cqefmt_se_owner = owner;
486       cqe[1].opcode_cqefmt_se_owner = owner;
487       cqe[2].opcode_cqefmt_se_owner = owner;
488       cqe[3].opcode_cqefmt_se_owner = owner;
489       cqe[4].opcode_cqefmt_se_owner = owner;
490       cqe[5].opcode_cqefmt_se_owner = owner;
491       cqe[6].opcode_cqefmt_se_owner = owner;
492       cqe[7].opcode_cqefmt_se_owner = owner;
493       n_left -= 8;
494       cqe += 8;
495     }
496   while (n_left)
497     {
498       cqe[0].opcode_cqefmt_se_owner = owner;
499       n_left--;
500       cqe++;
501     }
502 }
503
504 static_always_inline void
505 compressed_cqe_reset_owner (rdma_rxq_t * rxq, u32 n_mini_cqes, u32 cq_ci,
506                             u32 mask, u32 log2_cq_size)
507 {
508   u8 owner;
509   u32 offset, cq_size = 1 << log2_cq_size;
510
511
512   /* first CQE is reset by hardware */
513   cq_ci++;
514   n_mini_cqes--;
515
516   offset = cq_ci & mask;
517   owner = 0xf0 | ((cq_ci >> log2_cq_size) & 1);
518
519   if (offset + n_mini_cqes < cq_size)
520     {
521       cqe_set_owner (rxq->cqes + offset, n_mini_cqes, owner);
522     }
523   else
524     {
525       u32 n = cq_size - offset;
526       cqe_set_owner (rxq->cqes + offset, n, owner);
527       cqe_set_owner (rxq->cqes, n_mini_cqes - n, owner ^ 1);
528     }
529
530 }
531
532 static_always_inline uword
533 rdma_device_poll_cq_mlx5dv (rdma_device_t * rd, rdma_rxq_t * rxq,
534                             u32 * byte_cnt, u16 * cqe_flags)
535 {
536   u32 n_rx_packets = 0;
537   u32 log2_cq_size = rxq->log2_cq_size;
538   u32 mask = pow2_mask (log2_cq_size);
539   u32 cq_ci = rxq->cq_ci;
540
541   if (rxq->n_mini_cqes_left)
542     {
543       /* partially processed mini-cqe array */
544       u32 n_mini_cqes = rxq->n_mini_cqes;
545       u32 n_mini_cqes_left = rxq->n_mini_cqes_left;
546       process_mini_cqes (rxq, n_mini_cqes - n_mini_cqes_left,
547                          n_mini_cqes_left, cq_ci, mask, byte_cnt);
548       compressed_cqe_reset_owner (rxq, n_mini_cqes, cq_ci, mask,
549                                   log2_cq_size);
550       clib_memset_u16 (cqe_flags, rxq->last_cqe_flags, n_mini_cqes_left);
551       n_rx_packets = n_mini_cqes_left;
552       byte_cnt += n_mini_cqes_left;
553       cqe_flags += n_mini_cqes_left;
554       rxq->n_mini_cqes_left = 0;
555       rxq->cq_ci = cq_ci = cq_ci + n_mini_cqes;
556     }
557
558   while (n_rx_packets < VLIB_FRAME_SIZE)
559     {
560       u8 cqe_last_byte, owner;
561       mlx5dv_cqe_t *cqe = rxq->cqes + (cq_ci & mask);
562
563       clib_prefetch_load (rxq->cqes + ((cq_ci + 8) & mask));
564
565       owner = (cq_ci >> log2_cq_size) & 1;
566       cqe_last_byte = cqe->opcode_cqefmt_se_owner;
567
568       if ((cqe_last_byte & 0x1) != owner)
569         break;
570
571       cqe_last_byte &= 0xfc;    /* remove owner and solicited bits */
572
573       if (cqe_last_byte == 0x2c)        /* OPCODE = 0x2 (Responder Send), Format = 0x3 (Compressed CQE) */
574         {
575           u32 n_mini_cqes = clib_net_to_host_u32 (cqe->mini_cqe_num);
576           u32 n_left = VLIB_FRAME_SIZE - n_rx_packets;
577           u16 flags = cqe->flags;
578
579           if (n_left >= n_mini_cqes)
580             {
581               process_mini_cqes (rxq, 0, n_mini_cqes, cq_ci, mask, byte_cnt);
582               clib_memset_u16 (cqe_flags, flags, n_mini_cqes);
583               compressed_cqe_reset_owner (rxq, n_mini_cqes, cq_ci, mask,
584                                           log2_cq_size);
585               n_rx_packets += n_mini_cqes;
586               byte_cnt += n_mini_cqes;
587               cqe_flags += n_mini_cqes;
588               cq_ci += n_mini_cqes;
589             }
590           else
591             {
592               process_mini_cqes (rxq, 0, n_left, cq_ci, mask, byte_cnt);
593               clib_memset_u16 (cqe_flags, flags, n_left);
594               n_rx_packets = VLIB_FRAME_SIZE;
595               rxq->n_mini_cqes = n_mini_cqes;
596               rxq->n_mini_cqes_left = n_mini_cqes - n_left;
597               rxq->last_cqe_flags = flags;
598               goto done;
599             }
600           continue;
601         }
602
603       if (cqe_last_byte == 0x20)        /* OPCODE = 0x2 (Responder Send), Format = 0x0 (no inline data) */
604         {
605           byte_cnt[0] = cqe->byte_cnt;
606           cqe_flags[0] = cqe->flags;
607           n_rx_packets++;
608           cq_ci++;
609           byte_cnt++;
610           cqe_flags++;
611           continue;
612         }
613
614       rd->flags |= RDMA_DEVICE_F_ERROR;
615       break;
616     }
617
618 done:
619   if (n_rx_packets)
620     rxq->cq_db[0] = rxq->cq_ci = cq_ci;
621   return n_rx_packets;
622 }
623
624 static_always_inline int
625 rdma_device_mlx5dv_striding_rq_parse_bc (int n_rx_packets, int *n_rx_segs,
626                                          u32 * bc)
627 {
628 /* Determine if slow path is needed  */
629   int filler = 0;
630   for (int i = 0; i < n_rx_packets; i++)
631     {
632       *n_rx_segs +=
633         (bc[i] & CQE_BC_CONSUMED_STRIDES_MASK) >>
634         CQE_BC_CONSUMED_STRIDES_SHIFT;
635       filler |= ! !(bc[i] & CQE_BC_FILLER_MASK);
636     }
637   return n_rx_packets != *n_rx_segs || filler;
638 }
639
640 static_always_inline int
641 rdma_device_mlx5dv_legacy_rq_slow_path_needed (u32 buf_sz, int n_rx_packets,
642                                                u32 * bc)
643 {
644 #if defined CLIB_HAVE_VEC256
645   u32x8 thresh8 = u32x8_splat (buf_sz);
646   for (int i = 0; i < n_rx_packets; i += 8)
647     if (!u32x8_is_all_zero (*(u32x8 *) (bc + i) > thresh8))
648       return 1;
649 #elif defined CLIB_HAVE_VEC128
650   u32x4 thresh4 = u32x4_splat (buf_sz);
651   for (int i = 0; i < n_rx_packets; i += 4)
652     if (!u32x4_is_all_zero (*(u32x4 *) (bc + i) > thresh4))
653       return 1;
654 #else
655   while (n_rx_packets)
656     {
657       if (*bc > buf_sz)
658         return 1;
659       bc++;
660       n_rx_packets--;
661     }
662 #endif
663
664   return 0;
665 }
666
667 static_always_inline int
668 rdma_device_mlx5dv_l3_validate_and_swap_bc (rdma_per_thread_data_t
669                                             * ptd, int n_rx_packets, u32 * bc)
670 {
671   u16 mask = CQE_FLAG_L3_HDR_TYPE_MASK | CQE_FLAG_L3_OK;
672   u16 match =
673     CQE_FLAG_L3_HDR_TYPE_IP4 << CQE_FLAG_L3_HDR_TYPE_SHIFT | CQE_FLAG_L3_OK;
674
675   /* convert mask/match to big endian for subsequant comparison */
676   mask = clib_host_to_net_u16 (mask);
677   match = clib_host_to_net_u16 (match);
678
679   /* verify that all ip4 packets have l3_ok flag set and convert packet
680      length from network to host byte order */
681   int skip_ip4_cksum = 1;
682   int n_left = n_rx_packets;
683   u16 *cqe_flags = ptd->cqe_flags;
684
685 #if defined CLIB_HAVE_VEC256
686   if (n_left >= 16)
687     {
688       u16x16 mask16 = u16x16_splat (mask);
689       u16x16 match16 = u16x16_splat (match);
690       u16x16 r16 = {};
691
692       while (n_left >= 16)
693         {
694           r16 |= (*(u16x16 *) cqe_flags & mask16) != match16;
695
696           *(u32x8 *) bc = u32x8_byte_swap (*(u32x8 *) bc);
697           *(u32x8 *) (bc + 8) = u32x8_byte_swap (*(u32x8 *) (bc + 8));
698
699           cqe_flags += 16;
700           bc += 16;
701           n_left -= 16;
702         }
703
704       if (!u16x16_is_all_zero (r16))
705         skip_ip4_cksum = 0;
706     }
707 #elif defined CLIB_HAVE_VEC128
708   if (n_left >= 8)
709     {
710       u16x8 mask8 = u16x8_splat (mask);
711       u16x8 match8 = u16x8_splat (match);
712       u16x8 r8 = {};
713
714       while (n_left >= 8)
715         {
716           r8 |= (*(u16x8 *) cqe_flags & mask8) != match8;
717
718           *(u32x4 *) bc = u32x4_byte_swap (*(u32x4 *) bc);
719           *(u32x4 *) (bc + 4) = u32x4_byte_swap (*(u32x4 *) (bc + 4));
720
721           cqe_flags += 8;
722           bc += 8;
723           n_left -= 8;
724         }
725
726       if (!u16x8_is_all_zero (r8))
727         skip_ip4_cksum = 0;
728     }
729 #endif
730
731   while (n_left >= 1)
732     {
733       if ((cqe_flags[0] & mask) != match)
734         skip_ip4_cksum = 0;
735
736       bc[0] = clib_net_to_host_u32 (bc[0]);
737
738       cqe_flags += 1;
739       bc += 1;
740       n_left -= 1;
741     }
742
743   return skip_ip4_cksum;
744 }
745
746 static_always_inline u32
747 rdma_device_mlx5dv_fast_input (vlib_main_t * vm, rdma_rxq_t * rxq,
748                                vlib_buffer_t ** bufs,
749                                u32 qs_mask, vlib_buffer_t * bt,
750                                u32 * to_next, u32 n_rx_segs, u32 * bc,
751                                u32 bc_mask)
752 {
753   vlib_buffer_t **b = bufs;
754   u32 n_left = n_rx_segs;
755   u32 n_rx_bytes = 0;
756   vlib_buffer_copy_indices_from_ring (to_next, rxq->bufs,
757                                       rxq->head & qs_mask, rxq->size,
758                                       n_rx_segs);
759   rxq->head += n_rx_segs;
760   vlib_get_buffers (vm, to_next, bufs, n_rx_segs);
761   while (n_left >= 8)
762     {
763       clib_prefetch_store (b[4]);
764       vlib_buffer_copy_template (b[0], bt);
765       n_rx_bytes += b[0]->current_length = bc[0] & bc_mask;
766       clib_prefetch_store (b[5]);
767       vlib_buffer_copy_template (b[1], bt);
768       n_rx_bytes += b[1]->current_length = bc[1] & bc_mask;
769       clib_prefetch_store (b[6]);
770       vlib_buffer_copy_template (b[2], bt);
771       n_rx_bytes += b[2]->current_length = bc[2] & bc_mask;
772       clib_prefetch_store (b[7]);
773       vlib_buffer_copy_template (b[3], bt);
774       n_rx_bytes += b[3]->current_length = bc[3] & bc_mask;
775       /* next */
776       bc += 4;
777       b += 4;
778       n_left -= 4;
779     }
780   while (n_left)
781     {
782       vlib_buffer_copy_template (b[0], bt);
783       n_rx_bytes += b[0]->current_length = bc[0] & bc_mask;
784       /* next */
785       bc++;
786       b++;
787       n_left--;
788     }
789   return n_rx_bytes;
790 }
791
792 static_always_inline void
793 rdma_device_mlx5dv_legacy_rq_fix_chains (vlib_main_t * vm, rdma_rxq_t * rxq,
794                                          vlib_buffer_t ** bufs, u32 qs_mask,
795                                          u32 n)
796 {
797   u32 buf_sz = rxq->buf_sz;
798   uword slot = (rxq->head - n) & qs_mask;
799   u32 *second = &rxq->second_bufs[slot];
800   u32 n_wrap_around = (slot + n) & (qs_mask + 1) ? (slot + n) & qs_mask : 0;
801   u8 *n_used_per_chain = &rxq->n_used_per_chain[slot];
802   n -= n_wrap_around;
803 wrap_around:
804   while (n > 0)
805     {
806       u16 total_length = bufs[0]->current_length;
807       if (total_length > buf_sz)
808         {
809           vlib_buffer_t *current_buf = bufs[0];
810           u8 current_chain_sz = 0;
811           current_buf->current_length = buf_sz;
812           total_length -= buf_sz;
813           current_buf->total_length_not_including_first_buffer = total_length;
814           current_buf->flags |= VLIB_BUFFER_NEXT_PRESENT;
815           current_buf->next_buffer = second[0];
816           do
817             {
818               current_buf = vlib_get_buffer (vm, current_buf->next_buffer);
819               current_buf->current_length = clib_min (buf_sz, total_length);
820               total_length -= current_buf->current_length;
821               current_chain_sz++;
822             }
823           while (total_length > 0);
824           current_buf->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
825           second[0] = current_buf->next_buffer;
826           current_buf->next_buffer = 0;
827           rxq->n_total_additional_segs += current_chain_sz;
828           n_used_per_chain[0] = current_chain_sz;
829         }
830       bufs++;
831       second++;
832       n_used_per_chain++;
833       n--;
834     }
835   if (PREDICT_FALSE (n_wrap_around))
836     {
837       n = n_wrap_around;
838       n_wrap_around = 0;
839       second = rxq->second_bufs;
840       n_used_per_chain = rxq->n_used_per_chain;
841       goto wrap_around;
842     }
843 }
844
845 static_always_inline u32
846 rdma_device_mlx5dv_striding_rq_input (vlib_main_t * vm,
847                                       rdma_per_thread_data_t * ptd,
848                                       rdma_rxq_t * rxq,
849                                       vlib_buffer_t * bt, u32 * to_next,
850                                       int n_rx_segs, int *n_rx_packets,
851                                       u32 * bc, int slow_path_needed)
852 {
853   u32 mask = rxq->size - 1;
854   u32 n_rx_bytes = 0;
855   if (PREDICT_TRUE (!slow_path_needed))
856     {
857       vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
858       n_rx_bytes +=
859         rdma_device_mlx5dv_fast_input (vm, rxq, bufs, mask, bt, to_next,
860                                        n_rx_segs, bc, CQE_BC_BYTE_COUNT_MASK);
861     }
862   else                          /* Slow path with multiseg */
863     {
864       vlib_buffer_t *pkt_head;  /*Current head buffer */
865       vlib_buffer_t *pkt_prev;  /* Buffer processed at the previous iteration */
866       u32 pkt_head_idx;
867       vlib_buffer_t **pkt;
868       uword n_segs_remaining = 0;       /*Remaining strides in current buffer */
869       u32 n_bytes_remaining = 0;        /*Remaining bytes in current buffer */
870       u32 *next_in_frame = to_next;
871       u32 *next_to_free = ptd->to_free_buffers;
872       bt->current_length = vlib_buffer_get_default_data_size (vm);
873       do
874         {
875           vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
876           u32 n_left = clib_min (n_rx_segs, VLIB_FRAME_SIZE);
877           n_rx_segs -= n_left;
878           vlib_buffer_copy_indices_from_ring (ptd->current_segs,
879                                               rxq->bufs, rxq->head & mask,
880                                               rxq->size, n_left);
881           rxq->head += n_left;
882           vlib_get_buffers (vm, ptd->current_segs, bufs, n_left);
883           pkt = bufs;
884           while (n_left > 0)
885             {
886               /* Initialize the current buffer as full size */
887               vlib_buffer_copy_template (pkt[0], bt);
888               if (!n_segs_remaining)    /* No pending chain */
889                 {
890                   n_segs_remaining =
891                     (bc[0] & CQE_BC_CONSUMED_STRIDES_MASK) >>
892                     CQE_BC_CONSUMED_STRIDES_SHIFT;
893                   pkt_head = pkt[0];
894                   pkt_head_idx = ptd->current_segs[pkt - bufs];
895                   n_bytes_remaining = bc[0] & CQE_BC_BYTE_COUNT_MASK;
896                   pkt_head->total_length_not_including_first_buffer =
897                     n_segs_remaining >
898                     1 ? n_bytes_remaining - pkt[0]->current_length : 0;
899                 }
900               else              /* Perform chaining if it's a continuation buffer */
901                 {
902                   pkt_prev->next_buffer = ptd->current_segs[pkt - bufs];
903                   pkt_prev->flags |= VLIB_BUFFER_NEXT_PRESENT;
904                   pkt[0]->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
905                 }
906               if (n_segs_remaining == 1)        /* Last buffer of the chain */
907                 {
908                   pkt[0]->current_length = n_bytes_remaining;
909                   if (bc[0] & CQE_BC_FILLER_MASK)
910                     {
911                       (next_to_free++)[0] = pkt_head_idx;
912                       (*n_rx_packets)--;
913                     }
914
915                   else
916                     {
917                       (next_in_frame++)[0] = pkt_head_idx;
918                       n_rx_bytes +=
919                         pkt_head->current_length +
920                         pkt_head->total_length_not_including_first_buffer;
921                     }
922                   /*Go to next CQE */
923                   bc++;
924                 }
925               else
926                 {
927                   n_bytes_remaining -= pkt[0]->current_length;
928                   pkt_prev = pkt[0];
929                 }
930               n_segs_remaining--;
931               n_left--;
932               pkt++;
933             }
934
935         }
936       while (n_rx_segs > 0);
937       vlib_buffer_free (vm, ptd->to_free_buffers,
938                         next_to_free - ptd->to_free_buffers);
939     }
940   return n_rx_bytes;
941 }
942
943 static_always_inline uword
944 rdma_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
945                           vlib_frame_t * frame, rdma_device_t * rd,
946                           u16 qid, const int use_mlx5dv)
947 {
948   rdma_main_t *rm = &rdma_main;
949   vnet_main_t *vnm = vnet_get_main ();
950   rdma_per_thread_data_t *ptd = vec_elt_at_index (rm->per_thread_data,
951                                                   vm->thread_index);
952   rdma_rxq_t *rxq = vec_elt_at_index (rd->rxqs, qid);
953   struct ibv_wc wc[VLIB_FRAME_SIZE];
954   u32 __clib_aligned (32) byte_cnts[VLIB_FRAME_SIZE];
955   vlib_buffer_t bt;
956   u32 next_index, *to_next, n_left_to_next, n_rx_bytes = 0;
957   int n_rx_packets, skip_ip4_cksum = 0;
958   u32 mask = rxq->size - 1;
959   const int is_striding = ! !(rd->flags & RDMA_DEVICE_F_STRIDING_RQ);
960
961   if (use_mlx5dv)
962     n_rx_packets = rdma_device_poll_cq_mlx5dv (rd, rxq, byte_cnts,
963                                                ptd->cqe_flags);
964   else
965     n_rx_packets = ibv_poll_cq (rxq->cq, VLIB_FRAME_SIZE, wc);
966
967   /* init buffer template */
968   vlib_buffer_copy_template (&bt, &ptd->buffer_template);
969   vnet_buffer (&bt)->sw_if_index[VLIB_RX] = rd->sw_if_index;
970   bt.buffer_pool_index = rd->pool;
971
972   if (PREDICT_FALSE (n_rx_packets <= 0))
973     goto refill;
974
975   /* update buffer template for input feature arcs if any */
976   next_index = rd->per_interface_next_index;
977   if (PREDICT_FALSE (vnet_device_input_have_features (rd->sw_if_index)))
978     vnet_feature_start_device_input (rd->sw_if_index, &next_index, &bt);
979
980   vlib_get_new_next_frame (vm, node, next_index, to_next, n_left_to_next);
981
982   if (use_mlx5dv)
983     {
984       u32 *bc = byte_cnts;
985       int slow_path_needed;
986       skip_ip4_cksum =
987         rdma_device_mlx5dv_l3_validate_and_swap_bc (ptd, n_rx_packets, bc);
988       if (is_striding)
989         {
990           int n_rx_segs = 0;
991           slow_path_needed =
992             rdma_device_mlx5dv_striding_rq_parse_bc (n_rx_packets,
993                                                      &n_rx_segs, bc);
994           n_rx_bytes =
995             rdma_device_mlx5dv_striding_rq_input (vm, ptd, rxq, &bt,
996                                                   to_next, n_rx_segs,
997                                                   &n_rx_packets, bc,
998                                                   slow_path_needed);
999         }
1000       else
1001         {
1002           vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
1003           slow_path_needed =
1004             rdma_device_mlx5dv_legacy_rq_slow_path_needed (rxq->buf_sz,
1005                                                            n_rx_packets, bc);
1006           n_rx_bytes = rdma_device_mlx5dv_fast_input (
1007             vm, rxq, bufs, mask, &bt, to_next, n_rx_packets, bc, ~0);
1008
1009           /* If there are chained buffers, some of the head buffers have a current length
1010              higher than buf_sz: it needs to be fixed */
1011           if (PREDICT_FALSE (slow_path_needed))
1012             rdma_device_mlx5dv_legacy_rq_fix_chains (vm, rxq, bufs, mask,
1013                                                      n_rx_packets);
1014         }
1015     }
1016   else
1017     {
1018       vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
1019       vlib_buffer_copy_indices_from_ring (to_next, rxq->bufs,
1020                                           rxq->head & mask,
1021                                           rxq->size, n_rx_packets);
1022       vlib_get_buffers (vm, to_next, bufs, n_rx_packets);
1023       rxq->head += n_rx_packets;
1024       n_rx_bytes =
1025         rdma_device_input_bufs (vm, rd, bufs, wc, n_rx_packets, &bt);
1026
1027     }
1028
1029   rdma_device_input_ethernet (vm, node, rd, next_index, skip_ip4_cksum);
1030   vlib_put_next_frame (vm, node, next_index, n_left_to_next - n_rx_packets);
1031   rdma_device_input_trace (vm, node, rd, n_rx_packets, to_next,
1032                            next_index, ptd->cqe_flags, use_mlx5dv);
1033   /* reset flags to zero for the next run */
1034   if (use_mlx5dv)
1035     clib_memset_u16 (ptd->cqe_flags, 0, VLIB_FRAME_SIZE);
1036   vlib_increment_combined_counter (vnm->interface_main.
1037                                    combined_sw_if_counters +
1038                                    VNET_INTERFACE_COUNTER_RX,
1039                                    vm->thread_index, rd->hw_if_index,
1040                                    n_rx_packets, n_rx_bytes);
1041 refill:
1042   rdma_device_input_refill (vm, rd, rxq, &bt, use_mlx5dv, is_striding);
1043   return n_rx_packets;
1044 }
1045
1046 VLIB_NODE_FN (rdma_input_node) (vlib_main_t * vm,
1047                                 vlib_node_runtime_t * node,
1048                                 vlib_frame_t * frame)
1049 {
1050   u32 n_rx = 0;
1051   rdma_main_t *rm = &rdma_main;
1052   vnet_hw_if_rxq_poll_vector_t *pv;
1053   pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
1054   for (int i = 0; i < vec_len (pv); i++)
1055     {
1056       rdma_device_t *rd;
1057       rd = vec_elt_at_index (rm->devices, pv[i].dev_instance);
1058       if (PREDICT_TRUE (rd->flags & RDMA_DEVICE_F_ADMIN_UP) == 0)
1059         continue;
1060
1061       if (PREDICT_FALSE (rd->flags & RDMA_DEVICE_F_ERROR))
1062         continue;
1063
1064       if (PREDICT_TRUE (rd->flags & RDMA_DEVICE_F_MLX5DV))
1065         n_rx +=
1066           rdma_device_input_inline (vm, node, frame, rd, pv[i].queue_id, 1);
1067       else
1068         n_rx +=
1069           rdma_device_input_inline (vm, node, frame, rd, pv[i].queue_id, 0);
1070     }
1071   return n_rx;
1072 }
1073
1074 VLIB_REGISTER_NODE (rdma_input_node) = {
1075   .name = "rdma-input",
1076   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
1077   .sibling_of = "device-input",
1078   .format_trace = format_rdma_input_trace,
1079   .type = VLIB_NODE_TYPE_INPUT,
1080   .state = VLIB_NODE_STATE_DISABLED,
1081   .n_errors = RDMA_INPUT_N_ERROR,
1082   .error_strings = rdma_input_error_strings,
1083 };
1084
1085
1086
1087 /*
1088  * fd.io coding-style-patch-verification: ON
1089  *
1090  * Local Variables:
1091  * eval: (c-set-style "gnu")
1092  * End:
1093  */