NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_ip_in_ip_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2025 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 <stdint.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <arpa/inet.h>
30 
31 #include "doca_types.h"
32 #include <doca_log.h>
33 #include <doca_bitfield.h>
34 
35 #include "doca_flow.h"
36 #include "doca_flow_net.h"
37 
38 #include "flow_common.h"
39 
40 DOCA_LOG_REGISTER(FLOW_IP_IN_IP);
41 
42 /* The number of seconds app waits for traffic to come */
43 #define WAITING_TIME 10
44 
45 #define NB_ENCAP_ACTIONS (2)
46 #define NB_DECAP_ACTIONS (1)
47 
48 #define NB_HAIRPIN_PIPE_ENTRIES (1)
49 #define NB_ENCAP_PIPE_ENTRIES (2)
50 #define NB_DECAP_PIPE_ENTRIES (2)
51 #define NB_INGRESS_PIPE_ENTRIES (NB_HAIRPIN_PIPE_ENTRIES + NB_DECAP_PIPE_ENTRIES)
52 #define NB_EGRESS_PIPE_ENTRIES (NB_ENCAP_PIPE_ENTRIES)
53 #define TOTAL_ENTRIES (NB_INGRESS_PIPE_ENTRIES + NB_EGRESS_PIPE_ENTRIES)
54 
55 #define NEXT_HEADER_IPV4 (4)
56 #define NEXT_HEADER_IPV6 (41)
57 
58 /*
59  * Create DOCA Flow ingress pipe with transport layer match and set pkt meta value.
60  *
61  * @port [in]: port of the pipe.
62  * @dest_port_id [in]: port ID of the pipe.
63  * @is_root [in]: whether this is the root pipe for the port
64  * @status [in]: user context for adding entries.
65  * @nb_entries [out]: pointer to put into number of entries.
66  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
67  */
68 static doca_error_t create_hairpin_pipe(struct doca_flow_port *port,
69  int dest_port_id,
70  bool is_root,
71  struct entries_status *status,
72  struct doca_flow_pipe **pipe)
73 {
74  struct doca_flow_pipe_entry *entry;
75  struct doca_flow_match match;
76  struct doca_flow_actions actions, *actions_arr[NB_ACTIONS_ARR];
77  struct doca_flow_fwd fwd;
78  struct doca_flow_pipe_cfg *pipe_cfg;
79  enum doca_flow_flags_type flags;
81 
82  memset(&match, 0, sizeof(match));
83  memset(&actions, 0, sizeof(actions));
84  memset(&fwd, 0, sizeof(fwd));
85 
86  actions_arr[0] = &actions;
87 
88  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
89  if (result != DOCA_SUCCESS) {
90  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
91  return result;
92  }
93 
94  result = set_flow_pipe_cfg(pipe_cfg, "HAIRPIN_PIPE", DOCA_FLOW_PIPE_BASIC, is_root);
95  if (result != DOCA_SUCCESS) {
96  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
97  goto destroy_pipe_cfg;
98  }
100  if (result != DOCA_SUCCESS) {
101  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg domain: %s", doca_error_get_descr(result));
102  goto destroy_pipe_cfg;
103  }
105  if (result != DOCA_SUCCESS) {
106  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
107  goto destroy_pipe_cfg;
108  }
109  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
110  if (result != DOCA_SUCCESS) {
111  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
112  goto destroy_pipe_cfg;
113  }
114  result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_ACTIONS_ARR);
115  if (result != DOCA_SUCCESS) {
116  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
117  goto destroy_pipe_cfg;
118  }
119 
120  /* Forwarding traffic to other port */
122  fwd.port_id = dest_port_id;
123 
124  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
125  if (result != DOCA_SUCCESS) {
126  DOCA_LOG_ERR("Failed to create hairpin pipe: %s", doca_error_get_descr(result));
127  goto destroy_pipe_cfg;
128  }
129  doca_flow_pipe_cfg_destroy(pipe_cfg);
130 
131  flags = DOCA_FLOW_NO_WAIT;
132  result = doca_flow_pipe_add_entry(0, *pipe, &match, &actions, NULL, NULL, flags, status, &entry);
133  if (result != DOCA_SUCCESS) {
134  DOCA_LOG_ERR("Failed to add hairpin entry: %s", doca_error_get_descr(result));
135  return result;
136  }
137 
138  return DOCA_SUCCESS;
139 
141  doca_flow_pipe_cfg_destroy(pipe_cfg);
142  return result;
143 }
144 
145 /*
146  * Add DOCA Flow pipe entries with example encap values.
147  *
148  * @pipe [in]: pipe of the entry
149  * @status [in]: user context for adding entry
150  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
151  */
152 static doca_error_t add_encap_pipe_entries(struct doca_flow_pipe *pipe,
153  struct entries_status *status,
154  struct doca_flow_pipe_entry *encap_entries[])
155 {
156  struct doca_flow_match match;
157  struct doca_flow_actions actions;
159 
160  /* The mac address and IPv6 address digits are reversed for the inner-type=IPv6 case */
161  uint8_t smac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
162  uint8_t dmac[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
163  doca_be32_t ipv6_src[] = {htobe32(0x11115555), htobe32(0x22226666), htobe32(0x33337777), htobe32(0x44448888)};
164  doca_be32_t ipv6_dst[] = {htobe32(0xaaaaeeee), htobe32(0xbbbbffff), htobe32(0xcccc0000), htobe32(0xdddd9999)};
165 
166  memset(&match, 0, sizeof(match));
167  memset(&actions, 0, sizeof(actions));
168 
170  actions.action_idx = 0;
171  SET_MAC_ADDR(actions.encap_cfg.encap.outer.eth.src_mac, smac[0], smac[1], smac[2], smac[3], smac[4], smac[5]);
172  SET_MAC_ADDR(actions.encap_cfg.encap.outer.eth.dst_mac, dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);
173  SET_IPV6_ADDR(actions.encap_cfg.encap.outer.ip6.src_ip, ipv6_src[0], ipv6_src[1], ipv6_src[2], ipv6_src[3]);
174  SET_IPV6_ADDR(actions.encap_cfg.encap.outer.ip6.dst_ip, ipv6_dst[0], ipv6_dst[1], ipv6_dst[2], ipv6_dst[3]);
175 
176  result = doca_flow_pipe_add_entry(0, pipe, &match, &actions, NULL, NULL, 0, status, &encap_entries[0]);
177  if (result != DOCA_SUCCESS) {
178  DOCA_LOG_ERR("Failed to add entry matching on ipv4: %s", doca_error_get_descr(result));
179  return result;
180  }
181 
183  actions.action_idx = 1;
184  SET_MAC_ADDR(actions.encap_cfg.encap.outer.eth.src_mac, smac[5], smac[4], smac[3], smac[2], smac[1], smac[0]);
185  SET_MAC_ADDR(actions.encap_cfg.encap.outer.eth.dst_mac, dmac[5], dmac[4], dmac[3], dmac[2], dmac[1], dmac[0]);
186  SET_IPV6_ADDR(actions.encap_cfg.encap.outer.ip6.src_ip, ipv6_src[3], ipv6_src[2], ipv6_src[1], ipv6_src[0]);
187  SET_IPV6_ADDR(actions.encap_cfg.encap.outer.ip6.dst_ip, ipv6_dst[3], ipv6_dst[2], ipv6_dst[1], ipv6_dst[0]);
188 
189  result = doca_flow_pipe_add_entry(0, pipe, &match, &actions, NULL, NULL, 0, status, &encap_entries[1]);
190  if (result != DOCA_SUCCESS) {
191  DOCA_LOG_ERR("Failed to add entry matching on ipv6: %s", doca_error_get_descr(result));
192  return result;
193  }
194 
195  return DOCA_SUCCESS;
196 }
197 
198 /*
199  * Create DOCA Flow pipe on EGRESS domain with match on the packet meta and encap action with changeable values.
200  *
201  * @port [in]: port of the pipe.
202  * @port_id [in]: port_id for forwarding
203  * @status [in]: user context for adding entries.
204  * @nb_entries [out]: pointer to put into number of entries.
205  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
206  */
207 static doca_error_t create_encap_pipe(struct doca_flow_port *port, uint32_t port_id, struct doca_flow_pipe **encap_pipe)
208 {
209  struct doca_flow_match match;
211  struct doca_flow_monitor mon;
212  struct doca_flow_actions actions_ipv4, actions_ipv6, *actions_arr[NB_ENCAP_ACTIONS];
213  struct doca_flow_fwd fwd, fwd_miss;
214  struct doca_flow_pipe_cfg *pipe_cfg;
216 
217  memset(&match, 0, sizeof(match));
218  memset(&match_mask, 0, sizeof(match_mask));
219  memset(&mon, 0, sizeof(mon));
220  memset(&actions_ipv4, 0, sizeof(actions_ipv4));
221  memset(&actions_ipv6, 0, sizeof(actions_ipv6));
222  memset(&fwd, 0, sizeof(fwd));
223  memset(&fwd_miss, 0, sizeof(fwd_miss));
224 
225  /* Match on inner L3 type */
226  match.parser_meta.outer_l3_type = UINT32_MAX;
227  match_mask.parser_meta.outer_l3_type = UINT32_MAX;
228 
230 
231  /* Encap with IPv6 tunnel - most fields are changeable */
233  actions_ipv4.encap_cfg.is_l2 = false;
234  SET_MAC_ADDR(actions_ipv4.encap_cfg.encap.outer.eth.src_mac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
235  SET_MAC_ADDR(actions_ipv4.encap_cfg.encap.outer.eth.dst_mac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
237  SET_IPV6_ADDR(actions_ipv4.encap_cfg.encap.outer.ip6.src_ip, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
238  SET_IPV6_ADDR(actions_ipv4.encap_cfg.encap.outer.ip6.dst_ip, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
239  actions_ipv4.encap_cfg.encap.outer.ip6.hop_limit = 64;
240  actions_ipv4.encap_cfg.encap.outer.ip6.traffic_class = 0xdb;
243 
244  actions_ipv6 = actions_ipv4;
246 
247  actions_arr[0] = &actions_ipv4;
248  actions_arr[1] = &actions_ipv6;
249 
250  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
251  if (result != DOCA_SUCCESS) {
252  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
253  return result;
254  }
255 
256  result = set_flow_pipe_cfg(pipe_cfg, "ENCAP_PIPE", DOCA_FLOW_PIPE_BASIC, true);
257  if (result != DOCA_SUCCESS) {
258  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
259  goto destroy_pipe_cfg;
260  }
262  if (result != DOCA_SUCCESS) {
263  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg domain: %s", doca_error_get_descr(result));
264  goto destroy_pipe_cfg;
265  }
267  if (result != DOCA_SUCCESS) {
268  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
269  goto destroy_pipe_cfg;
270  }
271  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, &match_mask);
272  if (result != DOCA_SUCCESS) {
273  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
274  goto destroy_pipe_cfg;
275  }
276  result = doca_flow_pipe_cfg_set_monitor(pipe_cfg, &mon);
277  if (result != DOCA_SUCCESS) {
278  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
279  goto destroy_pipe_cfg;
280  }
281  result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_ENCAP_ACTIONS);
282  if (result != DOCA_SUCCESS) {
283  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
284  goto destroy_pipe_cfg;
285  }
286 
287  /* Forwarding traffic to the wire */
289  fwd.port_id = port_id;
290 
292 
293  result = doca_flow_pipe_create(pipe_cfg, &fwd, &fwd_miss, encap_pipe);
294  if (result != DOCA_SUCCESS) {
295  DOCA_LOG_ERR("Failed to create IP-in-IP encap pipe: %s", doca_error_get_descr(result));
296  goto destroy_pipe_cfg;
297  }
298  doca_flow_pipe_cfg_destroy(pipe_cfg);
299 
300  return DOCA_SUCCESS;
301 
303  doca_flow_pipe_cfg_destroy(pipe_cfg);
304  return result;
305 }
306 
307 /*
308  * Add DOCA Flow pipe entries with example decap values.
309  *
310  * @pipe [in]: pipe of the entry
311  * @status [in]: user context for adding entry
312  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
313  */
314 static doca_error_t add_decap_pipe_entries(struct doca_flow_pipe *pipe,
315  struct entries_status *status,
316  struct doca_flow_pipe_entry *decap_entries[])
317 {
318  struct doca_flow_match match;
319  struct doca_flow_actions actions;
321 
322  uint8_t smac[] = {0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc}; /* digits reversed for inner-type IPv6 */
323  uint8_t dmac[] = {0xdd, 0xee, 0xff, 0x11, 0x22, 0x33}; /* digits reversed for inner-type IPv6 */
324 
325  memset(&match, 0, sizeof(match));
326  memset(&actions, 0, sizeof(actions));
327 
329  SET_MAC_ADDR(actions.decap_cfg.eth.src_mac, smac[0], smac[1], smac[2], smac[3], smac[4], smac[5]);
330  SET_MAC_ADDR(actions.decap_cfg.eth.dst_mac, dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);
332 
333  result = doca_flow_pipe_add_entry(0, pipe, &match, &actions, NULL, NULL, 0, status, &decap_entries[0]);
334  if (result != DOCA_SUCCESS) {
335  DOCA_LOG_ERR("Failed to add entry matching on ipv4: %s", doca_error_get_descr(result));
336  return result;
337  }
338 
340  SET_MAC_ADDR(actions.decap_cfg.eth.src_mac, smac[5], smac[4], smac[3], smac[2], smac[1], smac[0]);
341  SET_MAC_ADDR(actions.decap_cfg.eth.dst_mac, dmac[5], dmac[4], dmac[3], dmac[2], dmac[1], dmac[0]);
343 
344  result = doca_flow_pipe_add_entry(0, pipe, &match, &actions, NULL, NULL, 0, status, &decap_entries[1]);
345  if (result != DOCA_SUCCESS) {
346  DOCA_LOG_ERR("Failed to add entry matching on ipv6: %s", doca_error_get_descr(result));
347  return result;
348  }
349 
350  return DOCA_SUCCESS;
351 }
352 
353 /*
354  * Create DOCA Flow pipe with match on the next_proto and decap action with changeable values.
355  *
356  * @port [in]: port of the pipe.
357  * @port_id [in]: port_id for forwarding
358  * @status [in]: user context for adding entries.
359  * @nb_entries [out]: pointer to put into number of entries.
360  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
361  */
362 static doca_error_t create_decap_pipe(struct doca_flow_port *port,
363  struct doca_flow_pipe *next_pipe,
364  struct doca_flow_pipe **decap_pipe)
365 {
366  struct doca_flow_match match;
367  struct doca_flow_monitor mon;
368  struct doca_flow_actions actions, *actions_arr[NB_DECAP_ACTIONS];
369  struct doca_flow_fwd fwd, fwd_miss;
370  struct doca_flow_pipe_cfg *pipe_cfg;
372 
373  memset(&match, 0, sizeof(match));
374  memset(&mon, 0, sizeof(mon));
375  memset(&actions, 0, sizeof(actions));
376  memset(&fwd, 0, sizeof(fwd));
377  memset(&fwd_miss, 0, sizeof(fwd_miss));
378 
379  /* Match on outer L3 type and next_proto */
382  match.outer.ip6.next_proto = UINT8_MAX;
383 
385 
386  /* Encap with IPv6 tunnel - most fields are changeable */
388  SET_MAC_ADDR(actions.decap_cfg.eth.src_mac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
389  SET_MAC_ADDR(actions.decap_cfg.eth.dst_mac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
390  actions.decap_cfg.eth.type = UINT16_MAX;
391 
392  actions_arr[0] = &actions;
393 
394  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
395  if (result != DOCA_SUCCESS) {
396  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
397  return result;
398  }
399  result = set_flow_pipe_cfg(pipe_cfg, "DECAP_PIPE", DOCA_FLOW_PIPE_BASIC, true);
400  if (result != DOCA_SUCCESS) {
401  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
402  goto destroy_pipe_cfg;
403  }
404  /* keep the default domain */
406  if (result != DOCA_SUCCESS) {
407  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
408  goto destroy_pipe_cfg;
409  }
410  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
411  if (result != DOCA_SUCCESS) {
412  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
413  goto destroy_pipe_cfg;
414  }
415  result = doca_flow_pipe_cfg_set_monitor(pipe_cfg, &mon);
416  if (result != DOCA_SUCCESS) {
417  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
418  goto destroy_pipe_cfg;
419  }
420  result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_DECAP_ACTIONS);
421  if (result != DOCA_SUCCESS) {
422  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
423  goto destroy_pipe_cfg;
424  }
425 
427  fwd.next_pipe = next_pipe;
428 
430 
431  result = doca_flow_pipe_create(pipe_cfg, &fwd, &fwd_miss, decap_pipe);
432  if (result != DOCA_SUCCESS) {
433  DOCA_LOG_ERR("Failed to create IP-in-IP decap pipe: %s", doca_error_get_descr(result));
434  goto destroy_pipe_cfg;
435  }
436  doca_flow_pipe_cfg_destroy(pipe_cfg);
437 
438  return DOCA_SUCCESS;
439 
441  doca_flow_pipe_cfg_destroy(pipe_cfg);
442  return result;
443 }
444 
445 /*
446  * Prepare egress domain pipeline.
447  *
448  * @ingress_port [in]: pointer to the ingress port.
449  * @egress_port [in]: pointer to the pair/egress port.
450  * @egress_port_id [in]: the ID of pair port.
451  * @status [in]: updated on entry creation/destruction
452  * @encap_entries [out]: entries created
453  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
454  */
455 static doca_error_t prepare_encap_pipeline(struct doca_flow_port *ingress_port,
456  struct doca_flow_port *egress_port,
457  uint32_t egress_port_id,
458  struct entries_status *status,
459  struct doca_flow_pipe_entry *encap_entries[])
460 {
461  struct doca_flow_pipe *hairpin_pipe, *encap_pipe;
463 
464  status->nb_processed = 0;
465 
466  result = create_hairpin_pipe(ingress_port, egress_port_id, true, status, &hairpin_pipe);
467  if (result != DOCA_SUCCESS) {
468  DOCA_LOG_ERR("Failed to create hairpin pipe with entries: %s", doca_error_get_descr(result));
469  return result;
470  }
471  result = flow_process_entries(ingress_port, status, NB_HAIRPIN_PIPE_ENTRIES);
472  if (result != DOCA_SUCCESS) {
473  DOCA_LOG_ERR("Failed to process encap entries: %s", doca_error_get_descr(result));
474  return result;
475  }
476 
477  status->nb_processed = 0;
478 
479  result = create_encap_pipe(egress_port, egress_port_id, &encap_pipe);
480  if (result != DOCA_SUCCESS) {
481  DOCA_LOG_ERR("Failed to create encap pipe with entries: %s", doca_error_get_descr(result));
482  return result;
483  }
484  result = add_encap_pipe_entries(encap_pipe, status, encap_entries);
485  if (result != DOCA_SUCCESS) {
486  DOCA_LOG_ERR("Failed to add entries to encap pipe: %s", doca_error_get_descr(result));
487  return result;
488  }
489  result = flow_process_entries(egress_port, status, NB_EGRESS_PIPE_ENTRIES);
490  if (result != DOCA_SUCCESS) {
491  DOCA_LOG_ERR("Failed to process encap entries: %s", doca_error_get_descr(result));
492  return result;
493  }
494 
495  return DOCA_SUCCESS;
496 }
497 
498 /*
499  * Prepare ingress domain pipeline.
500  *
501  * @ingress_port [in]: pointer to port.
502  * @egress_port_id [in]: pair port ID.
503  * @status [in]: updated on entry creation/destruction
504  * @decap_entries [out]: entries created
505  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
506  */
507 static doca_error_t prepare_decap_pipeline(struct doca_flow_port *ingress_port,
508  int egress_port_id,
509  struct entries_status *status,
510  struct doca_flow_pipe_entry *decap_entries[])
511 {
512  struct doca_flow_pipe *hairpin_pipe, *decap_pipe;
514 
515  status->nb_processed = 0;
516 
517  result = create_hairpin_pipe(ingress_port, egress_port_id, false, status, &hairpin_pipe);
518  if (result != DOCA_SUCCESS) {
519  DOCA_LOG_ERR("Failed to create hairpin pipe with entries: %s", doca_error_get_descr(result));
520  return result;
521  }
522 
523  result = create_decap_pipe(ingress_port, hairpin_pipe, &decap_pipe);
524  if (result != DOCA_SUCCESS) {
525  DOCA_LOG_ERR("Failed to create decap pipe with entries: %s", doca_error_get_descr(result));
526  return result;
527  }
528  result = add_decap_pipe_entries(decap_pipe, status, decap_entries);
529  if (result != DOCA_SUCCESS) {
530  DOCA_LOG_ERR("Failed to add entries to decap pipe: %s", doca_error_get_descr(result));
531  return result;
532  }
533  result = flow_process_entries(ingress_port, status, NB_INGRESS_PIPE_ENTRIES);
534  if (result != DOCA_SUCCESS) {
535  DOCA_LOG_ERR("Failed to process decap entries: %s", doca_error_get_descr(result));
536  return result;
537  }
538 
539  return DOCA_SUCCESS;
540 }
541 
542 /*
543  * Run flow_ip_in_ip sample.
544  *
545  * @nb_queues [in]: number of queues the sample will use.
546  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
547  */
549 {
550  const int nb_ports = 2;
551  struct flow_resources resource = {0};
552  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
553  struct doca_flow_port *ports[nb_ports];
554  struct doca_dev *dev_arr[nb_ports];
555  uint32_t actions_mem_size[nb_ports];
557  uint32_t raw_port_id = 0;
558  uint32_t tunnel_port_id = raw_port_id ^ 1;
559  struct doca_flow_pipe_entry *encap_entries[NB_ENCAP_PIPE_ENTRIES];
560  struct doca_flow_pipe_entry *decap_entries[NB_DECAP_PIPE_ENTRIES];
561  struct entries_status entries_status = {0};
562  struct doca_flow_resource_query encap_ipv4_query_stats, encap_ipv6_query_stats, decap_ipv4_query_stats,
563  decap_ipv6_query_stats;
564 
566  result = init_doca_flow(nb_queues, "vnf,hws", &resource, nr_shared_resources);
567  if (result != DOCA_SUCCESS) {
568  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
569  return result;
570  }
571 
572  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
575  if (result != DOCA_SUCCESS) {
576  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
578  return result;
579  }
580  result = prepare_encap_pipeline(ports[raw_port_id], /* packet arrives here, is hairpinned */
581  ports[tunnel_port_id], /* packet is encapped here */
582  tunnel_port_id, /* packet is forwarded here */
584  encap_entries);
585  if (result != DOCA_SUCCESS) {
586  DOCA_LOG_ERR("Failed to prepare egress pipeline: %s", doca_error_get_descr(result));
589  return result;
590  }
591 
592  result = prepare_decap_pipeline(ports[tunnel_port_id], /* packet arrives here, is decapped */
593  raw_port_id, /* packet is forwarded here */
595  decap_entries);
596  if (result != DOCA_SUCCESS) {
597  DOCA_LOG_ERR("Failed to prepare ingress pipeline: %s", doca_error_get_descr(result));
600  return result;
601  }
602 
603  DOCA_LOG_INFO("Wait %u seconds for packets to arrive", WAITING_TIME);
604  sleep(WAITING_TIME);
605 
606  result = doca_flow_resource_query_entry(encap_entries[0], &encap_ipv4_query_stats);
607  if (result != DOCA_SUCCESS) {
608  DOCA_LOG_ERR("Failed to query entry counter: %s", doca_error_get_descr(result));
609  }
610  result = doca_flow_resource_query_entry(decap_entries[0], &decap_ipv4_query_stats);
611  if (result != DOCA_SUCCESS) {
612  DOCA_LOG_ERR("Failed to query entry counter: %s", doca_error_get_descr(result));
613  }
614  result = doca_flow_resource_query_entry(encap_entries[1], &encap_ipv6_query_stats);
615  if (result != DOCA_SUCCESS) {
616  DOCA_LOG_ERR("Failed to query entry counter: %s", doca_error_get_descr(result));
617  }
618  result = doca_flow_resource_query_entry(decap_entries[1], &decap_ipv6_query_stats);
619  if (result != DOCA_SUCCESS) {
620  DOCA_LOG_ERR("Failed to query entry counter: %s", doca_error_get_descr(result));
621  }
622  DOCA_LOG_INFO("Encap: counted %ld IPv4 packets, %ld IPv6 packets",
623  encap_ipv4_query_stats.counter.total_pkts,
624  encap_ipv6_query_stats.counter.total_pkts);
625  DOCA_LOG_INFO("Decap: counted %ld IPv4 packets, %ld IPv6 packets",
626  decap_ipv4_query_stats.counter.total_pkts,
627  decap_ipv6_query_stats.counter.total_pkts);
628 
631  return result;
632 }
#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
#define SET_MAC_ADDR(addr, a, b, c, d, e, f)
Definition: flow_common.h:60
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static doca_error_t add_encap_pipe_entries(struct doca_flow_pipe *pipe, struct entries_status *status, struct doca_flow_pipe_entry *encap_entries[])
static doca_error_t prepare_encap_pipeline(struct doca_flow_port *ingress_port, struct doca_flow_port *egress_port, uint32_t egress_port_id, struct entries_status *status, struct doca_flow_pipe_entry *encap_entries[])
doca_error_t flow_ip_in_ip(int nb_queues)
#define NB_DECAP_PIPE_ENTRIES
#define NB_EGRESS_PIPE_ENTRIES
#define NEXT_HEADER_IPV4
DOCA_LOG_REGISTER(FLOW_IP_IN_IP)
static doca_error_t create_hairpin_pipe(struct doca_flow_port *port, int dest_port_id, bool is_root, struct entries_status *status, struct doca_flow_pipe **pipe)
#define NB_ENCAP_PIPE_ENTRIES
#define NB_DECAP_ACTIONS
#define NB_INGRESS_PIPE_ENTRIES
#define TOTAL_ENTRIES
static doca_error_t create_decap_pipe(struct doca_flow_port *port, struct doca_flow_pipe *next_pipe, struct doca_flow_pipe **decap_pipe)
#define WAITING_TIME
#define NB_HAIRPIN_PIPE_ENTRIES
static doca_error_t create_encap_pipe(struct doca_flow_port *port, uint32_t port_id, struct doca_flow_pipe **encap_pipe)
static doca_error_t add_decap_pipe_entries(struct doca_flow_pipe *pipe, struct entries_status *status, struct doca_flow_pipe_entry *decap_entries[])
static doca_error_t prepare_decap_pipeline(struct doca_flow_port *ingress_port, int egress_port_id, struct entries_status *status, struct doca_flow_pipe_entry *decap_entries[])
#define NEXT_HEADER_IPV6
#define NB_ENCAP_ACTIONS
static struct doca_flow_fwd fwd_miss
Definition: flow_parser.c:110
static struct doca_flow_actions actions
Definition: flow_parser.c:107
static struct doca_flow_fwd fwd
Definition: flow_parser.c:109
static struct doca_flow_match match_mask
Definition: flow_parser.c:106
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
#define DOCA_HTOBE16(_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_SUCCESS
Definition: doca_error.h:38
#define DOCA_FLOW_ETHER_TYPE_IPV6
Definition: doca_flow_net.h:58
#define DOCA_FLOW_ETHER_TYPE_IPV4
Definition: doca_flow_net.h:57
@ DOCA_FLOW_L3_TYPE_IP6
@ DOCA_FLOW_TUN_IP_IN_IP
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_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_flow_flags_type
doca flow flags type
Definition: doca_flow.h:114
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_STABLE doca_error_t doca_flow_pipe_cfg_set_nr_entries(struct doca_flow_pipe_cfg *cfg, uint32_t nr_entries)
Set pipe's maximum number of flow rules.
DOCA_STABLE doca_error_t doca_flow_pipe_cfg_set_domain(struct doca_flow_pipe_cfg *cfg, enum doca_flow_pipe_domain domain)
Set pipe's domain.
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_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_L3_META_IPV4
Definition: doca_flow.h:296
@ DOCA_FLOW_L3_META_IPV6
Definition: doca_flow.h:298
@ DOCA_FLOW_NO_WAIT
Definition: doca_flow.h:115
@ 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_DROP
Definition: doca_flow.h:748
@ DOCA_FLOW_PIPE_DOMAIN_EGRESS
Definition: doca_flow.h:245
@ DOCA_FLOW_PIPE_DOMAIN_DEFAULT
Definition: doca_flow.h:241
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
uint32_t doca_be32_t
Definition: doca_types.h:121
#define htobe32
Definition: os_utils.hpp:40
doca_error_t flow_process_entries(struct doca_flow_port *port, struct entries_status *status, uint32_t nr_entries)
Definition: flow_common.c:338
doca_error_t stop_doca_flow_ports(int nb_ports, struct doca_flow_port *ports[])
Definition: flow_common.c:240
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 NB_ACTIONS_ARR
Definition: flow_common.h:58
#define SHARED_RESOURCE_NUM_VALUES
Definition: flow_common.h:59
#define ACTIONS_MEM_SIZE(nr_queues, entries)
Definition: flow_common.h:66
#define SET_IPV6_ADDR(addr, a, b, c, d)
Definition: flow_common.h:40
#define ARRAY_INIT(array, val)
Definition: flow_common.h:71
doca flow actions information
Definition: doca_flow.h:684
struct doca_flow_resource_encap_cfg encap_cfg
Definition: doca_flow.h:710
enum doca_flow_resource_type encap_type
Definition: doca_flow.h:707
enum doca_flow_resource_type decap_type
Definition: doca_flow.h:689
struct doca_flow_resource_decap_cfg decap_cfg
Definition: doca_flow.h:692
uint8_t action_idx
Definition: doca_flow.h:685
struct doca_flow_tun tun
Definition: doca_flow.h:569
struct doca_flow_header_format outer
Definition: doca_flow.h:567
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
uint8_t dst_mac[DOCA_FLOW_ETHER_ADDR_LEN]
uint8_t src_mac[DOCA_FLOW_ETHER_ADDR_LEN]
struct doca_flow_header_eth eth
Definition: doca_flow.h:440
enum doca_flow_l3_type l3_type
Definition: doca_flow.h:446
struct doca_flow_header_ip6 ip6
Definition: doca_flow.h:451
doca_be32_t dst_ip[4]
doca_be32_t src_ip[4]
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_parser_meta parser_meta
Definition: doca_flow.h:496
struct doca_flow_header_format outer
Definition: doca_flow.h:498
doca monitor action configuration
Definition: doca_flow.h:968
enum doca_flow_resource_type counter_type
Definition: doca_flow.h:988
enum doca_flow_l3_meta outer_l3_type
Definition: doca_flow.h:382
struct doca_flow_header_eth eth
Definition: doca_flow.h:673
struct doca_flow_encap_action encap
Definition: doca_flow.h:663
flow resource query
Definition: doca_flow.h:1101
struct doca_flow_resource_query::@115::@117 counter
enum doca_flow_tun_type type
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
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