NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_ct_tcp_entry_finalize_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 
34 #include "flow_ct_common.h"
35 #include "flow_common.h"
36 
37 #define PACKET_BURST 128
38 #define DEFAULT_CNT_DELAY_S 2
39 #define DEFAULT_CNT_QUERY_INTERVAL 1
40 
41 DOCA_LOG_REGISTER(FLOW_CT_TCP_ENTRY_FINALIZE);
42 
44 static int nb_entries = 0;
45 
46 /*
47  * Create RSS pipe
48  *
49  * @port [in]: Pipe port
50  * @status [in]: user context for adding entry
51  * @pipe [out]: Created pipe pointer
52  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
53  */
54 static doca_error_t create_rss_pipe(struct doca_flow_port *port,
55  struct entries_status *status,
56  struct doca_flow_pipe **pipe)
57 {
58  struct doca_flow_match match;
59  struct doca_flow_pipe_cfg *cfg;
60  struct doca_flow_fwd fwd;
61  uint16_t rss_queues[1];
63 
64  memset(&match, 0, sizeof(match));
65  memset(&fwd, 0, sizeof(fwd));
66 
68  if (result != DOCA_SUCCESS) {
69  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
70  return result;
71  }
72 
73  result = set_flow_pipe_cfg(cfg, "RSS_PIPE", DOCA_FLOW_PIPE_BASIC, false);
74  if (result != DOCA_SUCCESS) {
75  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
76  goto destroy_pipe_cfg;
77  }
79  if (result != DOCA_SUCCESS) {
80  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
81  goto destroy_pipe_cfg;
82  }
83 
84  /* RSS queue - send matched traffic to queue 0 */
85  rss_queues[0] = 0;
90  fwd.rss.nr_queues = 1;
91 
93  if (result != DOCA_SUCCESS) {
94  DOCA_LOG_ERR("Failed to create RSS pipe: %s", doca_error_get_descr(result));
95  goto destroy_pipe_cfg;
96  }
98 
99  /* Match on any packet */
100  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, &fwd, 0, status, NULL);
101  if (result != DOCA_SUCCESS) {
102  DOCA_LOG_ERR("Failed to add RSS pipe entry: %s", doca_error_get_descr(result));
103  return result;
104  }
105 
107  if (result != DOCA_SUCCESS)
108  DOCA_LOG_ERR("Failed to process RSS entry: %s", doca_error_get_descr(result));
109 
110  return result;
111 
114  return result;
115 }
116 
117 /*
118  * Create egress pipe
119  *
120  * @port [in]: Pipe port
121  * @port_id [in]: Next pipe port id
122  * @status [in]: user context for adding entry
123  * @pipe [out]: Created pipe pointer
124  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
125  */
126 static doca_error_t create_egress_pipe(struct doca_flow_port *port,
127  int port_id,
128  struct entries_status *status,
129  struct doca_flow_pipe **pipe)
130 {
131  struct doca_flow_match match;
132  struct doca_flow_pipe_cfg *cfg;
133  struct doca_flow_fwd fwd;
135 
136  memset(&match, 0, sizeof(match));
137  memset(&fwd, 0, sizeof(fwd));
138 
140  if (result != DOCA_SUCCESS) {
141  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
142  return result;
143  }
144 
145  result = set_flow_pipe_cfg(cfg, "EGRESS_PIPE", DOCA_FLOW_PIPE_BASIC, false);
146  if (result != DOCA_SUCCESS) {
147  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
148  goto destroy_pipe_cfg;
149  }
151  if (result != DOCA_SUCCESS) {
152  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
153  goto destroy_pipe_cfg;
154  }
155 
157  fwd.port_id = port_id;
158 
160  if (result != DOCA_SUCCESS) {
161  DOCA_LOG_ERR("Failed to create EGRESS pipe: %s", doca_error_get_descr(result));
162  goto destroy_pipe_cfg;
163  }
165 
166  /* Match on any packet */
167  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, &fwd, 0, status, NULL);
168  if (result != DOCA_SUCCESS) {
169  DOCA_LOG_ERR("Failed to add EGRESS pipe entry: %s", doca_error_get_descr(result));
170  return result;
171  }
172 
174  if (result != DOCA_SUCCESS)
175  DOCA_LOG_ERR("Failed to process EGRESS entry: %s", doca_error_get_descr(result));
176 
177  return result;
178 
181  return result;
182 }
183 
184 /*
185  * Create CT miss pipe
186  *
187  * @port [in]: Pipe port
188  * @fwd_pipe [in]: Forward pipe pointer
189  * @status [in]: user context for adding entry
190  * @pipe [out]: Created pipe pointer
191  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
192  */
193 static doca_error_t create_ct_miss_pipe(struct doca_flow_port *port,
194  struct doca_flow_pipe *fwd_pipe,
195  struct entries_status *status,
196  struct doca_flow_pipe **pipe)
197 {
198  struct doca_flow_match match;
199  struct doca_flow_pipe_cfg *cfg;
200  struct doca_flow_fwd fwd;
201  struct doca_flow_fwd fwd_miss;
203 
204  memset(&match, 0, sizeof(match));
205  memset(&fwd, 0, sizeof(fwd));
206  memset(&fwd_miss, 0, sizeof(fwd));
207 
209  if (result != DOCA_SUCCESS) {
210  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
211  return result;
212  }
213 
214  result = set_flow_pipe_cfg(cfg, "CT_MISS_PIPE", DOCA_FLOW_PIPE_BASIC, false);
215  if (result != DOCA_SUCCESS) {
216  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
217  goto destroy_pipe_cfg;
218  }
220  if (result != DOCA_SUCCESS) {
221  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
222  goto destroy_pipe_cfg;
223  }
224 
226  fwd.next_pipe = fwd_pipe;
227 
229  fwd_miss.next_pipe = fwd_pipe;
230 
232  if (result != DOCA_SUCCESS) {
233  DOCA_LOG_ERR("Failed to create CT miss pipe: %s", doca_error_get_descr(result));
234  goto destroy_pipe_cfg;
235  }
237 
238  /* Match on any packet */
239  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, &fwd, 0, status, NULL);
240  if (result != DOCA_SUCCESS) {
241  DOCA_LOG_ERR("Failed to add CT miss pipe entry: %s", doca_error_get_descr(result));
242  return result;
243  }
244 
246  if (result != DOCA_SUCCESS)
247  DOCA_LOG_ERR("Failed to process CT miss entry: %s", doca_error_get_descr(result));
248 
249  return result;
250 
253  return result;
254 }
255 
256 /*
257  * Create DOCA Flow TCP state pipe to filter state on known TCP session
258  *
259  * @port [in]: Pipe port
260  * @status [in]: User context for adding entry
261  * @fwd_pipe [in]: Forward pipe
262  * @fwd_miss_pipe [in]: Forward miss pipe
263  * @pipe [out]: Created pipe pointer
264  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
265  */
266 static doca_error_t create_tcp_flags_filter_pipe(struct doca_flow_port *port,
267  struct entries_status *status,
268  struct doca_flow_pipe *fwd_pipe,
269  struct doca_flow_pipe *fwd_miss_pipe,
270  struct doca_flow_pipe **pipe)
271 {
272  struct doca_flow_match match;
273  struct doca_flow_match mask;
274  struct doca_flow_fwd fwd;
275  struct doca_flow_fwd fwd_miss;
276  struct doca_flow_pipe_cfg *cfg;
278 
279  memset(&match, 0, sizeof(match));
280  memset(&mask, 0, sizeof(mask));
281  memset(&fwd, 0, sizeof(fwd));
282  memset(&fwd_miss, 0, sizeof(fwd_miss));
283 
284  /* Match on non SYN, FIN and RST packets */
285  match.outer.tcp.flags = 0xff;
287 
291 
293  if (result != DOCA_SUCCESS) {
294  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
295  return result;
296  }
297 
298  result = set_flow_pipe_cfg(cfg, "TCP_FLAGS_FILTER_PIPE", DOCA_FLOW_PIPE_BASIC, false);
299  if (result != DOCA_SUCCESS) {
300  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
301  goto destroy_pipe_cfg;
302  }
303  result = doca_flow_pipe_cfg_set_match(cfg, &match, &mask);
304  if (result != DOCA_SUCCESS) {
305  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
306  goto destroy_pipe_cfg;
307  }
308 
310  fwd.next_pipe = fwd_pipe;
311 
313  fwd_miss.next_pipe = fwd_miss_pipe;
314 
316  if (result != DOCA_SUCCESS) {
317  DOCA_LOG_ERR("Failed to create TCP_FLAGS_FILTER pipe: %s", doca_error_get_descr(result));
318  goto destroy_pipe_cfg;
319  }
321 
322  match.outer.tcp.flags = 0;
323  result = doca_flow_pipe_add_entry(0, *pipe, &match, NULL, NULL, NULL, 0, status, NULL);
324  if (result != DOCA_SUCCESS) {
325  DOCA_LOG_ERR("Failed to create TCP flags filter pipe entry: %s", doca_error_get_descr(result));
326  return result;
327  }
328 
330  if (result != DOCA_SUCCESS)
331  DOCA_LOG_ERR("Failed to process TCP flags filter entry: %s", doca_error_get_descr(result));
332 
333  return result;
334 
337  return result;
338 }
339 
340 /*
341  * Create CT pipe
342  *
343  * @port [in]: Pipe port
344  * @fwd_pipe [in]: Forward pipe pointer
345  * @fwd_miss_pipe [in]: Forward miss pipe pointer
346  * @pipe [out]: Created pipe pointer
347  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
348  */
349 static doca_error_t create_ct_pipe(struct doca_flow_port *port,
350  struct doca_flow_pipe *fwd_pipe,
351  struct doca_flow_pipe *fwd_miss_pipe,
352  struct doca_flow_pipe **pipe)
353 {
354  struct doca_flow_match match;
355  struct doca_flow_pipe_cfg *cfg;
356  struct doca_flow_fwd fwd;
357  struct doca_flow_fwd fwd_miss;
359 
360  memset(&match, 0, sizeof(match));
361  memset(&fwd, 0, sizeof(fwd));
362  memset(&fwd_miss, 0, sizeof(fwd));
363 
365  if (result != DOCA_SUCCESS) {
366  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
367  return result;
368  }
369 
370  result = set_flow_pipe_cfg(cfg, "CT_PIPE", DOCA_FLOW_PIPE_CT, false);
371  if (result != DOCA_SUCCESS) {
372  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
373  goto destroy_pipe_cfg;
374  }
376  if (result != DOCA_SUCCESS) {
377  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
378  goto destroy_pipe_cfg;
379  }
380 
382  fwd.next_pipe = fwd_pipe;
383 
385  fwd_miss.next_pipe = fwd_miss_pipe;
386 
388  if (result != DOCA_SUCCESS)
389  DOCA_LOG_ERR("Failed to create CT pipe: %s", doca_error_get_descr(result));
392  return result;
393 }
394 
395 /*
396  * Parse TCP packet to update CT tables
397  *
398  * @packet [in]: Packet to parse
399  * @match_o [out]: Origin match struct to fill
400  * @match_r [out]: Reply match struct to fill
401  * @tcp_state [out]: Packet TCP state
402  */
403 static void parse_packet(struct rte_mbuf *packet,
404  struct doca_flow_ct_match *match_o,
405  struct doca_flow_ct_match *match_r,
406  uint8_t *tcp_state)
407 {
408  uint8_t *l4_hdr;
409  struct rte_ipv4_hdr *ipv4_hdr;
410  const struct rte_tcp_hdr *tcp_hdr;
411 
412  ipv4_hdr = rte_pktmbuf_mtod_offset(packet, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
413 
414  match_o->ipv4.src_ip = ipv4_hdr->src_addr;
415  match_o->ipv4.dst_ip = ipv4_hdr->dst_addr;
416  match_r->ipv4.src_ip = match_o->ipv4.dst_ip;
417  match_r->ipv4.dst_ip = match_o->ipv4.src_ip;
418 
419  l4_hdr = (typeof(l4_hdr))ipv4_hdr + rte_ipv4_hdr_len(ipv4_hdr);
420  tcp_hdr = (typeof(tcp_hdr))l4_hdr;
421 
422  match_o->ipv4.l4_port.src_port = tcp_hdr->src_port;
423  match_o->ipv4.l4_port.dst_port = tcp_hdr->dst_port;
424  match_r->ipv4.l4_port.src_port = match_o->ipv4.l4_port.dst_port;
425  match_r->ipv4.l4_port.dst_port = match_o->ipv4.l4_port.src_port;
426 
429 
430  *tcp_state = tcp_hdr->tcp_flags;
431 }
432 
433 /*
434  * Dequeue 'SYN' packets from DPDK queues, parse and update CT tables with new connection 5 tuple
435  *
436  * @port [in]: Port id to which an entry should be inserted
437  * @ct_queue [in]: DOCA Flow CT queue number
438  * @ct_status [in]: User context for adding CT entry
439  * @entry [in/out]: CT entry
440  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
441  */
442 static doca_error_t process_syn_packets(struct doca_flow_port *port,
443  uint16_t ct_queue,
444  struct entries_status *ct_status,
445  struct doca_flow_pipe_entry **entry)
446 {
447  struct rte_mbuf *packets[PACKET_BURST];
448  struct doca_flow_ct_match match_o;
449  struct doca_flow_ct_match match_r;
453  uint8_t tcp_state;
455  int rc, i, nb_packets, nb_process = 0;
456 
457  memset(&match_o, 0, sizeof(match_o));
458  memset(&match_r, 0, sizeof(match_r));
459 
460  rc = rte_flow_dynf_metadata_register();
461  if (unlikely(rc)) {
462  DOCA_LOG_ERR("Enable metadata failed");
463  return DOCA_ERROR_BAD_STATE;
464  }
465 
466  nb_packets = rte_eth_rx_burst(0, 0, packets, PACKET_BURST);
467  if (nb_packets == 0) {
468  DOCA_LOG_INFO("Sample didn't receive packets to process");
469  return DOCA_ERROR_BAD_STATE;
470  }
471 
472  DOCA_LOG_INFO("%d packets received on rx_burst()", nb_packets);
473  for (i = 0; i < PACKET_BURST && i < nb_packets; i++) {
474  parse_packet(packets[i], &match_o, &match_r, &tcp_state);
475  if (tcp_state & DOCA_FLOW_MATCH_TCP_FLAG_SYN) {
476  if (nb_entries > 0) {
477  DOCA_LOG_INFO("Already have one entry, skip");
478  continue;
479  }
480  /* Allocate CT entry */
482  NULL,
484  &match_o,
485  0,
486  &match_r,
487  0,
488  entry,
489  NULL);
490  if (result != DOCA_SUCCESS) {
491  DOCA_LOG_ERR("Failed to prepare CT entry\n");
492  return result;
493  }
494  result = doca_flow_ct_add_entry(ct_queue,
495  NULL,
496  flags,
497  &match_o,
498  &match_r,
499  0,
500  0,
501  0,
502  0,
503  0,
504  ct_status,
505  *entry);
506  if (result != DOCA_SUCCESS) {
507  DOCA_LOG_ERR("Failed to add CT pipe an entry: %s", doca_error_get_descr(result));
508  return result;
509  }
510  nb_entries++;
511  nb_process++;
512  while (ct_status->nb_processed != nb_process) {
513  result = doca_flow_ct_entries_process(port, ct_queue, 0, 0, NULL);
514  if (result != DOCA_SUCCESS) {
515  DOCA_LOG_ERR("Failed to process Flow CT entries: %s",
517  return result;
518  }
519 
520  if (ct_status->failure) {
521  DOCA_LOG_ERR("Flow CT entries process returned with a failure");
522  return DOCA_ERROR_BAD_STATE;
523  }
524  }
525  rte_flow_dynf_metadata_set(packets[i], 1);
526  packets[i]->ol_flags |= RTE_MBUF_DYNFLAG_TX_METADATA;
527  rte_eth_tx_burst(0, 0, &packets[i], 1);
528  } else {
529  DOCA_LOG_WARN("Sample is only able to process 'SYN' packets at first phase");
530  continue;
531  }
532  }
533  ct_status->nb_processed = 0;
534 
535  return DOCA_SUCCESS;
536 }
537 
538 /*
539  * Dequeue 'FIN' and 'RST' packets from DPDK queues to remove entries
540  *
541  * @port [in]: Port id to which an entry should be inserted
542  * @ct_queue [in]: DOCA Flow CT queue number
543  * @entry [in/out]: CT entry
544  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
545  */
546 static doca_error_t process_fin_packets(struct doca_flow_port *port,
547  uint16_t ct_queue,
548  struct doca_flow_pipe_entry **entry)
549 {
550  struct rte_mbuf *packets[PACKET_BURST];
551  struct doca_flow_ct_match match_o;
552  struct doca_flow_ct_match match_r;
553  uint32_t flags = DOCA_FLOW_CT_ENTRY_FLAGS_NO_WAIT;
554  uint8_t tcp_state;
556  int rc, i, nb_packets, nb_process = 0;
557 
558  memset(&match_o, 0, sizeof(match_o));
559  memset(&match_r, 0, sizeof(match_r));
560 
561  rc = rte_flow_dynf_metadata_register();
562  if (unlikely(rc)) {
563  DOCA_LOG_ERR("Enable metadata failed");
564  return DOCA_ERROR_BAD_STATE;
565  }
566 
567  nb_packets = rte_eth_rx_burst(0, 0, packets, PACKET_BURST);
568  if (nb_packets == 0) {
569  DOCA_LOG_INFO("Sample didn't receive packets to process");
570  return DOCA_ERROR_BAD_STATE;
571  }
572 
573  DOCA_LOG_INFO("%d packets received on rx_burst()", nb_packets);
574  for (i = 0; i < PACKET_BURST && i < nb_packets; i++) {
575  parse_packet(packets[i], &match_o, &match_r, &tcp_state);
576  if (tcp_state & DOCA_FLOW_MATCH_TCP_FLAG_FIN || tcp_state & DOCA_FLOW_MATCH_TCP_FLAG_RST) {
577  if (nb_entries == 0) {
578  DOCA_LOG_INFO("No entry to remove, skip");
579  continue;
580  }
581  result = doca_flow_ct_rm_entry(ct_queue, NULL, flags, *entry);
582  if (result != DOCA_SUCCESS) {
583  DOCA_LOG_ERR("Failed to remove CT pipe entry: %s", doca_error_get_descr(result));
584  return result;
585  }
586  nb_process++;
587  while (nb_entry_finalize_triggers != nb_process) {
588  result = doca_flow_ct_entries_process(port, ct_queue, 0, 0, NULL);
589  if (result != DOCA_SUCCESS) {
590  DOCA_LOG_ERR("Failed to process Flow CT entries: %s",
592  return result;
593  }
594  (void)doca_flow_aging_handle(port, ct_queue, 0, 0);
595  }
596  nb_entries--;
597  DOCA_LOG_INFO("TCP session was ended");
598  rte_flow_dynf_metadata_set(packets[i], 1);
599  packets[i]->ol_flags |= RTE_MBUF_DYNFLAG_TX_METADATA;
600  rte_eth_tx_burst(0, 0, &packets[i], 1);
601  } else {
602  DOCA_LOG_WARN("Sample is only able to process 'FIN' and 'RST' packets at second phase");
603  continue;
604  }
605  }
606 
607  return DOCA_SUCCESS;
608 }
609 
610 /*
611  * CT entry_finalize callback
612  *
613  * @pipe [in]: Not being used
614  * @entry [in]: DOCA Flow CT entry
615  * @ct_queue [in]: DOCA Flow CT queue number
616  * @usr_ctx [in]: Usr context
617  */
618 static void entry_finalize_cb(struct doca_flow_pipe *pipe, void *entry, uint16_t ct_queue, void *usr_ctx)
619 {
620  (void)usr_ctx;
621  uint64_t entry_flags, last_hit_s;
622  struct doca_flow_ct_match match_o, match_r;
623  struct doca_flow_resource_query query_o, query_r;
625 
626  result = doca_flow_ct_get_entry(ct_queue, pipe, 0, entry, &match_o, &match_r, &entry_flags);
627  if (result != DOCA_SUCCESS) {
628  DOCA_LOG_ERR("Failed to get CT entry information: %s", doca_error_get_descr(result));
629  return;
630  }
631 
633 
634  DOCA_LOG_INFO("Entry finalize callback triggered on entry %d, origin: 0x%08x:0x%x -> 0x%08x:0x%x",
636  be32toh(match_o.ipv4.src_ip),
637  match_o.ipv4.l4_port.src_port,
638  be32toh(match_o.ipv4.dst_ip),
639  match_o.ipv4.l4_port.dst_port);
640 
641  result = doca_flow_ct_query_entry(ct_queue, pipe, 0, entry, &query_o, &query_r, &last_hit_s);
642  if (result != DOCA_SUCCESS) {
643  DOCA_LOG_ERR("Failed to query CT entry: %s", doca_error_get_descr(result));
644  return;
645  }
646 
647  DOCA_LOG_INFO("Entry %d, origin total bytes: %ld", nb_entry_finalize_triggers, query_o.counter.total_bytes);
648  DOCA_LOG_INFO("Entry %d, origin total packets: %ld", nb_entry_finalize_triggers, query_o.counter.total_pkts);
649  DOCA_LOG_INFO("Entry %d, last hit since Epoch (sec) : %ld", nb_entry_finalize_triggers, last_hit_s);
650 }
651 
652 /*
653  * Run flow_ct_tcp_entry_finalize sample
654  *
655  * @nb_queues [in]: number of queues the sample will use
656  * @ct_dev [in]: Flow CT device
657  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
658  */
659 doca_error_t flow_ct_tcp_entry_finalize(uint16_t nb_queues, struct doca_dev *ct_dev)
660 {
661  const int nb_ports = 2, nb_entries = 7;
662  struct flow_resources resource;
663  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
664  struct doca_flow_pipe_entry *tcp_entry;
665  struct doca_flow_pipe *egress_pipe, *ct_miss_pipe, *tcp_flags_filter_pipe, *rss_pipe, *tcp_pipe;
666  struct doca_flow_pipe *ct_pipe = NULL;
667  struct doca_flow_port *ports[nb_ports];
668  struct doca_flow_meta o_zone_mask, o_modify_mask, r_zone_mask, r_modify_mask;
669  struct doca_dev *dev_arr[nb_ports];
670  uint32_t actions_mem_size[nb_ports];
671  struct entries_status ctrl_status, ct_status;
672  uint32_t ct_flags = 0, nb_arm_queues = 1, nb_ctrl_queues = 1, nb_user_actions = 0, nb_ipv4_sessions = 1024,
673  nb_ipv6_sessions = 0; /* On BF2 should always be 0 */
674  uint16_t ct_queue = nb_queues;
676 
677  memset(&ctrl_status, 0, sizeof(ctrl_status));
678  memset(&ct_status, 0, sizeof(ct_status));
679  memset(&resource, 0, sizeof(resource));
680 
681  resource.nr_counters = 1;
682 
683  result = init_doca_flow(nb_queues, "switch,hws", &resource, nr_shared_resources);
684  if (result != DOCA_SUCCESS) {
685  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
686  return result;
687  }
688 
689  /* Dont use zone masking */
690  memset(&o_zone_mask, 0, sizeof(o_zone_mask));
691  memset(&o_modify_mask, 0, sizeof(o_modify_mask));
692  memset(&r_zone_mask, 0, sizeof(r_zone_mask));
693  memset(&r_modify_mask, 0, sizeof(r_modify_mask));
694 
695  result = init_doca_flow_ct(ct_flags,
696  nb_arm_queues,
697  nb_ctrl_queues,
698  nb_user_actions,
700  nb_ipv4_sessions,
701  nb_ipv6_sessions,
702  0,
703  false,
704  &o_zone_mask,
705  &o_modify_mask,
706  false,
707  &r_zone_mask,
708  &r_modify_mask);
709  if (result != DOCA_SUCCESS) {
711  return result;
712  }
713 
714  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
715  dev_arr[0] = ct_dev;
718  if (result != DOCA_SUCCESS) {
719  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
722  return result;
723  }
724 
725  result = create_rss_pipe(ports[0], &ctrl_status, &rss_pipe);
726  if (result != DOCA_SUCCESS)
727  goto cleanup;
728 
729  result = create_egress_pipe(ports[0], 1, &ctrl_status, &egress_pipe);
730  if (result != DOCA_SUCCESS)
731  goto cleanup;
732 
733  result = create_tcp_flags_filter_pipe(ports[0], &ctrl_status, egress_pipe, rss_pipe, &tcp_flags_filter_pipe);
734  if (result != DOCA_SUCCESS)
735  goto cleanup;
736 
737  result = create_ct_miss_pipe(ports[0], rss_pipe, &ctrl_status, &ct_miss_pipe);
738  if (result != DOCA_SUCCESS)
739  goto cleanup;
740 
741  result = create_ct_pipe(ports[0], tcp_flags_filter_pipe, ct_miss_pipe, &ct_pipe);
742  if (result != DOCA_SUCCESS)
743  goto cleanup;
744 
745  result = create_ct_root_pipe(ports[0], true, false, DOCA_FLOW_L4_META_TCP, ct_pipe, &ctrl_status, &tcp_pipe);
746  if (result != DOCA_SUCCESS)
747  goto cleanup;
748 
750  if (result != DOCA_SUCCESS) {
751  DOCA_LOG_ERR("Failed to process Flow CT entries: %s", doca_error_get_descr(result));
752  goto cleanup;
753  }
754 
755  if (ctrl_status.nb_processed != nb_entries || ctrl_status.failure) {
756  DOCA_LOG_ERR("Failed to process entries");
758  goto cleanup;
759  }
760 
761  DOCA_LOG_INFO("Wait few seconds for 'SYN' packet to arrive");
762 
763  sleep(5);
764  result = process_syn_packets(ports[0], ct_queue, &ct_status, &tcp_entry);
765  if (result != DOCA_SUCCESS)
766  goto cleanup;
767 
769  DOCA_LOG_INFO("TCP session was created, waiting for 'FIN'/'RST' packet before ending the session");
770 
771  sleep(7);
772  result = process_fin_packets(ports[0], ct_queue, &tcp_entry);
773  if (result != DOCA_SUCCESS)
774  goto cleanup;
775 
776 cleanup:
777  cleanup_procedure(ct_pipe, nb_ports, ports);
778  return result;
779 }
#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 int nb_entries
static doca_error_t process_syn_packets(struct doca_flow_port *port, uint16_t ct_queue, struct entries_status *ct_status, struct doca_flow_pipe_entry **entry)
static void entry_finalize_cb(struct doca_flow_pipe *pipe, void *entry, uint16_t ct_queue, void *usr_ctx)
#define PACKET_BURST
DOCA_LOG_REGISTER(FLOW_CT_TCP_ENTRY_FINALIZE)
static doca_error_t process_fin_packets(struct doca_flow_port *port, uint16_t ct_queue, 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 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)
doca_error_t flow_ct_tcp_entry_finalize(uint16_t nb_queues, struct doca_dev *ct_dev)
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)
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)
#define DEFAULT_CNT_QUERY_INTERVAL
static int nb_entry_finalize_triggers
#define DEFAULT_CNT_DELAY_S
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_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
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_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_get_entry(uint16_t queue, struct doca_flow_pipe *pipe, uint32_t flags, struct doca_flow_pipe_entry *entry, struct doca_flow_ct_match *match_origin, struct doca_flow_ct_match *match_reply, uint64_t *entry_flags)
Get CT entry match pattern.
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_ALLOC_ON_MISS
Definition: doca_flow_ct.h:683
@ DOCA_FLOW_CT_ENTRY_FLAGS_ENTRY_FINALIZE
Definition: doca_flow_ct.h:681
@ DOCA_FLOW_CT_ENTRY_FLAGS_COUNTER_ORIGIN
Definition: doca_flow_ct.h:675
#define DOCA_FLOW_PROTO_TCP
Definition: doca_flow_net.h:41
@ DOCA_FLOW_L4_TYPE_EXT_TCP
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_STABLE int doca_flow_aging_handle(struct doca_flow_port *port, uint16_t queue, uint64_t quota, uint64_t max_entries)
Handle aging of entries.
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_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_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
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
struct doca_flow_pipe * pipe
Definition: doca_flow.h:806
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
enum doca_flow_l4_type_ext l4_type_ext
Definition: doca_flow.h:454
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
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