551056affabfefe8a253a3ccde6bb8e7a126c683
[samplevnf.git] / VNFs / DPPD-PROX / tx_pkt.c
1 /*
2 // Copyright (c) 2010-2020 Intel Corporation
3 //
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 #include <rte_ethdev.h>
18 #include <rte_version.h>
19
20 #include "rx_pkt.h"
21 #include "tx_pkt.h"
22 #include "task_base.h"
23 #include "stats.h"
24 #include "prefetch.h"
25 #include "prox_assert.h"
26 #include "log.h"
27 #include "mbuf_utils.h"
28 #include "handle_master.h"
29 #include "defines.h"
30
31 static void buf_pkt_single(struct task_base *tbase, struct rte_mbuf *mbuf, const uint8_t out)
32 {
33         const uint16_t prod = tbase->ws_mbuf->idx[out].prod++;
34         tbase->ws_mbuf->mbuf[out][prod & WS_MBUF_MASK] = mbuf;
35 }
36
37 static inline void buf_pkt_all(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
38 {
39         for (uint16_t j = 0; j < n_pkts; ++j) {
40                 if (unlikely(out[j] >= OUT_HANDLED)) {
41                         rte_pktmbuf_free(mbufs[j]);
42                         if (out[j] == OUT_HANDLED)
43                                 TASK_STATS_ADD_DROP_HANDLED(&tbase->aux->stats, 1);
44                         else
45                                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
46                 }
47                 else {
48                         buf_pkt_single(tbase, mbufs[j], out[j]);
49                 }
50         }
51 }
52 #define MAX_PMD_TX 32
53
54 void store_packet(struct task_base *tbase, struct rte_mbuf *mbuf)
55 {
56         // If buffer is full, drop the first mbuf
57         if (tbase->aux->mbuf)
58                 tx_drop(tbase->aux->mbuf);
59         tbase->aux->mbuf = mbuf;
60 }
61
62 int tx_pkt_ndp(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
63 {
64         struct ipv6_addr ip_dst;
65         int first = 0, ret, ok = 0, rc;
66         const struct port_queue *port_queue = &tbase->tx_params_hw.tx_port_queue[0];
67         struct rte_mbuf *mbuf = NULL;       // used when one need to send both an ARP and a mbuf
68         uint16_t vlan;
69         uint64_t tsc = rte_rdtsc();
70
71         for (int j = 0; j < n_pkts; j++) {
72                 if ((out) && (out[j] >= OUT_HANDLED))
73                         continue;
74                 if (unlikely((rc = write_ip6_dst_mac(tbase, mbufs[j], &ip_dst, &vlan, tsc)) != SEND_MBUF)) {
75                         if (j - first) {
76                                 ret = tbase->aux->tx_pkt_l2(tbase, mbufs + first, j - first, out);
77                                 ok += ret;
78                         }
79                         first = j + 1;
80                         switch(rc) {
81                         case SEND_ARP_ND:
82                                 // Original mbuf (packet) is stored to be sent later -> need to allocate new mbuf
83                                 ret = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)&mbuf);
84                                 if (likely(ret == 0))   {
85                                         store_packet(tbase, mbufs[j]);
86                                         mbuf->port = tbase->l3.reachable_port_id;
87                                         tx_ring_cti6(tbase, tbase->l3.ctrl_plane_ring, IP6_REQ_MAC_TO_MASTER, mbuf, tbase->l3.core_id, tbase->l3.task_id, &ip_dst, vlan);
88                                 } else {
89                                         plog_err("Failed to get a mbuf from arp/nd mempool\n");
90                                         tx_drop(mbufs[j]);
91                                         TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
92                                 }
93                                 break;
94                         case SEND_MBUF_AND_ARP_ND:
95                                 // We send the mbuf and an ND - we need to allocate another mbuf for ND
96                                 ret = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)&mbuf);
97                                 if (likely(ret == 0))   {
98                                         mbuf->port = tbase->l3.reachable_port_id;
99                                         tx_ring_cti6(tbase, tbase->l3.ctrl_plane_ring, IP6_REQ_MAC_TO_MASTER, mbuf, tbase->l3.core_id, tbase->l3.task_id, &ip_dst, vlan);
100                                 } else {
101                                         plog_err("Failed to get a mbuf from arp/nd mempool\n");
102                                         // We still send the initial mbuf
103                                 }
104                                 ret = tbase->aux->tx_pkt_l2(tbase, mbufs + j, 1, out);
105                                 break;
106                         case DROP_MBUF:
107                                 tx_drop(mbufs[j]);
108                                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
109                                 break;
110                         }
111                 }
112         }
113         if (n_pkts - first) {
114                 ret = tbase->aux->tx_pkt_l2(tbase, mbufs + first, n_pkts - first, out);
115                 ok += ret;
116         }
117         return ok;
118 }
119 int tx_pkt_l3(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
120 {
121         uint32_t ip_dst;
122         uint16_t vlan;
123         int first = 0, ret, ok = 0, rc;
124         const struct port_queue *port_queue = &tbase->tx_params_hw.tx_port_queue[0];
125         struct rte_mbuf *arp_mbuf = NULL;       // used when one need to send both an ARP and a mbuf
126         uint64_t *time;
127         uint64_t tsc = rte_rdtsc();
128
129         for (int j = 0; j < n_pkts; j++) {
130                 if ((out) && (out[j] >= OUT_HANDLED))
131                         continue;
132                 if (unlikely((rc = write_dst_mac(tbase, mbufs[j], &ip_dst, &vlan, &time, tsc)) != SEND_MBUF)) {
133                         if (j - first) {
134                                 ret = tbase->aux->tx_pkt_l2(tbase, mbufs + first, j - first, out);
135                                 ok += ret;
136                         }
137                         first = j + 1;
138                         switch(rc) {
139                         case SEND_ARP_ND:
140                                 // We re-use the mbuf - no need to create a arp_mbuf and delete the existing mbuf
141                                 mbufs[j]->port = tbase->l3.reachable_port_id;
142                                 if (tx_ring_cti(tbase, tbase->l3.ctrl_plane_ring, IP4_REQ_MAC_TO_MASTER, mbufs[j], tbase->l3.core_id, tbase->l3.task_id, ip_dst, vlan) == 0)
143                                         update_arp_ndp_retransmit_timeout(&tbase->l3, time, 1000);
144                                 else
145                                         update_arp_ndp_retransmit_timeout(&tbase->l3, time, 100);
146                                 break;
147                         case SEND_MBUF_AND_ARP_ND:
148                                 // We send the mbuf and an ARP - we need to allocate another mbuf for ARP
149                                 ret = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)&arp_mbuf);
150                                 if (likely(ret == 0))   {
151                                         arp_mbuf->port = tbase->l3.reachable_port_id;
152                                         if (tx_ring_cti(tbase, tbase->l3.ctrl_plane_ring, IP4_REQ_MAC_TO_MASTER, arp_mbuf, tbase->l3.core_id, tbase->l3.task_id, ip_dst, vlan) == 0)
153                                                 update_arp_ndp_retransmit_timeout(&tbase->l3, time, 1000);
154                                         else
155                                                 update_arp_ndp_retransmit_timeout(&tbase->l3, time, 100);
156                                 } else {
157                                         plog_err("Failed to get a mbuf from arp mempool\n");
158                                         // We still send the initial mbuf
159                                 }
160                                 ret = tbase->aux->tx_pkt_l2(tbase, mbufs + j, 1, out);
161                                 break;
162                         case DROP_MBUF:
163                                 tx_drop(mbufs[j]);
164                                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
165                                 break;
166                         }
167                 }
168         }
169         if (n_pkts - first) {
170                 ret = tbase->aux->tx_pkt_l2(tbase, mbufs + first, n_pkts - first, out);
171                 ok += ret;
172         }
173         return ok;
174 }
175
176 /* The following help functions also report stats. Therefore we need
177    to pass the task_base struct. */
178 static inline int txhw_drop(const struct port_queue *port_queue, struct rte_mbuf **mbufs, uint16_t n_pkts, struct task_base *tbase)
179 {
180         uint16_t ntx;
181         int ret;
182
183         /* TX vector mode can't transmit more than 32 packets */
184         if (n_pkts > MAX_PMD_TX) {
185                 ntx = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, MAX_PMD_TX);
186                 ntx += rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs + ntx, n_pkts - ntx);
187         } else {
188                 ntx = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, n_pkts);
189         }
190         TASK_STATS_ADD_TX(&tbase->aux->stats, ntx);
191
192         ret =  n_pkts - ntx;
193         if (ntx < n_pkts) {
194                 plog_dbg("Failed to send %d packets from %p\n", ret, mbufs[0]);
195                 TASK_STATS_ADD_DROP_TX_FAIL(&tbase->aux->stats, n_pkts - ntx);
196                 if (tbase->tx_pkt == tx_pkt_bw) {
197                         uint32_t drop_bytes = 0;
198                         do {
199                                 drop_bytes += mbuf_wire_size(mbufs[ntx]);
200                                 rte_pktmbuf_free(mbufs[ntx++]);
201                         } while (ntx < n_pkts);
202                         TASK_STATS_ADD_DROP_BYTES(&tbase->aux->stats, drop_bytes);
203                 }
204                 else {
205                         do {
206                                 rte_pktmbuf_free(mbufs[ntx++]);
207                         } while (ntx < n_pkts);
208                 }
209         }
210         return ret;
211 }
212
213 static inline int txhw_no_drop(const struct port_queue *port_queue, struct rte_mbuf **mbufs, uint16_t n_pkts, struct task_base *tbase)
214 {
215         uint16_t ret;
216         uint16_t n = n_pkts;
217
218         TASK_STATS_ADD_TX(&tbase->aux->stats, n_pkts);
219         do {
220                 ret = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, n_pkts);
221                 mbufs += ret;
222                 n_pkts -= ret;
223         }
224         while (n_pkts);
225         return (n != ret);
226 }
227
228 static inline int ring_enq_drop(struct rte_ring *ring, struct rte_mbuf *const *mbufs, uint16_t n_pkts, __attribute__((unused)) struct task_base *tbase)
229 {
230         int ret = 0;
231         /* return 0 on succes, -ENOBUFS on failure */
232         // Rings can be single or multiproducer (ctrl rings are multi producer)
233 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
234         if (unlikely(rte_ring_enqueue_bulk(ring, (void *const *)mbufs, n_pkts))) {
235 #else
236         if (unlikely(rte_ring_enqueue_bulk(ring, (void *const *)mbufs, n_pkts, NULL) == 0)) {
237 #endif
238                 ret = n_pkts;
239                 if (tbase->tx_pkt == tx_pkt_bw) {
240                         uint32_t drop_bytes = 0;
241                         for (uint16_t i = 0; i < n_pkts; ++i) {
242                                 drop_bytes += mbuf_wire_size(mbufs[i]);
243                                 rte_pktmbuf_free(mbufs[i]);
244                         }
245                         TASK_STATS_ADD_DROP_BYTES(&tbase->aux->stats, drop_bytes);
246                         TASK_STATS_ADD_DROP_TX_FAIL(&tbase->aux->stats, n_pkts);
247                 }
248                 else {
249                         for (uint16_t i = 0; i < n_pkts; ++i)
250                                 rte_pktmbuf_free(mbufs[i]);
251                         TASK_STATS_ADD_DROP_TX_FAIL(&tbase->aux->stats, n_pkts);
252                 }
253         }
254         else {
255                 TASK_STATS_ADD_TX(&tbase->aux->stats, n_pkts);
256         }
257         return ret;
258 }
259
260 static inline int ring_enq_no_drop(struct rte_ring *ring, struct rte_mbuf *const *mbufs, uint16_t n_pkts, __attribute__((unused)) struct task_base *tbase)
261 {
262         int i = 0;
263 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
264         while (rte_ring_enqueue_bulk(ring, (void *const *)mbufs, n_pkts)) {
265 #else
266         while (rte_ring_enqueue_bulk(ring, (void *const *)mbufs, n_pkts, NULL) == 0) {
267 #endif
268                 i++;
269         };
270         TASK_STATS_ADD_TX(&tbase->aux->stats, n_pkts);
271         return (i != 0);
272 }
273
274 void flush_queues_hw(struct task_base *tbase)
275 {
276         uint16_t prod, cons;
277
278         for (uint8_t i = 0; i < tbase->tx_params_hw.nb_txports; ++i) {
279                 prod = tbase->ws_mbuf->idx[i].prod;
280                 cons = tbase->ws_mbuf->idx[i].cons;
281
282                 if (prod != cons) {
283                         tbase->ws_mbuf->idx[i].prod = 0;
284                         tbase->ws_mbuf->idx[i].cons = 0;
285                         txhw_drop(&tbase->tx_params_hw.tx_port_queue[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), prod - cons, tbase);
286                 }
287         }
288
289         tbase->flags &= ~FLAG_TX_FLUSH;
290 }
291
292 void flush_queues_sw(struct task_base *tbase)
293 {
294         uint16_t prod, cons;
295
296         for (uint8_t i = 0; i < tbase->tx_params_sw.nb_txrings; ++i) {
297                 prod = tbase->ws_mbuf->idx[i].prod;
298                 cons = tbase->ws_mbuf->idx[i].cons;
299
300                 if (prod != cons) {
301                         tbase->ws_mbuf->idx[i].prod = 0;
302                         tbase->ws_mbuf->idx[i].cons = 0;
303                         ring_enq_drop(tbase->tx_params_sw.tx_rings[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), prod - cons, tbase);
304                 }
305         }
306         tbase->flags &= ~FLAG_TX_FLUSH;
307 }
308
309 void flush_queues_no_drop_hw(struct task_base *tbase)
310 {
311         uint16_t prod, cons;
312
313         for (uint8_t i = 0; i < tbase->tx_params_hw.nb_txports; ++i) {
314                 prod = tbase->ws_mbuf->idx[i].prod;
315                 cons = tbase->ws_mbuf->idx[i].cons;
316
317                 if (prod != cons) {
318                         tbase->ws_mbuf->idx[i].prod = 0;
319                         tbase->ws_mbuf->idx[i].cons = 0;
320                         txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), prod - cons, tbase);
321                 }
322         }
323
324         tbase->flags &= ~FLAG_TX_FLUSH;
325 }
326
327 void flush_queues_no_drop_sw(struct task_base *tbase)
328 {
329         uint16_t prod, cons;
330
331         for (uint8_t i = 0; i < tbase->tx_params_sw.nb_txrings; ++i) {
332                 prod = tbase->ws_mbuf->idx[i].prod;
333                 cons = tbase->ws_mbuf->idx[i].cons;
334
335                 if (prod != cons) {
336                         tbase->ws_mbuf->idx[i].prod = 0;
337                         tbase->ws_mbuf->idx[i].cons = 0;
338                         ring_enq_no_drop(tbase->tx_params_sw.tx_rings[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), prod - cons, tbase);
339                 }
340         }
341         tbase->flags &= ~FLAG_TX_FLUSH;
342 }
343
344 /* "try" functions try to send packets to sw/hw w/o failing or blocking;
345    They return if ring/queue is full and are used by aggregators.
346    "try" functions do not have drop/no drop flavors
347    They are only implemented in never_discard mode (as by default they
348    use only one outgoing ring. */
349 uint16_t tx_try_self(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
350 {
351         if (n_pkts < 64) {
352                 tx_pkt_never_discard_self(tbase, mbufs, n_pkts, NULL);
353                 return n_pkts;
354         } else {
355                 tx_pkt_never_discard_self(tbase, mbufs, 64, NULL);
356                 return 64;
357         }
358 }
359
360 uint16_t tx_try_sw1(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
361 {
362         const int bulk_size = 64;
363         uint16_t ret = bulk_size, sent = 0, n_bulks;
364         n_bulks = n_pkts >> __builtin_ctz(bulk_size);
365
366         for (int i = 0; i < n_bulks; i++) {
367 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
368                 ret = rte_ring_enqueue_burst(tbase->tx_params_sw.tx_rings[0], (void *const *)mbufs, bulk_size);
369 #else
370                 ret = rte_ring_enqueue_burst(tbase->tx_params_sw.tx_rings[0], (void *const *)mbufs, bulk_size, NULL);
371 #endif
372                 mbufs += ret;
373                 sent += ret;
374                 if (ret != bulk_size)
375                         break;
376         }
377         if ((ret == bulk_size) && (n_pkts & (bulk_size - 1))) {
378 #if RTE_VERSION < RTE_VERSION_NUM(17,5,0,1)
379                 ret = rte_ring_enqueue_burst(tbase->tx_params_sw.tx_rings[0], (void *const *)mbufs, (n_pkts & (bulk_size - 1)));
380 #else
381                 ret = rte_ring_enqueue_burst(tbase->tx_params_sw.tx_rings[0], (void *const *)mbufs, (n_pkts & (bulk_size - 1)), NULL);
382 #endif
383                 mbufs += ret;
384                 sent += ret;
385         }
386         TASK_STATS_ADD_TX(&tbase->aux->stats, sent);
387         return sent;
388 }
389
390 uint16_t tx_try_hw1(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
391 {
392         const int bulk_size = 64;
393         uint16_t ret = bulk_size, n_bulks, sent = 0;
394         n_bulks = n_pkts >>  __builtin_ctz(bulk_size);
395
396         const struct port_queue *port_queue = &tbase->tx_params_hw.tx_port_queue[0];
397         for (int i = 0; i < n_bulks; i++) {
398                 ret = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, bulk_size);
399                 mbufs += ret;
400                 sent += ret;
401                 if (ret != bulk_size)
402                         break;
403         }
404         if ((ret == bulk_size) && (n_pkts & (bulk_size - 1))) {
405                 ret = rte_eth_tx_burst(port_queue->port, port_queue->queue, mbufs, (n_pkts & (bulk_size - 1)));
406                 mbufs += ret;
407                 sent += ret;
408         }
409         TASK_STATS_ADD_TX(&tbase->aux->stats, sent);
410         return sent;
411 }
412
413 int tx_pkt_no_drop_never_discard_hw1_lat_opt(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
414 {
415         return txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_pkts, tbase);
416 }
417
418 int tx_pkt_no_drop_never_discard_hw1_thrpt_opt(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
419 {
420         static uint8_t fake_out[MAX_PKT_BURST] = {0};
421         int ret = 0;
422         if (n_pkts == MAX_PKT_BURST) {
423                 // First xmit what was queued
424                 uint16_t prod, cons;
425
426                 prod = tbase->ws_mbuf->idx[0].prod;
427                 cons = tbase->ws_mbuf->idx[0].cons;
428
429                 if ((uint16_t)(prod - cons)){
430                         tbase->flags &= ~FLAG_TX_FLUSH;
431                         tbase->ws_mbuf->idx[0].prod = 0;
432                         tbase->ws_mbuf->idx[0].cons = 0;
433                         ret+= txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[0], tbase->ws_mbuf->mbuf[0] + (cons & WS_MBUF_MASK), (uint16_t)(prod - cons), tbase);
434                 }
435                 ret+= txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_pkts, tbase);
436         } else {
437                 ret+= tx_pkt_no_drop_hw(tbase, mbufs, n_pkts, fake_out);
438         }
439         return ret;
440 }
441
442 int tx_pkt_never_discard_hw1_lat_opt(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
443 {
444         return txhw_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_pkts, tbase);
445 }
446
447 int tx_pkt_never_discard_hw1_thrpt_opt(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
448 {
449         static uint8_t fake_out[MAX_PKT_BURST] = {0};
450         int ret = 0;
451         if (n_pkts == MAX_PKT_BURST) {
452                 // First xmit what was queued
453                 uint16_t prod, cons;
454
455                 prod = tbase->ws_mbuf->idx[0].prod;
456                 cons = tbase->ws_mbuf->idx[0].cons;
457
458                 if ((uint16_t)(prod - cons)){
459                         tbase->flags &= ~FLAG_TX_FLUSH;
460                         tbase->ws_mbuf->idx[0].prod = 0;
461                         tbase->ws_mbuf->idx[0].cons = 0;
462                         ret+= txhw_drop(&tbase->tx_params_hw.tx_port_queue[0], tbase->ws_mbuf->mbuf[0] + (cons & WS_MBUF_MASK), (uint16_t)(prod - cons), tbase);
463                 }
464                 ret+= txhw_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_pkts, tbase);
465         } else {
466                 ret+= tx_pkt_hw(tbase, mbufs, n_pkts, fake_out);
467         }
468         return ret;
469 }
470
471 /* Transmit to hw using tx_params_hw_sw structure
472    This function is used  to transmit to hw when tx_params_hw_sw should be used
473    i.e. when the task needs to transmit both to hw and sw */
474 int tx_pkt_no_drop_never_discard_hw1_no_pointer(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
475 {
476         txhw_no_drop(&tbase->tx_params_hw_sw.tx_port_queue, mbufs, n_pkts, tbase);
477         return 0;
478 }
479
480 int tx_pkt_no_drop_never_discard_sw1(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
481 {
482         return ring_enq_no_drop(tbase->tx_params_sw.tx_rings[0], mbufs, n_pkts, tbase);
483 }
484
485 int tx_pkt_never_discard_sw1(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
486 {
487         return ring_enq_drop(tbase->tx_params_sw.tx_rings[0], mbufs, n_pkts, tbase);
488 }
489
490 static uint16_t tx_pkt_free_dropped(__attribute__((unused)) struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out)
491 {
492         uint64_t v = 0;
493         uint16_t i;
494         /* The most probable and most important optimize case is if
495            the no packets should be dropped. */
496         for (i = 0; i + 8 < n_pkts; i += 8) {
497                 v |= *((uint64_t*)(&out[i]));
498         }
499         for (; i < n_pkts; ++i) {
500                 v |= out[i];
501         }
502
503         if (unlikely(v)) {
504                 /* At least some packets need to be dropped, so the
505                    mbufs array needs to be updated. */
506                 uint16_t n_kept = 0;
507                 uint16_t n_discard = 0;
508                 for (uint16_t i = 0; i < n_pkts; ++i) {
509                         if (unlikely(out[i] >= OUT_HANDLED)) {
510                                 rte_pktmbuf_free(mbufs[i]);
511                                 n_discard += out[i] == OUT_DISCARD;
512                                 continue;
513                         }
514                         mbufs[n_kept++] = mbufs[i];
515                 }
516                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, n_discard);
517                 TASK_STATS_ADD_DROP_HANDLED(&tbase->aux->stats, n_pkts - n_kept - n_discard);
518                 return n_kept;
519         }
520         return n_pkts;
521 }
522
523 int tx_pkt_no_drop_hw1(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out)
524 {
525         const uint16_t n_kept = tx_pkt_free_dropped(tbase, mbufs, n_pkts, out);
526         int ret = 0;
527
528         if (likely(n_kept))
529                 ret = txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_kept, tbase);
530         return ret;
531 }
532
533 int tx_pkt_no_drop_sw1(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out)
534 {
535         const uint16_t n_kept = tx_pkt_free_dropped(tbase, mbufs, n_pkts, out);
536         int ret = 0;
537
538         if (likely(n_kept))
539                 ret = ring_enq_no_drop(tbase->tx_params_sw.tx_rings[0], mbufs, n_kept, tbase);
540         return ret;
541 }
542
543 int tx_pkt_hw1(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out)
544 {
545         const uint16_t n_kept = tx_pkt_free_dropped(tbase, mbufs, n_pkts, out);
546
547         if (likely(n_kept))
548                 return txhw_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_kept, tbase);
549         return n_pkts;
550 }
551
552 int tx_pkt_sw1(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out)
553 {
554         const uint16_t n_kept = tx_pkt_free_dropped(tbase, mbufs, n_pkts, out);
555
556         if (likely(n_kept))
557                 return ring_enq_drop(tbase->tx_params_sw.tx_rings[0], mbufs, n_kept, tbase);
558         return 0;
559 }
560
561 int tx_pkt_self(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, uint8_t *out)
562 {
563         const uint16_t n_kept = tx_pkt_free_dropped(tbase, mbufs, n_pkts, out);
564
565         TASK_STATS_ADD_TX(&tbase->aux->stats, n_kept);
566         tbase->ws_mbuf->idx[0].nb_rx = n_kept;
567         struct rte_mbuf **tx_mbuf = tbase->ws_mbuf->mbuf[0] + (tbase->ws_mbuf->idx[0].prod & WS_MBUF_MASK);
568         for (uint16_t i = 0; i < n_kept; ++i) {
569                 tx_mbuf[i] = mbufs[i];
570         }
571         return 0;
572 }
573
574 int tx_pkt_never_discard_self(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
575 {
576         TASK_STATS_ADD_TX(&tbase->aux->stats, n_pkts);
577         tbase->ws_mbuf->idx[0].nb_rx = n_pkts;
578         struct rte_mbuf **tx_mbuf = tbase->ws_mbuf->mbuf[0] + (tbase->ws_mbuf->idx[0].prod & WS_MBUF_MASK);
579         for (uint16_t i = 0; i < n_pkts; ++i) {
580                 tx_mbuf[i] = mbufs[i];
581         }
582         return 0;
583 }
584
585 int tx_pkt_no_drop_hw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
586 {
587         int ret = 0;
588         buf_pkt_all(tbase, mbufs, n_pkts, out);
589
590         const uint8_t nb_bufs = tbase->tx_params_hw.nb_txports;
591         uint16_t prod, cons;
592
593         for (uint8_t i = 0; i < nb_bufs; ++i) {
594                 prod = tbase->ws_mbuf->idx[i].prod;
595                 cons = tbase->ws_mbuf->idx[i].cons;
596
597                 if (((uint16_t)(prod - cons)) >= MAX_PKT_BURST) {
598                         tbase->flags &= ~FLAG_TX_FLUSH;
599                         tbase->ws_mbuf->idx[i].cons = cons + MAX_PKT_BURST;
600                         ret+= txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), MAX_PKT_BURST, tbase);
601                 }
602         }
603         return ret;
604 }
605
606 int tx_pkt_no_drop_sw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
607 {
608         int ret = 0;
609         buf_pkt_all(tbase, mbufs, n_pkts, out);
610
611         const uint8_t nb_bufs = tbase->tx_params_sw.nb_txrings;
612         uint16_t prod, cons;
613
614         for (uint8_t i = 0; i < nb_bufs; ++i) {
615                 prod = tbase->ws_mbuf->idx[i].prod;
616                 cons = tbase->ws_mbuf->idx[i].cons;
617
618                 if (((uint16_t)(prod - cons)) >= MAX_PKT_BURST) {
619                         tbase->flags &= ~FLAG_TX_FLUSH;
620                         tbase->ws_mbuf->idx[i].cons = cons + MAX_PKT_BURST;
621                         ret += ring_enq_no_drop(tbase->tx_params_sw.tx_rings[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), MAX_PKT_BURST, tbase);
622                 }
623         }
624         return ret;
625 }
626
627 int tx_pkt_hw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
628 {
629         int ret = 0;
630         buf_pkt_all(tbase, mbufs, n_pkts, out);
631
632         const uint8_t nb_bufs = tbase->tx_params_hw.nb_txports;
633         uint16_t prod, cons;
634
635         for (uint8_t i = 0; i < nb_bufs; ++i) {
636                 prod = tbase->ws_mbuf->idx[i].prod;
637                 cons = tbase->ws_mbuf->idx[i].cons;
638
639                 if (((uint16_t)(prod - cons)) >= MAX_PKT_BURST) {
640                         tbase->flags &= ~FLAG_TX_FLUSH;
641                         tbase->ws_mbuf->idx[i].cons = cons + MAX_PKT_BURST;
642                         ret += txhw_drop(&tbase->tx_params_hw.tx_port_queue[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), MAX_PKT_BURST, tbase);
643                 }
644         }
645         return ret;
646 }
647
648 int tx_pkt_sw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
649 {
650         int ret = 0;
651         buf_pkt_all(tbase, mbufs, n_pkts, out);
652
653         const uint8_t nb_bufs = tbase->tx_params_sw.nb_txrings;
654         uint16_t prod, cons;
655         for (uint8_t i = 0; i < nb_bufs; ++i) {
656                 prod = tbase->ws_mbuf->idx[i].prod;
657                 cons = tbase->ws_mbuf->idx[i].cons;
658
659                 if (((uint16_t)(prod - cons)) >= MAX_PKT_BURST) {
660                         tbase->flags &= ~FLAG_TX_FLUSH;
661                         tbase->ws_mbuf->idx[i].cons = cons + MAX_PKT_BURST;
662                         ret+= ring_enq_drop(tbase->tx_params_sw.tx_rings[i], tbase->ws_mbuf->mbuf[i] + (cons & WS_MBUF_MASK), MAX_PKT_BURST, tbase);
663                 }
664         }
665         return ret;
666 }
667
668 static inline void trace_one_rx_pkt(struct task_base *tbase, struct rte_mbuf *mbuf)
669 {
670         struct rte_mbuf tmp;
671         /* For each packet being transmitted, find which
672            buffer represent the packet as it was before
673            processing. */
674         uint32_t j = 0;
675         uint32_t len = sizeof(tbase->aux->task_rt_dump.pkt_mbuf_addr)/sizeof(tbase->aux->task_rt_dump.pkt_mbuf_addr[0]);
676         for (;j < len; ++j) {
677                 if (tbase->aux->task_rt_dump.pkt_mbuf_addr[j] == mbuf)
678                         break;
679         }
680         if (j != len) {
681 #if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0)
682                 tmp.data_off = 0;
683 #endif
684                 rte_pktmbuf_data_len(&tmp) = tbase->aux->task_rt_dump.pkt_cpy_len[j];
685                 rte_pktmbuf_pkt_len(&tmp) = tbase->aux->task_rt_dump.pkt_cpy_len[j];
686                 tmp.buf_addr = tbase->aux->task_rt_dump.pkt_cpy[j];
687                 plogdx_info(&tmp, "Trace RX: ");
688         }
689 }
690
691 static inline void trace_one_tx_pkt(struct task_base *tbase, struct rte_mbuf *mbuf, uint8_t *out, uint32_t i)
692 {
693         if (out) {
694                 switch(out[i]) {
695                 case 0xFE:
696                         plogdx_info(mbuf, "Handled: ");
697                         break;
698                 case 0xFF:
699                         plogdx_info(mbuf, "Dropped: ");
700                         break;
701                 default:
702                         plogdx_info(mbuf, "TX[%d]: ", out[i]);
703                         break;
704                 }
705         } else if (tbase->aux->tx_pkt_orig == tx_pkt_drop_all) {
706                 plogdx_info(mbuf, "Dropped: ");
707         } else
708                 plogdx_info(mbuf, "TX[0]: ");
709 }
710
711 static void unset_trace(struct task_base *tbase)
712 {
713         if (0 == tbase->aux->task_rt_dump.n_trace) {
714                 if ((tbase->tx_pkt == tx_pkt_l3) || (tbase->tx_pkt == tx_pkt_ndp)){
715                         tbase->aux->tx_pkt_l2 = tbase->aux->tx_pkt_orig;
716                         tbase->aux->tx_pkt_orig = NULL;
717                 } else {
718                         tbase->tx_pkt = tbase->aux->tx_pkt_orig;
719                         tbase->aux->tx_pkt_orig = NULL;
720                 }
721                 tbase->aux->task_rt_dump.cur_trace = 0;
722                 task_base_del_rx_pkt_function(tbase, rx_pkt_trace);
723         }
724 }
725
726 int tx_pkt_trace(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
727 {
728         int ret = 0;
729         if (tbase->aux->task_rt_dump.cur_trace == 0) {
730                 // No packet received since dumping...
731                 tbase->aux->task_rt_dump.n_print_tx = tbase->aux->task_rt_dump.n_trace;
732                 if (tbase->aux->task_rt_dump.n_trace < n_pkts) {
733                         tbase->aux->task_rt_dump.n_trace = 0;
734                         tbase->aux->task_rt_dump.cur_trace = 0;
735                         task_base_del_rx_pkt_function(tbase, rx_pkt_trace);
736                 } else {
737                         tbase->aux->task_rt_dump.n_trace -= n_pkts;
738                 }
739                 ret = tx_pkt_dump(tbase, mbufs, n_pkts, out);
740                 tbase->aux->task_rt_dump.n_print_tx = 0;
741                 return ret;
742         }
743         plog_info("Tracing %d pkts\n", tbase->aux->task_rt_dump.cur_trace);
744         uint32_t cur_trace = (n_pkts < tbase->aux->task_rt_dump.cur_trace) ? n_pkts: tbase->aux->task_rt_dump.cur_trace;
745         for (uint32_t i = 0; i < cur_trace; ++i) {
746                 trace_one_rx_pkt(tbase, mbufs[i]);
747                 trace_one_tx_pkt(tbase, mbufs[i], out, i);
748
749         }
750         ret = tbase->aux->tx_pkt_orig(tbase, mbufs, n_pkts, out);
751
752         unset_trace(tbase);
753         return ret;
754 }
755
756 int tx_pkt_dump(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
757 {
758         uint32_t n_dump = tbase->aux->task_rt_dump.n_print_tx;
759         int ret = 0;
760
761         n_dump = n_pkts < n_dump? n_pkts : n_dump;
762         for (uint32_t i = 0; i < n_dump; ++i) {
763                 if (out) {
764                         switch (out[i]) {
765                         case 0xFE:
766                                 plogdx_info(mbufs[i], "Handled: ");
767                                 break;
768                         case 0xFF:
769                                 plogdx_info(mbufs[i], "Dropped: ");
770                                 break;
771                         default:
772                                 plogdx_info(mbufs[i], "TX[%d]: ", out[i]);
773                                 break;
774                         }
775                 } else
776                         plogdx_info(mbufs[i], "TX: ");
777         }
778         tbase->aux->task_rt_dump.n_print_tx -= n_dump;
779
780         ret = tbase->aux->tx_pkt_orig(tbase, mbufs, n_pkts, out);
781
782         if (0 == tbase->aux->task_rt_dump.n_print_tx) {
783                 if ((tbase->tx_pkt == tx_pkt_l3) || (tbase->tx_pkt == tx_pkt_ndp)) {
784                         tbase->aux->tx_pkt_l2 = tbase->aux->tx_pkt_orig;
785                         tbase->aux->tx_pkt_orig = NULL;
786                 } else {
787                         tbase->tx_pkt = tbase->aux->tx_pkt_orig;
788                         tbase->aux->tx_pkt_orig = NULL;
789                 }
790         }
791         return ret;
792 }
793
794 /* Gather the distribution of the number of packets that have been
795    xmitted from one TX call. Since the value is only modified by the
796    task that xmits the packet, no atomic operation is needed. */
797 int tx_pkt_distr(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
798 {
799         if (likely(n_pkts < TX_BUCKET_SIZE))
800                 tbase->aux->tx_bucket[n_pkts]++;
801         else
802                 tbase->aux->tx_bucket[TX_BUCKET_SIZE - 1]++;
803         return tbase->aux->tx_pkt_orig(tbase, mbufs, n_pkts, out);
804 }
805
806 int tx_pkt_bw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
807 {
808         uint32_t tx_bytes = 0;
809         uint32_t drop_bytes = 0;
810
811         for (uint16_t i = 0; i < n_pkts; ++i) {
812                 if (!out || out[i] < OUT_HANDLED)
813                         tx_bytes += mbuf_wire_size(mbufs[i]);
814                 else
815                         drop_bytes += mbuf_wire_size(mbufs[i]);
816         }
817
818         TASK_STATS_ADD_TX_BYTES(&tbase->aux->stats, tx_bytes);
819         TASK_STATS_ADD_DROP_BYTES(&tbase->aux->stats, drop_bytes);
820         return tbase->aux->tx_pkt_orig(tbase, mbufs, n_pkts, out);
821 }
822
823 int tx_pkt_drop_all(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, uint8_t *out)
824 {
825         for (uint16_t j = 0; j < n_pkts; ++j) {
826                 rte_pktmbuf_free(mbufs[j]);
827         }
828         if (out == NULL)
829                 TASK_STATS_ADD_DROP_HANDLED(&tbase->aux->stats, n_pkts);
830         else {
831                 for (uint16_t j = 0; j < n_pkts; ++j) {
832                         if (out[j] == OUT_HANDLED)
833                                 TASK_STATS_ADD_DROP_HANDLED(&tbase->aux->stats, 1);
834                         else
835                                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
836                 }
837         }
838         return n_pkts;
839 }
840 static inline void dump_pkts(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
841 {
842         uint32_t n_dump = tbase->aux->task_rt_dump.n_print_tx;
843         uint32_t n_trace = tbase->aux->task_rt_dump.n_trace;
844
845         if (unlikely(n_dump)) {
846                 n_dump = n_pkts < n_dump? n_pkts : n_dump;
847                 for (uint32_t i = 0; i < n_dump; ++i) {
848                         plogdx_info(mbufs[i], "TX: ");
849                 }
850                 tbase->aux->task_rt_dump.n_print_tx -= n_dump;
851         } else if (unlikely(n_trace)) {
852                 n_trace = n_pkts < n_trace? n_pkts : n_trace;
853                 for (uint32_t i = 0; i < n_trace; ++i) {
854                         plogdx_info(mbufs[i], "TX: ");
855                 }
856                 tbase->aux->task_rt_dump.n_trace -= n_trace;
857         }
858 }
859
860 // ctrlplane packets are slow path, hence cost of checking if dump ortrace is needed in not too important
861 // easier to have this implementation than an implementation similar to dataplane tx
862 int tx_ctrlplane_hw(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
863 {
864         dump_pkts(tbase, mbufs, n_pkts);
865         return txhw_no_drop(&tbase->tx_params_hw.tx_port_queue[0], mbufs, n_pkts, tbase);
866 }
867
868 int tx_ctrlplane_sw(struct task_base *tbase, struct rte_mbuf **mbufs, const uint16_t n_pkts, __attribute__((unused)) uint8_t *out)
869 {
870         dump_pkts(tbase, mbufs, n_pkts);
871         return ring_enq_no_drop(tbase->tx_params_sw.tx_rings[0], mbufs, n_pkts, tbase);
872 }
873
874 static inline int tx_ring_all(struct task_base *tbase, struct rte_ring *ring, uint8_t command,  struct rte_mbuf *mbuf, uint8_t core_id, uint8_t task_id, uint32_t ip)
875 {
876         if (tbase->aux->task_rt_dump.cur_trace) {
877                 trace_one_rx_pkt(tbase, mbuf);
878         }
879         ctrl_ring_set_command_core_task_ip(mbuf, ((uint64_t)ip << 32) | (core_id << 16) | (task_id << 8) | command);
880         return rte_ring_enqueue(ring, mbuf);
881 }
882
883 int tx_ring_cti(struct task_base *tbase, struct rte_ring *ring, uint8_t command,  struct rte_mbuf *mbuf, uint8_t core_id, uint8_t task_id, uint32_t ip, uint16_t vlan)
884 {
885         plogx_dbg("\tSending command %s with ip %d.%d.%d.%d to ring %p using mbuf %p, core %d and task %d - ring size now %d\n", actions_string[command], IP4(ip), ring, mbuf, core_id, task_id, rte_ring_free_count(ring));
886         ctrl_ring_set_vlan(mbuf, vlan);
887         int ret = tx_ring_all(tbase, ring, command,  mbuf, core_id, task_id, ip);
888         if (unlikely(ret != 0)) {
889                 plogx_dbg("\tFail to send command %s with ip %d.%d.%d.%d to ring %p using mbuf %p, core %d and task %d - ring size now %d\n", actions_string[command], IP4(ip), ring, mbuf, core_id, task_id, rte_ring_free_count(ring));
890                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
891                 rte_pktmbuf_free(mbuf);
892         }
893         return ret;
894 }
895
896 void tx_ring_ip(struct task_base *tbase, struct rte_ring *ring, uint8_t command,  struct rte_mbuf *mbuf, uint32_t ip)
897 {
898         plogx_dbg("\tSending command %s with ip %d.%d.%d.%d to ring %p using mbuf %p - ring size now %d\n", actions_string[command], IP4(ip), ring, mbuf, rte_ring_free_count(ring));
899         int ret = tx_ring_all(tbase, ring, command,  mbuf, 0, 0, ip);
900         if (unlikely(ret != 0)) {
901                 plogx_dbg("\tFail to send command %s with ip %d.%d.%d.%d to ring %p using mbuf %p - ring size now %d\n", actions_string[command], IP4(ip), ring, mbuf, rte_ring_free_count(ring));
902                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
903                 rte_pktmbuf_free(mbuf);
904         }
905 }
906
907 void tx_ring(struct task_base *tbase, struct rte_ring *ring, uint16_t command,  struct rte_mbuf *mbuf)
908 {
909         plogx_dbg("\tSending command %s to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ring, mbuf, rte_ring_free_count(ring));
910         int ret = tx_ring_all(tbase, ring, command,  mbuf, 0, 0, 0);
911         if (unlikely(ret != 0)) {
912                 plogx_dbg("\tFail to send command %s to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ring, mbuf, rte_ring_free_count(ring));
913                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
914                 rte_pktmbuf_free(mbuf);
915         }
916 }
917
918 void tx_ring_route(struct task_base *tbase, struct rte_ring *ring, int add, struct rte_mbuf *mbuf, uint32_t ip, uint32_t gateway_ip, uint32_t prefix)
919 {
920         uint8_t command;
921         if (add)
922                 command = ROUTE_ADD_FROM_MASTER;
923         else
924                 command = ROUTE_DEL_FROM_MASTER;
925
926         plogx_dbg("\tSending command %s to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ring, mbuf, rte_ring_free_count(ring));
927         ctrl_ring_set_command(mbuf, command);
928         ctrl_ring_set_ip(mbuf, ip);
929         ctrl_ring_set_gateway_ip(mbuf, gateway_ip);
930         ctrl_ring_set_prefix(mbuf, prefix);
931         if (tbase->aux->task_rt_dump.cur_trace) {
932                 trace_one_rx_pkt(tbase, mbuf);
933         }
934         int ret = rte_ring_enqueue(ring, mbuf);
935         if (unlikely(ret != 0)) {
936                 plogx_dbg("\tFail to send command %s to ring %p using mbuf %p - ring size now %d\n", actions_string[command], ring, mbuf, rte_ring_free_count(ring));
937                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
938                 rte_pktmbuf_free(mbuf);
939         }
940 }
941
942 void tx_ring_cti6(struct task_base *tbase, struct rte_ring *ring, uint8_t command,  struct rte_mbuf *mbuf, uint8_t core_id, uint8_t task_id, struct ipv6_addr *ip, uint16_t vlan)
943 {
944         int ret;
945         plogx_dbg("\tSending command %s with ip "IPv6_BYTES_FMT" to ring %p using mbuf %p, core %d and task %d - ring size now %d\n", actions_string[command], IPv6_BYTES(ip->bytes), ring, mbuf, core_id, task_id, rte_ring_free_count(ring));
946         if (tbase->aux->task_rt_dump.cur_trace) {
947                 trace_one_rx_pkt(tbase, mbuf);
948         }
949         ctrl_ring_set_command_core_task_ip(mbuf, (core_id << 16) | (task_id << 8) | command);
950         ctrl_ring_set_ipv6_addr(mbuf, ip);
951         ctrl_ring_set_vlan(mbuf, vlan);
952         ret = rte_ring_enqueue(ring, mbuf);
953
954         if (unlikely(ret != 0)) {
955                 plogx_dbg("\tFail to send command %s with ip "IPv6_BYTES_FMT" to ring %p using mbuf %p, core %d and task %d - ring size now %d\n", actions_string[command], IPv6_BYTES(ip->bytes), ring, mbuf, core_id, task_id, rte_ring_free_count(ring));
956                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
957                 rte_pktmbuf_free(mbuf);
958         }
959 }
960
961 void tx_ring_ip6(struct task_base *tbase, struct rte_ring *ring, uint8_t command,  struct rte_mbuf *mbuf, struct ipv6_addr *ip)
962 {
963         int ret;
964         plogx_dbg("\tSending command %s with ip "IPv6_BYTES_FMT" to ring %p using mbuf %p - ring size now %d\n", actions_string[command], IPv6_BYTES(ip->bytes), ring, mbuf, rte_ring_free_count(ring));
965         if (tbase->aux->task_rt_dump.cur_trace) {
966                 trace_one_rx_pkt(tbase, mbuf);
967         }
968         ctrl_ring_set_command(mbuf, command);
969         ctrl_ring_set_ipv6_addr(mbuf, ip);
970         ret = rte_ring_enqueue(ring, mbuf);
971
972         if (unlikely(ret != 0)) {
973                 plogx_dbg("\tFail to send command %s with ip "IPv6_BYTES_FMT" to ring %p using mbuf %p - ring size now %d\n", actions_string[command], IPv6_BYTES(ip->bytes), ring, mbuf, rte_ring_free_count(ring));
974                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
975                 rte_pktmbuf_free(mbuf);
976         }
977 }
978
979 void tx_ring_ip6_data(struct task_base *tbase, struct rte_ring *ring, uint8_t command,  struct rte_mbuf *mbuf, struct ipv6_addr *ip, uint64_t data)
980 {
981         int ret;
982         plogx_dbg("\tSending command %s with ip "IPv6_BYTES_FMT" to ring %p using mbuf %p - ring size now %d\n", actions_string[command], IPv6_BYTES(ip->bytes), ring, mbuf, rte_ring_free_count(ring));
983         if (tbase->aux->task_rt_dump.cur_trace) {
984                 trace_one_rx_pkt(tbase, mbuf);
985         }
986         ctrl_ring_set_command(mbuf, command);
987         ctrl_ring_set_ipv6_addr(mbuf, ip);
988         ctrl_ring_set_data(mbuf, data);
989         ret = rte_ring_enqueue(ring, mbuf);
990
991         if (unlikely(ret != 0)) {
992                 plogx_dbg("\tFail to send command %s with ip "IPv6_BYTES_FMT" to ring %p using mbuf %p - ring size now %d\n", actions_string[command], IPv6_BYTES(ip->bytes), ring, mbuf, rte_ring_free_count(ring));
993                 TASK_STATS_ADD_DROP_DISCARD(&tbase->aux->stats, 1);
994                 rte_pktmbuf_free(mbuf);
995         }
996
997 }