NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_ct_tcp_actions_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024 NVIDIA CORPORATION AND AFFILIATES. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are permitted
5  * provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice, this list of
7  * conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
12  * to endorse or promote products derived from this software without specific prior written
13  * permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21  * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  */
25 
26 #include <unistd.h>
27 
28 #include <rte_ethdev.h>
29 
30 #include <doca_log.h>
31 #include <doca_flow.h>
32 #include <doca_flow_ct.h>
33 #include <doca_bitfield.h>
34 
35 #include "flow_ct_common.h"
36 #include "flow_common.h"
37 
38 #define PACKET_BURST 128
39 #define NB_COUNTERS 6
40 
41 static uint16_t sessions = 0;
42 static struct doca_flow_pipe_entry *rss_entry;
43 static struct doca_flow_pipe_entry *egress_entry;
44 static struct doca_flow_pipe_entry *tcp_flags_filter_entry;
45 static struct doca_flow_pipe_entry *ct_miss_entry;
46 static struct doca_flow_pipe_entry *ct_entry;
47 
48 DOCA_LOG_REGISTER(FLOW_CT_TCP);
49 
71 /*
72  * Create RSS pipe
73  *
74  * @port [in]: Pipe port
75  * @status [in]: user context for adding entry
76  * @pipe [out]: Created pipe pointer
77  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
78  */
79 static doca_error_t create_rss_pipe(struct doca_flow_port *port,
80  struct entries_status *status,
81  struct doca_flow_pipe **pipe)
82 {
83  struct doca_flow_match match;
84  struct doca_flow_pipe_cfg *cfg;
85  struct doca_flow_fwd fwd;
87  uint16_t rss_queues[1];
89 
90  memset(&match, 0, sizeof(match));
91  memset(&fwd, 0, sizeof(fwd));
92  memset(&monitor, 0, sizeof(monitor));
93 
95 
97  if (result != DOCA_SUCCESS) {
98  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
99  return result;
100  }
101 
102  result = set_flow_pipe_cfg(cfg, "RSS_PIPE", DOCA_FLOW_PIPE_BASIC, false);
103  if (result != DOCA_SUCCESS) {
104  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
105  goto destroy_pipe_cfg;
106  }
108  if (result != DOCA_SUCCESS) {
109  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
110  goto destroy_pipe_cfg;
111  }
113  if (result != DOCA_SUCCESS) {
114  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
115  goto destroy_pipe_cfg;
116  }
117 
118  /* RSS queue - send matched traffic to queue 0 */
119  rss_queues[0] = 0;
124  fwd.rss.nr_queues = 1;
125 
127  if (result != DOCA_SUCCESS) {
128  DOCA_LOG_ERR("Failed to create RSS pipe: %s", doca_error_get_descr(result));
129  goto destroy_pipe_cfg;
130  }
132 
133  /* Match on any packet */
134  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, &fwd, 0, status, &rss_entry);
135  if (result != DOCA_SUCCESS) {
136  DOCA_LOG_ERR("Failed to add RSS pipe entry: %s", doca_error_get_descr(result));
137  return result;
138  }
139 
141  if (result != DOCA_SUCCESS)
142  DOCA_LOG_ERR("Failed to process RSS entry: %s", doca_error_get_descr(result));
143 
144  return result;
145 
148  return result;
149 }
150 
151 /*
152  * Create egress pipe
153  *
154  * @port [in]: Pipe port
155  * @port_id [in]: Next pipe port id
156  * @status [in]: user context for adding entry
157  * @pipe [out]: Created pipe pointer
158  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
159  */
160 static doca_error_t create_egress_pipe(struct doca_flow_port *port,
161  int port_id,
162  struct entries_status *status,
163  struct doca_flow_pipe **pipe)
164 {
165  struct doca_flow_match match;
166  struct doca_flow_pipe_cfg *cfg;
167  struct doca_flow_fwd fwd;
168  struct doca_flow_monitor monitor;
170 
171  memset(&match, 0, sizeof(match));
172  memset(&fwd, 0, sizeof(fwd));
173  memset(&monitor, 0, sizeof(monitor));
174 
176 
178  if (result != DOCA_SUCCESS) {
179  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
180  return result;
181  }
182 
183  result = set_flow_pipe_cfg(cfg, "EGRESS_PIPE", DOCA_FLOW_PIPE_BASIC, false);
184  if (result != DOCA_SUCCESS) {
185  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
186  goto destroy_pipe_cfg;
187  }
189  if (result != DOCA_SUCCESS) {
190  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
191  goto destroy_pipe_cfg;
192  }
194  if (result != DOCA_SUCCESS) {
195  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
196  goto destroy_pipe_cfg;
197  }
198 
200  fwd.port_id = port_id;
201 
203  if (result != DOCA_SUCCESS) {
204  DOCA_LOG_ERR("Failed to create EGRESS pipe: %s", doca_error_get_descr(result));
205  goto destroy_pipe_cfg;
206  }
208 
209  /* Match on any packet */
210  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, &fwd, 0, status, &egress_entry);
211  if (result != DOCA_SUCCESS) {
212  DOCA_LOG_ERR("Failed to add EGRESS pipe entry: %s", doca_error_get_descr(result));
213  return result;
214  }
215 
217  if (result != DOCA_SUCCESS)
218  DOCA_LOG_ERR("Failed to process EGRESS entry: %s", doca_error_get_descr(result));
219 
220  return result;
221 
224  return result;
225 }
226 
227 /*
228  * Create CT miss pipe
229  *
230  * @port [in]: Pipe port
231  * @fwd_pipe [in]: Forward pipe pointer
232  * @status [in]: user context for adding entry
233  * @pipe [out]: Created pipe pointer
234  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
235  */
236 static doca_error_t create_ct_miss_pipe(struct doca_flow_port *port,
237  struct doca_flow_pipe *fwd_pipe,
238  struct entries_status *status,
239  struct doca_flow_pipe **pipe)
240 {
241  struct doca_flow_match match;
242  struct doca_flow_pipe_cfg *cfg;
243  struct doca_flow_fwd fwd;
244  struct doca_flow_monitor monitor;
246 
247  memset(&match, 0, sizeof(match));
248  memset(&fwd, 0, sizeof(fwd));
249  memset(&monitor, 0, sizeof(monitor));
250 
252 
254  if (result != DOCA_SUCCESS) {
255  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
256  return result;
257  }
258 
259  result = set_flow_pipe_cfg(cfg, "CT_MISS_PIPE", DOCA_FLOW_PIPE_BASIC, false);
260  if (result != DOCA_SUCCESS) {
261  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
262  goto destroy_pipe_cfg;
263  }
265  if (result != DOCA_SUCCESS) {
266  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
267  goto destroy_pipe_cfg;
268  }
270  if (result != DOCA_SUCCESS) {
271  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
272  goto destroy_pipe_cfg;
273  }
274 
276  fwd.next_pipe = fwd_pipe;
277 
279  if (result != DOCA_SUCCESS) {
280  DOCA_LOG_ERR("Failed to create CT miss pipe: %s", doca_error_get_descr(result));
281  goto destroy_pipe_cfg;
282  }
284 
285  /* Match on any packet */
286  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, &fwd, 0, status, &ct_miss_entry);
287  if (result != DOCA_SUCCESS) {
288  DOCA_LOG_ERR("Failed to add CT miss pipe entry: %s", doca_error_get_descr(result));
289  return result;
290  }
291 
293  if (result != DOCA_SUCCESS)
294  DOCA_LOG_ERR("Failed to process CT miss entry: %s", doca_error_get_descr(result));
295 
296  return result;
297 
300  return result;
301 }
302 
303 /*
304  * Create DOCA Flow TCP state pipe to filter state on known TCP session
305  *
306  * @port [in]: Pipe port
307  * @status [in]: User context for adding entry
308  * @fwd_pipe [in]: Forward pipe
309  * @fwd_miss_pipe [in]: Forward miss pipe
310  * @pipe [out]: Created pipe pointer
311  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
312  */
313 static doca_error_t create_tcp_flags_filter_pipe(struct doca_flow_port *port,
314  struct entries_status *status,
315  struct doca_flow_pipe *fwd_pipe,
316  struct doca_flow_pipe *fwd_miss_pipe,
317  struct doca_flow_pipe **pipe)
318 {
319  struct doca_flow_match match;
320  struct doca_flow_match mask;
321  struct doca_flow_fwd fwd;
322  struct doca_flow_fwd fwd_miss;
323  struct doca_flow_pipe_cfg *cfg;
324  struct doca_flow_monitor monitor;
326 
327  memset(&match, 0, sizeof(match));
328  memset(&mask, 0, sizeof(mask));
329  memset(&fwd, 0, sizeof(fwd));
330  memset(&fwd_miss, 0, sizeof(fwd_miss));
331  memset(&monitor, 0, sizeof(monitor));
332 
334 
335  /* Match on non SYN, FIN and RST packets */
336  match.outer.tcp.flags = 0xff;
338 
342 
344  if (result != DOCA_SUCCESS) {
345  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
346  return result;
347  }
348 
349  result = set_flow_pipe_cfg(cfg, "TCP_FLAGS_FILTER_PIPE", DOCA_FLOW_PIPE_BASIC, false);
350  if (result != DOCA_SUCCESS) {
351  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
352  goto destroy_pipe_cfg;
353  }
354  result = doca_flow_pipe_cfg_set_match(cfg, &match, &mask);
355  if (result != DOCA_SUCCESS) {
356  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
357  goto destroy_pipe_cfg;
358  }
360  if (result != DOCA_SUCCESS) {
361  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
362  goto destroy_pipe_cfg;
363  }
364 
366  fwd.next_pipe = fwd_pipe;
367 
369  fwd_miss.next_pipe = fwd_miss_pipe;
370 
372  if (result != DOCA_SUCCESS) {
373  DOCA_LOG_ERR("Failed to create TCP_FLAGS_FILTER pipe: %s", doca_error_get_descr(result));
374  goto destroy_pipe_cfg;
375  }
377 
378  match.outer.tcp.flags = 0;
379  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, NULL, 0, status, &tcp_flags_filter_entry);
380  if (result != DOCA_SUCCESS) {
381  DOCA_LOG_ERR("Failed to create TCP flags filter pipe entry: %s", doca_error_get_descr(result));
382  return result;
383  }
384 
386  if (result != DOCA_SUCCESS)
387  DOCA_LOG_ERR("Failed to process TCP flags filter entry: %s", doca_error_get_descr(result));
388 
389  return result;
390 
393  return result;
394 }
395 
396 /*
397  * Create CT pipe
398  *
399  * @port [in]: Pipe port
400  * @fwd_pipe [in]: Forward pipe pointer
401  * @fwd_miss_pipe [in]: Forward miss pipe pointer
402  * @pipe [out]: Created pipe pointer
403  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
404  */
405 static doca_error_t create_ct_pipe(struct doca_flow_port *port,
406  struct doca_flow_pipe *fwd_pipe,
407  struct doca_flow_pipe *fwd_miss_pipe,
408  struct doca_flow_pipe **pipe)
409 {
410  struct doca_flow_match match;
411  struct doca_flow_pipe_cfg *cfg;
412  struct doca_flow_fwd fwd;
413  struct doca_flow_fwd fwd_miss;
414  struct doca_flow_actions meta_action;
415  struct doca_flow_actions nat_action;
416  struct doca_flow_actions meta_action_mask;
417  struct doca_flow_actions nat_action_mask;
418  struct doca_flow_actions *actions_list[] = {&meta_action, &nat_action};
419  struct doca_flow_actions *actions_mask_list[] = {&meta_action_mask, &nat_action_mask};
421 
422  memset(&match, 0, sizeof(match));
423  memset(&fwd, 0, sizeof(fwd));
424  memset(&fwd_miss, 0, sizeof(fwd));
425  memset(&meta_action, 0, sizeof(meta_action));
426  memset(&nat_action, 0, sizeof(nat_action));
427  memset(&meta_action_mask, 0, sizeof(meta_action_mask));
428  memset(&nat_action_mask, 0, sizeof(nat_action_mask));
429 
431  fwd.next_pipe = fwd_pipe;
432 
434  fwd_miss.next_pipe = fwd_miss_pipe;
435 
436  meta_action.action_idx = 0;
437  meta_action.meta.pkt_meta = UINT32_MAX;
438  meta_action.meta.u32[0] = UINT32_MAX;
439 
440  nat_action.action_idx = 1;
441  nat_action.outer.l3_type = DOCA_FLOW_L3_TYPE_IP4;
442  nat_action.outer.ip4.src_ip = UINT32_MAX;
443  nat_action.outer.ip4.dst_ip = UINT32_MAX;
445  nat_action.outer.transport.src_port = UINT16_MAX;
446  nat_action.outer.transport.dst_port = UINT16_MAX;
447 
448  meta_action_mask.action_idx = 0;
449  meta_action_mask.meta.pkt_meta = DOCA_HTOBE32(0xffff);
450  meta_action_mask.meta.u32[0] = DOCA_HTOBE32(0xffff);
451 
452  nat_action_mask.action_idx = 1;
453  nat_action_mask.outer.l3_type = DOCA_FLOW_L3_TYPE_IP4;
454  nat_action_mask.outer.ip4.src_ip = UINT32_MAX;
455  nat_action_mask.outer.ip4.dst_ip = UINT32_MAX;
456  nat_action_mask.outer.l4_type_ext = DOCA_FLOW_L4_TYPE_EXT_TCP;
457  nat_action_mask.outer.transport.src_port = UINT16_MAX;
458  nat_action_mask.outer.transport.dst_port = UINT16_MAX;
459 
461  if (result != DOCA_SUCCESS) {
462  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
463  return result;
464  }
465 
466  result = set_flow_pipe_cfg(cfg, "CT_PIPE", DOCA_FLOW_PIPE_CT, false);
467  if (result != DOCA_SUCCESS) {
468  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
469  goto destroy_pipe_cfg;
470  }
472  if (result != DOCA_SUCCESS) {
473  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
474  goto destroy_pipe_cfg;
475  }
476  result = doca_flow_pipe_cfg_set_actions(cfg, actions_list, actions_mask_list, NULL, 2);
477  if (result != DOCA_SUCCESS) {
478  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
479  goto destroy_pipe_cfg;
480  }
481 
483  if (result != DOCA_SUCCESS)
484  DOCA_LOG_ERR("Failed to create CT pipe: %s", doca_error_get_descr(result));
487  return result;
488 }
489 
490 /*
491  * Parse TCP packet to update CT tables
492  *
493  * @packet [in]: Packet to parse
494  * @match_o [out]: Origin match struct to fill
495  * @match_r [out]: Reply match struct to fill
496  * @tcp_state [out]: Packet TCP state
497  */
498 static void parse_packet(struct rte_mbuf *packet,
499  struct doca_flow_ct_match *match_o,
500  struct doca_flow_ct_match *match_r,
501  uint8_t *tcp_state)
502 {
503  uint8_t *l4_hdr;
504  struct rte_ipv4_hdr *ipv4_hdr;
505  const struct rte_tcp_hdr *tcp_hdr;
506 
507  ipv4_hdr = rte_pktmbuf_mtod_offset(packet, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
508 
509  match_o->ipv4.src_ip = ipv4_hdr->src_addr;
510  match_o->ipv4.dst_ip = ipv4_hdr->dst_addr;
511  match_r->ipv4.src_ip = match_o->ipv4.dst_ip;
512  match_r->ipv4.dst_ip = match_o->ipv4.src_ip;
513 
514  l4_hdr = (typeof(l4_hdr))ipv4_hdr + rte_ipv4_hdr_len(ipv4_hdr);
515  tcp_hdr = (typeof(tcp_hdr))l4_hdr;
516 
517  match_o->ipv4.l4_port.src_port = tcp_hdr->src_port;
518  match_o->ipv4.l4_port.dst_port = tcp_hdr->dst_port;
519  match_r->ipv4.l4_port.src_port = match_o->ipv4.l4_port.dst_port;
520  match_r->ipv4.l4_port.dst_port = match_o->ipv4.l4_port.src_port;
521 
524 
525  *tcp_state = tcp_hdr->tcp_flags;
526 }
527 
528 /*
529  * Dequeue packets from DPDK queues, parse and update CT tables with new connection 5 tuple
530  *
531  * @port [in]: Port id to which an entry should be inserted
532  * @ct_queue [in]: DOCA Flow CT queue number
533  * @ct_status [in]: User context for adding CT entry
534  * @shared_handle [in]: Shared action handle
535  * @entry [in/out]: CT entry
536  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
537  */
538 static doca_error_t process_packets(struct doca_flow_port *port,
539  uint16_t ct_queue,
540  struct entries_status *ct_status,
541  uint32_t shared_handle,
542  struct doca_flow_pipe_entry **entry)
543 {
544  struct rte_mbuf *packets[PACKET_BURST];
545  struct doca_flow_ct_match match_o;
546  struct doca_flow_ct_match match_r;
547  struct doca_flow_ct_actions shared_action_o, action_r;
551  uint8_t tcp_state;
553  int rc, i, nb_packets, nb_process = 0;
554 
555  memset(&match_o, 0, sizeof(match_o));
556  memset(&match_r, 0, sizeof(match_r));
557  memset(&action_r, 0, sizeof(action_r));
558  memset(&shared_action_o, 0, sizeof(shared_action_o));
559 
561  shared_action_o.action_handle = shared_handle;
562 
564  action_r.data.action_idx = 1;
565 
566  rc = rte_flow_dynf_metadata_register();
567  if (unlikely(rc)) {
568  DOCA_LOG_ERR("Enable metadata failed");
569  return DOCA_ERROR_BAD_STATE;
570  }
571 
572  nb_packets = rte_eth_rx_burst(0, 0, packets, PACKET_BURST);
573  if (nb_packets == 0) {
574  DOCA_LOG_INFO("Sample didn't receive packets to process");
575  return DOCA_ERROR_BAD_STATE;
576  }
577 
578  DOCA_LOG_INFO("%d packets received on rx_burst()", nb_packets);
579  for (i = 0; i < PACKET_BURST && i < nb_packets; i++) {
580  parse_packet(packets[i], &match_o, &match_r, &tcp_state);
581  if (tcp_state & DOCA_FLOW_MATCH_TCP_FLAG_SYN) {
582  if (sessions > 0) {
583  DOCA_LOG_INFO("Already have one alive session, cannot handle more, skip");
584  continue;
585  }
586  action_r.data.l4_port.src_port = match_r.ipv4.l4_port.dst_port;
587  action_r.data.l4_port.dst_port = match_r.ipv4.l4_port.src_port;
588  action_r.data.ip4.src_ip = match_r.ipv4.dst_ip;
589  action_r.data.ip4.dst_ip = match_r.ipv4.src_ip;
590 
591  /* Allocate CT entry */
593  NULL,
595  &match_o,
596  0,
597  &match_r,
598  0,
599  entry,
600  NULL);
601  if (result != DOCA_SUCCESS) {
602  DOCA_LOG_ERR("Failed to prepare CT entry\n");
603  return result;
604  }
605  result = doca_flow_ct_add_entry(ct_queue,
606  NULL,
607  flags,
608  &match_o,
609  &match_r,
610  &shared_action_o,
611  &action_r,
612  0,
613  0,
614  0,
615  ct_status,
616  *entry);
617  if (result != DOCA_SUCCESS) {
618  DOCA_LOG_ERR("Failed to add CT pipe an entry: %s", doca_error_get_descr(result));
619  return result;
620  }
621  sessions++;
622  nb_process++;
623  while (ct_status->nb_processed != nb_process) {
624  result = doca_flow_ct_entries_process(port, ct_queue, 0, 0, NULL);
625  if (result != DOCA_SUCCESS) {
626  DOCA_LOG_ERR("Failed to process Flow CT entries: %s",
628  return result;
629  }
630 
631  if (ct_status->failure) {
632  DOCA_LOG_ERR("Flow CT entries process returned with a failure");
633  return DOCA_ERROR_BAD_STATE;
634  }
635  }
637  "TCP session was created, waiting for 'FIN'/'RST' packet before ending the session");
638  } else if (tcp_state & DOCA_FLOW_MATCH_TCP_FLAG_FIN || tcp_state & DOCA_FLOW_MATCH_TCP_FLAG_RST) {
639  if (sessions == 0) {
640  DOCA_LOG_INFO("No alive session to destroy, skip destroy");
641  continue;
642  }
643  result = doca_flow_ct_rm_entry(ct_queue, NULL, flags, *entry);
644  if (result != DOCA_SUCCESS) {
645  DOCA_LOG_ERR("Failed to remove CT pipe entry: %s", doca_error_get_descr(result));
646  return result;
647  }
648  *entry = NULL;
649  sessions--;
650  DOCA_LOG_INFO("TCP session was ended");
651  } else {
652  DOCA_LOG_WARN("Sample is only able to process 'SYN', 'FIN' and 'RST' packets");
653  continue;
654  }
655  rte_flow_dynf_metadata_set(packets[i], 1);
656  packets[i]->ol_flags |= RTE_MBUF_DYNFLAG_TX_METADATA;
657  rte_eth_tx_burst(0, 0, &packets[i], 1);
658  }
659  ct_status->nb_processed = 0;
660 
661  return DOCA_SUCCESS;
662 }
663 
664 /*
665  * Print counters for all pipes
666  *
667  * @ct_queue [in]: DOCA Flow CT queue number
668  * @ct_pipe [in]: CT pipe
669  */
670 static doca_error_t print_pipe_counters(uint16_t ct_queue, struct doca_flow_pipe *ct_pipe)
671 {
672  struct doca_flow_resource_query query_stats, miss_stats;
674  uint64_t last_hit_time;
675  memset(&query_stats, 0, sizeof(query_stats));
676  memset(&miss_stats, 0, sizeof(miss_stats));
677 
678  printf("\n");
679  if (ct_entry) {
680  result = doca_flow_ct_query_entry(ct_queue,
681  ct_pipe,
683  ct_entry,
684  &query_stats,
685  &miss_stats,
686  &last_hit_time);
687  if (result != DOCA_SUCCESS) {
688  DOCA_LOG_ERR("Failed to query CT pipe counter: %s", doca_error_get_descr(result));
689  return result;
690  }
691  printf("CT pipe entry: origin_pkts=%ld reply_pkts=%ld\n",
692  query_stats.counter.total_pkts,
693  miss_stats.counter.total_pkts);
694  }
695 
697  if (result != DOCA_SUCCESS) {
698  DOCA_LOG_ERR("Failed to query TCP flags filter pipe counter: %s", doca_error_get_descr(result));
699  return result;
700  }
701  printf("Known packets TCP flags filter pipe pkts: %ld\n", query_stats.counter.total_pkts);
702 
704  if (result != DOCA_SUCCESS) {
705  DOCA_LOG_ERR("Failed to query CT miss pipe counter: %s", doca_error_get_descr(result));
706  return result;
707  }
708  printf("Unknown packets miss pipe pkts: %ld\n", query_stats.counter.total_pkts);
709 
711  if (result != DOCA_SUCCESS) {
712  DOCA_LOG_ERR("Failed to query RSS pipe counter: %s", doca_error_get_descr(result));
713  return result;
714  }
715  printf("RSS pipe pkts: %ld\n", query_stats.counter.total_pkts);
716 
718  if (result != DOCA_SUCCESS) {
719  DOCA_LOG_ERR("Failed to query Egress pipe counter: %s", doca_error_get_descr(result));
720  return result;
721  }
722  printf("Egress pipe pkts: %ld\n", query_stats.counter.total_pkts);
723  printf("\n");
724 
725  return DOCA_SUCCESS;
726 }
727 
728 /*
729  * Run flow_ct_tcp sample
730  *
731  * @nb_queues [in]: number of queues the sample will use
732  * @ct_dev [in]: Flow CT device
733  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
734  */
735 doca_error_t flow_ct_tcp_actions(uint16_t nb_queues, struct doca_dev *ct_dev)
736 {
737  const int nb_ports = 2, nb_entries = 7;
738  struct flow_resources resource;
739  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
740  struct doca_flow_pipe *egress_pipe, *ct_miss_pipe, *tcp_flags_filter_pipe, *rss_pipe, *root_pipe;
741  struct doca_flow_pipe *ct_pipe = NULL;
742  struct doca_flow_port *ports[nb_ports];
743  struct doca_flow_ct_actions shared_action;
744  struct doca_flow_meta o_zone_mask, o_modify_mask, r_zone_mask, r_modify_mask;
745  struct doca_dev *dev_arr[nb_ports];
746  uint32_t actions_mem_size[nb_ports];
747  struct entries_status ctrl_status, ct_status;
748  uint32_t ct_flags, nb_arm_queues = 1, nb_ctrl_queues = 1, nb_user_actions = 4096, nb_ipv4_sessions = 1024,
749  shared_action_handle, nb_ipv6_sessions = 0; /* On BF2 should always be 0 */
750  uint16_t ct_queue = nb_queues;
752 
753  memset(&ctrl_status, 0, sizeof(ctrl_status));
754  memset(&ct_status, 0, sizeof(ct_status));
755  memset(&resource, 0, sizeof(resource));
756  memset(&shared_action, 0, sizeof(shared_action));
757 
758  resource.nr_counters = NB_COUNTERS;
759 
760  result = init_doca_flow(nb_queues, "switch,hws", &resource, nr_shared_resources);
761  if (result != DOCA_SUCCESS) {
762  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
763  return result;
764  }
765 
766  /* Dont use zone masking */
767  memset(&o_zone_mask, 0, sizeof(o_zone_mask));
768  memset(&o_modify_mask, 0, sizeof(o_modify_mask));
769  memset(&r_zone_mask, 0, sizeof(r_zone_mask));
770  memset(&r_modify_mask, 0, sizeof(r_modify_mask));
771 
772  ct_flags = DOCA_FLOW_CT_FLAG_NO_AGING;
773  result = init_doca_flow_ct(ct_flags,
774  nb_arm_queues,
775  nb_ctrl_queues,
776  nb_user_actions,
777  NULL,
778  nb_ipv4_sessions,
779  nb_ipv6_sessions,
780  0,
781  false,
782  &o_zone_mask,
783  &o_modify_mask,
784  false,
785  &r_zone_mask,
786  &r_modify_mask);
787  if (result != DOCA_SUCCESS) {
789  return result;
790  }
791 
792  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
793  dev_arr[0] = ct_dev;
796  if (result != DOCA_SUCCESS) {
797  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
800  return result;
801  }
802 
803  result = create_rss_pipe(ports[0], &ctrl_status, &rss_pipe);
804  if (result != DOCA_SUCCESS)
805  goto cleanup;
806 
807  result = create_egress_pipe(ports[0], 1, &ctrl_status, &egress_pipe);
808  if (result != DOCA_SUCCESS)
809  goto cleanup;
810 
811  result = create_tcp_flags_filter_pipe(ports[0], &ctrl_status, egress_pipe, rss_pipe, &tcp_flags_filter_pipe);
812  if (result != DOCA_SUCCESS)
813  goto cleanup;
814 
815  result = create_ct_miss_pipe(ports[0], rss_pipe, &ctrl_status, &ct_miss_pipe);
816  if (result != DOCA_SUCCESS)
817  goto cleanup;
818 
819  result = create_ct_pipe(ports[0], tcp_flags_filter_pipe, ct_miss_pipe, &ct_pipe);
820  if (result != DOCA_SUCCESS)
821  goto cleanup;
822 
823  shared_action.data.action_idx = 0;
824  shared_action.data.meta.pkt_meta = DOCA_HTOBE32(1);
825  shared_action.data.meta.u32[0] = DOCA_HTOBE32(1);
826 
827  result = doca_flow_ct_actions_add_shared(ct_queue, ct_pipe, &shared_action, 1, &shared_action_handle);
828  if (result != DOCA_SUCCESS)
829  goto cleanup;
830 
831  result = create_ct_root_pipe(ports[0], true, false, DOCA_FLOW_L4_META_TCP, ct_pipe, &ctrl_status, &root_pipe);
832  if (result != DOCA_SUCCESS)
833  goto cleanup_shared_res;
834 
836  if (result != DOCA_SUCCESS) {
837  DOCA_LOG_ERR("Failed to process Flow CT entries: %s", doca_error_get_descr(result));
838  goto cleanup_shared_res;
839  }
840 
841  if (ctrl_status.nb_processed != nb_entries || ctrl_status.failure) {
842  DOCA_LOG_ERR("Failed to process entries");
844  goto cleanup_shared_res;
845  }
846 
847  DOCA_LOG_INFO("Wait few seconds for 'SYN' packet to arrive");
848 
849  sleep(5);
850  result = process_packets(ports[0], ct_queue, &ct_status, shared_action_handle, &ct_entry);
851  if (result != DOCA_SUCCESS)
852  goto dump;
853 
854  sleep(7);
855  process_packets(ports[0], ct_queue, &ct_status, shared_action_handle, &ct_entry);
857 
858 dump:
859  /* Print counters for all pipes */
860  print_pipe_counters(ct_queue, ct_pipe);
861 cleanup_shared_res:
862  doca_flow_ct_actions_rm_shared(ct_queue, ct_pipe, &shared_action_handle, 1);
863 cleanup:
864  cleanup_procedure(ct_pipe, nb_ports, ports);
865  return result;
866 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
struct doca_flow_port * init_doca_flow(uint16_t port_id, uint8_t rxq_num)
Definition: flow.c:37
static void cleanup(struct cache_invalidate_sample_state *state)
#define unlikely(x)
Definition: utils.h:42
doca_error_t init_doca_flow_ct(uint32_t flags, uint32_t nb_arm_queues, uint32_t nb_ctrl_queues, uint32_t nb_user_actions, doca_flow_ct_entry_finalize_cb entry_finalize_cb, uint32_t nb_ipv4_sessions, uint32_t nb_ipv6_sessions, uint32_t dup_filter_sz, bool o_match_inner, struct doca_flow_meta *o_zone_mask, struct doca_flow_meta *o_modify_mask, bool r_match_inner, struct doca_flow_meta *r_zone_mask, struct doca_flow_meta *r_modify_mask)
doca_error_t create_ct_root_pipe(struct doca_flow_port *port, bool is_ipv4, bool is_ipv6, enum doca_flow_l4_meta l4_type, struct doca_flow_pipe *fwd_pipe, struct entries_status *status, struct doca_flow_pipe **pipe)
void cleanup_procedure(struct doca_flow_pipe *ct_pipe, int nb_ports, struct doca_flow_port *ports[])
static struct doca_flow_pipe_entry * ct_miss_entry
doca_error_t flow_ct_tcp_actions(uint16_t nb_queues, struct doca_dev *ct_dev)
#define PACKET_BURST
DOCA_LOG_REGISTER(FLOW_CT_TCP)
static struct doca_flow_pipe_entry * ct_entry
static doca_error_t process_packets(struct doca_flow_port *port, uint16_t ct_queue, struct entries_status *ct_status, uint32_t shared_handle, struct doca_flow_pipe_entry **entry)
static doca_error_t create_ct_pipe(struct doca_flow_port *port, struct doca_flow_pipe *fwd_pipe, struct doca_flow_pipe *fwd_miss_pipe, struct doca_flow_pipe **pipe)
static struct doca_flow_pipe_entry * egress_entry
static struct doca_flow_pipe_entry * tcp_flags_filter_entry
static doca_error_t create_rss_pipe(struct doca_flow_port *port, struct entries_status *status, struct doca_flow_pipe **pipe)
static doca_error_t create_egress_pipe(struct doca_flow_port *port, int port_id, struct entries_status *status, struct doca_flow_pipe **pipe)
static doca_error_t create_ct_miss_pipe(struct doca_flow_port *port, struct doca_flow_pipe *fwd_pipe, struct entries_status *status, struct doca_flow_pipe **pipe)
static doca_error_t create_tcp_flags_filter_pipe(struct doca_flow_port *port, struct entries_status *status, struct doca_flow_pipe *fwd_pipe, struct doca_flow_pipe *fwd_miss_pipe, struct doca_flow_pipe **pipe)
#define NB_COUNTERS
static struct doca_flow_pipe_entry * rss_entry
static void parse_packet(struct rte_mbuf *packet, struct doca_flow_ct_match *match_o, struct doca_flow_ct_match *match_r, uint8_t *tcp_state)
static doca_error_t print_pipe_counters(uint16_t ct_queue, struct doca_flow_pipe *ct_pipe)
static uint16_t sessions
static int nb_entries
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static struct doca_flow_fwd fwd_miss
Definition: flow_parser.c:110
static uint16_t * rss_queues
Definition: flow_parser.c:114
static struct doca_flow_monitor monitor
Definition: flow_parser.c:108
static struct doca_flow_fwd fwd
Definition: flow_parser.c:109
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
#define DEFAULT_TIMEOUT_US
Definition: flow_skeleton.c:36
#define DOCA_HTOBE32(_x)
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_descr(doca_error_t error)
Returns the description string of an error code.
@ DOCA_ERROR_BAD_STATE
Definition: doca_error.h:56
@ DOCA_SUCCESS
Definition: doca_error.h:38
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_entries_process(struct doca_flow_port *port, uint16_t pipe_queue, uint32_t min_room, uint32_t max_processed_entries, uint32_t *queue_room)
Process CT entries in queue.
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_query_entry(uint16_t queue, struct doca_flow_pipe *pipe, uint32_t flags, struct doca_flow_pipe_entry *entry, struct doca_flow_resource_query *stats_origin, struct doca_flow_resource_query *stats_reply, uint64_t *last_hit_s)
Extract information about specific entry.
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_actions_add_shared(uint16_t ctrl_queue, struct doca_flow_pipe *pipe, const struct doca_flow_ct_actions actions[], uint32_t nb_actions, uint32_t actions_handles[])
Add shared modify-action.
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_add_entry(uint16_t queue, struct doca_flow_pipe *pipe, uint32_t flags, struct doca_flow_ct_match *match_origin, struct doca_flow_ct_match *match_reply, const struct doca_flow_ct_actions *actions_origin, const struct doca_flow_ct_actions *actions_reply, uint32_t fwd_handle_origin, uint32_t fwd_handle_reply, uint32_t timeout_s, void *usr_ctx, struct doca_flow_pipe_entry *entry)
Add new entry to doca flow CT pipe.
DOCA_EXPERIMENTAL void doca_flow_ct_destroy(void)
Destroy the doca flow ct.
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_actions_rm_shared(uint16_t ctrl_queue, struct doca_flow_pipe *pipe, uint32_t actions_handles[], uint32_t nb_actions)
Remove shared modify-action.
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_rm_entry(uint16_t queue, struct doca_flow_pipe *pipe, uint32_t flags, struct doca_flow_pipe_entry *entry)
remove CT entry.
DOCA_EXPERIMENTAL doca_error_t doca_flow_ct_entry_prepare(uint16_t queue, struct doca_flow_pipe *pipe, uint32_t flags, struct doca_flow_ct_match *match_origin, uint32_t hash_origin, struct doca_flow_ct_match *match_reply, uint32_t hash_reply, struct doca_flow_pipe_entry **entry, bool *conn_found)
Lookup recent CT entry and create on miss.
@ DOCA_FLOW_CT_ENTRY_FLAGS_COUNTER_REPLY
Definition: doca_flow_ct.h:677
@ DOCA_FLOW_CT_ENTRY_FLAGS_DIR_ORIGIN
Definition: doca_flow_ct.h:667
@ DOCA_FLOW_CT_ENTRY_FLAGS_NO_WAIT
Definition: doca_flow_ct.h:665
@ DOCA_FLOW_CT_ENTRY_FLAGS_DIR_REPLY
Definition: doca_flow_ct.h:669
@ DOCA_FLOW_CT_ENTRY_FLAGS_ALLOC_ON_MISS
Definition: doca_flow_ct.h:683
@ DOCA_FLOW_CT_ENTRY_FLAGS_COUNTER_ORIGIN
Definition: doca_flow_ct.h:675
@ DOCA_FLOW_CT_FLAG_NO_AGING
Definition: doca_flow_ct.h:58
#define DOCA_FLOW_PROTO_TCP
Definition: doca_flow_net.h:41
@ DOCA_FLOW_L4_TYPE_EXT_TCP
@ DOCA_FLOW_L4_TYPE_EXT_TRANSPORT
@ DOCA_FLOW_L3_TYPE_IP4
DOCA_STABLE doca_error_t doca_flow_pipe_cfg_destroy(struct doca_flow_pipe_cfg *cfg)
Destroy DOCA Flow pipe configuration struct.
DOCA_STABLE doca_error_t doca_flow_pipe_cfg_create(struct doca_flow_pipe_cfg **cfg, struct doca_flow_port *port)
Create DOCA Flow pipe configuration struct.
DOCA_STABLE doca_error_t doca_flow_entries_process(struct doca_flow_port *port, uint16_t pipe_queue, uint64_t timeout, uint32_t max_processed_entries)
Process entries in queue.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_cfg_set_match(struct doca_flow_pipe_cfg *cfg, const struct doca_flow_match *match, const struct doca_flow_match *match_mask)
Set pipe's match and match mask.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_create(const struct doca_flow_pipe_cfg *cfg, const struct doca_flow_fwd *fwd, const struct doca_flow_fwd *fwd_miss, struct doca_flow_pipe **pipe)
Create one new pipe.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_cfg_set_actions(struct doca_flow_pipe_cfg *cfg, struct doca_flow_actions *const *actions, struct doca_flow_actions *const *actions_masks, struct doca_flow_action_descs *const *action_descs, size_t nr_actions)
Set pipe's actions, actions mask and actions descriptor.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_cfg_set_monitor(struct doca_flow_pipe_cfg *cfg, const struct doca_flow_monitor *monitor)
Set pipe's monitor.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_add_entry(uint16_t pipe_queue, struct doca_flow_pipe *pipe, const struct doca_flow_match *match, const struct doca_flow_actions *actions, const struct doca_flow_monitor *monitor, const struct doca_flow_fwd *fwd, uint32_t flags, void *usr_ctx, struct doca_flow_pipe_entry **entry)
Add one new entry to a pipe.
DOCA_STABLE void doca_flow_destroy(void)
Destroy the doca flow.
DOCA_EXPERIMENTAL doca_error_t doca_flow_resource_query_entry(struct doca_flow_pipe_entry *entry, struct doca_flow_resource_query *query_stats)
Extract information about specific entry.
@ DOCA_FLOW_RSS_TCP
Definition: doca_flow.h:770
@ DOCA_FLOW_RSS_IPV4
Definition: doca_flow.h:764
@ DOCA_FLOW_PIPE_CT
Definition: doca_flow.h:227
@ DOCA_FLOW_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_MATCH_TCP_FLAG_FIN
Definition: doca_flow.h:403
@ DOCA_FLOW_MATCH_TCP_FLAG_RST
Definition: doca_flow.h:407
@ DOCA_FLOW_MATCH_TCP_FLAG_SYN
Definition: doca_flow.h:405
@ DOCA_FLOW_RESOURCE_TYPE_SHARED
Definition: doca_flow.h:614
@ DOCA_FLOW_RESOURCE_TYPE_NON_SHARED
Definition: doca_flow.h:615
@ DOCA_FLOW_FWD_PORT
Definition: doca_flow.h:744
@ DOCA_FLOW_FWD_PIPE
Definition: doca_flow.h:746
@ DOCA_FLOW_FWD_RSS
Definition: doca_flow.h:742
@ DOCA_FLOW_L4_META_TCP
Definition: doca_flow.h:308
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_WARN(format,...)
Generates a WARNING application log message.
Definition: doca_log.h:476
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
struct tcp_hdr l4_hdr
Definition: packets.h:2
doca_error_t init_doca_flow_ports(int nb_ports, struct doca_flow_port *ports[], bool is_hairpin, struct doca_dev *dev_arr[], uint32_t actions_mem_size[])
Definition: flow_common.c:296
doca_error_t set_flow_pipe_cfg(struct doca_flow_pipe_cfg *cfg, const char *name, enum doca_flow_pipe_type type, bool is_root)
Definition: flow_common.c:305
#define SHARED_RESOURCE_NUM_VALUES
Definition: flow_common.h:59
#define ACTIONS_MEM_SIZE(nr_queues, entries)
Definition: flow_common.h:66
#define ARRAY_INIT(array, val)
Definition: flow_common.h:71
doca flow actions information
Definition: doca_flow.h:684
struct doca_flow_header_format outer
Definition: doca_flow.h:703
struct doca_flow_meta meta
Definition: doca_flow.h:699
uint8_t action_idx
Definition: doca_flow.h:685
enum doca_flow_resource_type resource_type
Definition: doca_flow_ct.h:597
struct doca_flow_ct_actions::@121::@123 data
struct doca_flow_header_l4_port l4_port
Definition: doca_flow_ct.h:623
doca_be32_t src_ip
Definition: doca_flow_ct.h:625
doca_be32_t dst_ip
Definition: doca_flow_ct.h:627
doca flow CT match pattern
Definition: doca_flow_ct.h:654
struct doca_flow_ct_match4 ipv4
Definition: doca_flow_ct.h:656
forwarding configuration
Definition: doca_flow.h:779
struct doca_flow_pipe * next_pipe
Definition: doca_flow.h:800
uint16_t port_id
Definition: doca_flow.h:795
enum doca_flow_fwd_type type
Definition: doca_flow.h:780
enum doca_flow_resource_type rss_type
Definition: doca_flow.h:784
struct doca_flow_resource_rss_cfg rss
Definition: doca_flow.h:787
struct doca_flow_header_ip4 ip4
Definition: doca_flow.h:449
enum doca_flow_l4_type_ext l4_type_ext
Definition: doca_flow.h:454
struct doca_flow_header_l4_port transport
Definition: doca_flow.h:463
enum doca_flow_l3_type l3_type
Definition: doca_flow.h:446
struct doca_flow_header_tcp tcp
Definition: doca_flow.h:461
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_header_format outer
Definition: doca_flow.h:498
doca flow meta data
Definition: doca_flow.h:358
doca_be32_t pkt_meta
Definition: doca_flow.h:359
doca_be32_t u32[DOCA_FLOW_META_SCRATCH_PAD_MAX]
Definition: doca_flow.h:360
doca monitor action configuration
Definition: doca_flow.h:968
enum doca_flow_resource_type counter_type
Definition: doca_flow.h:988
flow resource query
Definition: doca_flow.h:1101
struct doca_flow_resource_query::@115::@117 counter
user context struct that will be used in entries process callback
Definition: flow_common.h:78
uint32_t nr_counters
Definition: flow_common.h:96
uint32_t src_addr
Definition: packets.h:75
uint32_t dst_addr
Definition: packets.h:76
uint16_t src_port
Definition: packets.h:80
uint8_t tcp_flags
Definition: packets.h:85
uint16_t dst_port
Definition: packets.h:81
static int nb_ports
Definition: switch_core.c:44
static uint32_t actions_mem_size[FLOW_SWITCH_PORTS_MAX]
Definition: switch_core.c:43
static struct doca_flow_port * ports[FLOW_SWITCH_PORTS_MAX]
Definition: switch_core.c:42