NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_esp_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023 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 
30 #include <doca_log.h>
31 #include <doca_flow.h>
32 
33 #include "doca_error.h"
34 #include "doca_bitfield.h"
35 
36 #include "flow_common.h"
37 
39 
40 /* The number of seconds app waits for traffic to come */
41 #define WAITING_TIME 5
42 
43 /*
44  * Create DOCA Flow pipe with changeable 5 tuple match as root
45  *
46  * @port [in]: port of the pipe
47  * @pipe [out]: created pipe pointer
48  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
49  */
50 static doca_error_t create_root_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
51 {
52  struct doca_flow_match match;
53  struct doca_flow_fwd fwd;
54  struct doca_flow_pipe_cfg *pipe_cfg;
55  uint32_t sequence_number = 2;
57 
58  memset(&match, 0, sizeof(match));
59  memset(&fwd, 0, sizeof(fwd));
60 
61  /* ESP packet match */
64  match.tun.type = DOCA_FLOW_TUN_ESP;
65  match.tun.esp_spi = 0xffffffff;
66  match.tun.esp_sn = DOCA_HTOBE32(sequence_number);
67 
68  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
69  if (result != DOCA_SUCCESS) {
70  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
71  return result;
72  }
73 
74  result = set_flow_pipe_cfg(pipe_cfg, "ESP_ROOT_PIPE", DOCA_FLOW_PIPE_BASIC, true);
75  if (result != DOCA_SUCCESS) {
76  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
77  goto destroy_pipe_cfg;
78  }
80  if (result != DOCA_SUCCESS) {
81  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
82  goto destroy_pipe_cfg;
83  }
84  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
85  if (result != DOCA_SUCCESS) {
86  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
87  goto destroy_pipe_cfg;
88  }
89 
91  fwd.next_pipe = NULL;
92 
93  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
96  return result;
97 }
98 
99 /*
100  * Add DOCA Flow pipe entry to the root pipe that forwards the traffic to specific comparison pipe.
101  *
102  * @pipe [in]: pipe of the entries.
103  * @next_pipe [in]: comparison pipe to forward the matched traffic.
104  * @spi [in]: the ESP SPI to match on in this entry.
105  * @status [in]: user context for adding entry.
106  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
107  */
108 static doca_error_t add_root_pipe_entry(struct doca_flow_pipe *pipe,
109  struct doca_flow_pipe *next_pipe,
110  uint32_t spi,
111  struct entries_status *status)
112 {
113  struct doca_flow_pipe_entry *entry;
114  struct doca_flow_match match;
115  struct doca_flow_fwd fwd;
116 
117  memset(&match, 0, sizeof(match));
118  memset(&fwd, 0, sizeof(fwd));
119 
120  match.tun.esp_spi = DOCA_HTOBE32(spi);
121 
124 
125  return doca_flow_pipe_add_entry(0, pipe, &match, NULL, NULL, &fwd, 0, status, &entry);
126 }
127 
128 /*
129  * Add DOCA Flow pipe entries to the root pipe that forwards the traffic to comparison pipes.
130  *
131  * @pipe [in]: pipe of the entries.
132  * @status [in]: user context for adding entry
133  * @gt_pipe [in]: Greater Than pipe to forward the matched traffic.
134  * @lt_pipe [in]: Less Than pipe to forward the matched traffic.
135  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
136  */
137 static doca_error_t add_root_pipe_entries(struct doca_flow_pipe *pipe,
138  struct entries_status *status,
139  struct doca_flow_pipe *gt_pipe,
140  struct doca_flow_pipe *lt_pipe)
141 {
143  uint32_t spi = 8;
144 
145  result = add_root_pipe_entry(pipe, gt_pipe, spi, status);
146  if (result != DOCA_SUCCESS) {
147  DOCA_LOG_ERR("Failed to add entry - go to GT pipe: %s", doca_error_get_descr(result));
148  return result;
149  }
150 
151  spi = 5;
152  result = add_root_pipe_entry(pipe, lt_pipe, spi, status);
153  if (result != DOCA_SUCCESS) {
154  DOCA_LOG_ERR("Failed to add entry - go to LT pipe: %s", doca_error_get_descr(result));
155  return result;
156  }
157 
158  return DOCA_SUCCESS;
159 }
160 
161 /*
162  * Add DOCA Flow pipe use condition API according to ESP sequence number.
163  *
164  * @port [in]: port of the pipe
165  * @name [in]: name of the pipe
166  * @pipe [out]: created pipe pointer
167  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
168  */
169 static doca_error_t create_comparison_pipe(struct doca_flow_port *port, const char *name, struct doca_flow_pipe **pipe)
170 {
171  struct doca_flow_pipe_cfg *pipe_cfg;
173 
174  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
175  if (result != DOCA_SUCCESS) {
176  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
177  return result;
178  }
179 
180  result = set_flow_pipe_cfg(pipe_cfg, name, DOCA_FLOW_PIPE_CONTROL, false);
181  if (result != DOCA_SUCCESS) {
182  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
183  goto destroy_pipe_cfg;
184  }
185 
186  result = doca_flow_pipe_create(pipe_cfg, NULL, NULL, pipe);
188  doca_flow_pipe_cfg_destroy(pipe_cfg);
189  return result;
190 }
191 
192 /*
193  * Add DOCA Flow pipe entry to the comparison pipe.
194  *
195  * @pipe [in]: pipe of the entries.
196  * @port_id [in]: port ID for forwarding to.
197  * @gt [in]: indicator whether compare operation is "GT (>)" or "LT (<)".
198  * @status [in]: user context for adding entry.
199  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
200  */
201 static doca_error_t add_comparison_pipe_entry(struct doca_flow_pipe *pipe,
202  uint16_t port_id,
203  bool gt,
204  struct entries_status *status)
205 {
206  struct doca_flow_pipe_entry *entry;
207  struct doca_flow_match match;
208  struct doca_flow_match_condition condition;
209  struct doca_flow_fwd fwd;
210 
211  memset(&match, 0, sizeof(match));
212  memset(&condition, 0, sizeof(condition));
213  memset(&fwd, 0, sizeof(fwd));
214 
216  /* Argument field is always ESP sequence number */
217  condition.field_op.a.field_string = "tunnel.esp.sn";
218  condition.field_op.a.bit_offset = 0;
219  /* Base is immediate value, so the string should be NULL and value is taken from match structure */
220  condition.field_op.b.field_string = NULL;
221  condition.field_op.b.bit_offset = 0;
222  condition.field_op.width = 32;
223 
224  /*
225  * The immediate value to compare with ESP sequence number field is provided in the match structure.
226  * The value is hard-coded 3 (arbitrary).
227  */
228  match.tun.esp_sn = DOCA_HTOBE32(3);
229 
231  fwd.port_id = port_id ^ 1;
232 
233  return doca_flow_pipe_control_add_entry(0 /* queue */,
234  0 /* priority */,
235  pipe,
236  &match,
237  NULL /* match_mask */,
238  &condition,
239  NULL,
240  NULL,
241  NULL,
242  NULL,
243  &fwd,
244  status,
245  &entry);
246 }
247 
248 /*
249  * Run flow_esp sample.
250  *
251  * This sample tests ESP header fields in two ways:
252  * 1. Exact match on SPI field in the root pipe.
253  * 2. Condition match for sequence number field.
254  *
255  * @nb_queues [in]: number of queues the sample will use
256  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
257  */
258 doca_error_t flow_esp(int nb_queues)
259 {
260  int nb_ports = 2;
261  struct flow_resources resource = {0};
262  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
263  struct doca_flow_port *ports[nb_ports];
264  struct doca_dev *dev_arr[nb_ports];
265  uint32_t actions_mem_size[nb_ports];
266  struct doca_flow_pipe *root_pipe;
267  struct doca_flow_pipe *gt_pipe;
268  struct doca_flow_pipe *lt_pipe;
269  struct entries_status status;
270  uint32_t num_of_entries = 4;
272  int port_id;
273 
274  result = init_doca_flow(nb_queues, "vnf,hws", &resource, nr_shared_resources);
275  if (result != DOCA_SUCCESS) {
276  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
277  return result;
278  }
279 
280  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
281  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_queues, num_of_entries));
283  if (result != DOCA_SUCCESS) {
284  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
286  return result;
287  }
288 
289  for (port_id = 0; port_id < nb_ports; port_id++) {
290  memset(&status, 0, sizeof(status));
291 
292  result = create_comparison_pipe(ports[port_id], "ESP_GT_PIPE", &gt_pipe);
293  if (result != DOCA_SUCCESS) {
294  DOCA_LOG_ERR("Failed to create GT comparison pipe: %s", doca_error_get_descr(result));
297  return result;
298  }
299 
300  result = add_comparison_pipe_entry(gt_pipe, port_id, true, &status);
301  if (result != DOCA_SUCCESS) {
302  DOCA_LOG_ERR("Failed to add GT comparison pipe entries: %s", doca_error_get_descr(result));
305  return result;
306  }
307 
308  result = create_comparison_pipe(ports[port_id], "ESP_LT_PIPE", &lt_pipe);
309  if (result != DOCA_SUCCESS) {
310  DOCA_LOG_ERR("Failed to create LT comparison pipe: %s", doca_error_get_descr(result));
313  return result;
314  }
315 
316  result = add_comparison_pipe_entry(lt_pipe, port_id, false, &status);
317  if (result != DOCA_SUCCESS) {
318  DOCA_LOG_ERR("Failed to add LT comparison pipe entries: %s", doca_error_get_descr(result));
321  return result;
322  }
323 
324  result = create_root_pipe(ports[port_id], &root_pipe);
325  if (result != DOCA_SUCCESS) {
326  DOCA_LOG_ERR("Failed to create root pipe: %s", doca_error_get_descr(result));
329  return result;
330  }
331 
332  result = add_root_pipe_entries(root_pipe, &status, gt_pipe, lt_pipe);
333  if (result != DOCA_SUCCESS) {
334  DOCA_LOG_ERR("Failed to add root pipe entries: %s", doca_error_get_descr(result));
337  return result;
338  }
339 
340  result = flow_process_entries(ports[port_id], &status, num_of_entries);
341  if (result != DOCA_SUCCESS) {
342  DOCA_LOG_ERR("Failed to process entries: %s", doca_error_get_descr(result));
345  return result;
346  }
347  }
348 
349  DOCA_LOG_INFO("Wait %u seconds for packets to arrive", WAITING_TIME);
350  sleep(WAITING_TIME);
351 
354  return result;
355 }
#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 doca_error_t add_root_pipe_entries(struct doca_flow_pipe *pipe, struct entries_status *status, struct doca_flow_pipe *gt_pipe, struct doca_flow_pipe *lt_pipe)
doca_error_t flow_esp(int nb_queues)
DOCA_LOG_REGISTER(FLOW_ESP)
static doca_error_t add_comparison_pipe_entry(struct doca_flow_pipe *pipe, uint16_t port_id, bool gt, struct entries_status *status)
#define WAITING_TIME
static doca_error_t create_root_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
static doca_error_t add_root_pipe_entry(struct doca_flow_pipe *pipe, struct doca_flow_pipe *next_pipe, uint32_t spi, struct entries_status *status)
static doca_error_t create_comparison_pipe(struct doca_flow_port *port, const char *name, struct doca_flow_pipe **pipe)
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static struct doca_flow_fwd fwd
Definition: flow_parser.c:109
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
#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_SUCCESS
Definition: doca_error.h:38
@ DOCA_FLOW_TUN_ESP
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_control_add_entry(uint16_t pipe_queue, uint32_t priority, struct doca_flow_pipe *pipe, const struct doca_flow_match *match, const struct doca_flow_match *match_mask, const struct doca_flow_match_condition *condition, const struct doca_flow_actions *actions, const struct doca_flow_actions *actions_mask, const struct doca_flow_action_descs *action_descs, const struct doca_flow_monitor *monitor, const struct doca_flow_fwd *fwd, void *usr_ctx, struct doca_flow_pipe_entry **entry)
Add one new entry to a control pipe.
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_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_FLOW_PIPE_CONTROL
Definition: doca_flow.h:223
@ DOCA_FLOW_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_L3_META_IPV4
Definition: doca_flow.h:296
@ DOCA_FLOW_COMPARE_GT
Definition: doca_flow.h:518
@ DOCA_FLOW_COMPARE_LT
Definition: doca_flow.h:514
@ DOCA_FLOW_FWD_PORT
Definition: doca_flow.h:744
@ DOCA_FLOW_FWD_PIPE
Definition: doca_flow.h:746
@ DOCA_FLOW_L4_META_ESP
Definition: doca_flow.h:314
#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
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 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
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
doca flow match condition information
Definition: doca_flow.h:548
enum doca_flow_compare_op operation
Definition: doca_flow.h:549
struct doca_flow_match_condition::@68::@70 field_op
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_parser_meta parser_meta
Definition: doca_flow.h:496
struct doca_flow_tun tun
Definition: doca_flow.h:500
enum doca_flow_l3_meta outer_l3_type
Definition: doca_flow.h:382
enum doca_flow_l4_meta outer_l4_type
Definition: doca_flow.h:383
enum doca_flow_tun_type type
doca_be32_t esp_spi
doca_be32_t esp_sn
user context struct that will be used in entries process callback
Definition: flow_common.h:78
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