NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_lpm_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022 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 <string.h>
27 #include <unistd.h>
28 
29 #include <doca_log.h>
30 #include <doca_flow.h>
31 
32 #include "flow_common.h"
33 
35 
36 /*
37  * Create DOCA Flow main pipe
38  *
39  * @port [in]: port of the pipe
40  * @next_pipe [in]: lpm pipe to forward the matched traffic
41  * @pipe [out]: created pipe pointer
42  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
43  */
44 static doca_error_t create_main_pipe(struct doca_flow_port *port,
45  struct doca_flow_pipe *next_pipe,
46  struct doca_flow_pipe **pipe)
47 {
48  struct doca_flow_pipe_cfg *pipe_cfg;
49  struct doca_flow_match match;
50  struct doca_flow_monitor counter;
51  struct doca_flow_fwd fwd;
53 
54  memset(&match, 0, sizeof(match));
55  memset(&counter, 0, sizeof(counter));
56  memset(&fwd, 0, sizeof(fwd));
57 
59 
61 
64 
65  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
66  if (result != DOCA_SUCCESS) {
67  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
68  return result;
69  }
70 
71  result = set_flow_pipe_cfg(pipe_cfg, "MAIN_PIPE", DOCA_FLOW_PIPE_BASIC, true);
72  if (result != DOCA_SUCCESS) {
73  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
74  goto destroy_pipe_cfg;
75  }
76 
77  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
78  if (result != DOCA_SUCCESS) {
79  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
80  goto destroy_pipe_cfg;
81  }
82 
83  result = doca_flow_pipe_cfg_set_monitor(pipe_cfg, &counter);
84  if (result != DOCA_SUCCESS) {
85  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
86  goto destroy_pipe_cfg;
87  }
88 
89  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
92  return result;
93 }
94 
95 /*
96  * Add DOCA Flow pipe entry to the main pipe that forwards ipv4 traffic to lpm pipe
97  *
98  * @pipe [in]: pipe of the entry
99  * @status [in]: user context for adding entry
100  * @entry [out]: result of entry addition
101  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
102  */
103 static doca_error_t add_main_pipe_entry(struct doca_flow_pipe *pipe,
104  struct entries_status *status,
105  struct doca_flow_pipe_entry **entry)
106 {
107  struct doca_flow_match match;
108 
109  memset(&match, 0, sizeof(match));
110 
111  return doca_flow_pipe_add_entry(0, pipe, &match, NULL, NULL, NULL, DOCA_FLOW_NO_WAIT, status, entry);
112 }
113 
114 /*
115  * Add DOCA Flow LPM pipe that matched IPV4 addresses
116  *
117  * @port [in]: port of the pipe
118  * @port_id [in]: port ID of the pipe
119  * @pipe [out]: created pipe pointer
120  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
121  */
122 static doca_error_t create_lpm_pipe(struct doca_flow_port *port, int port_id, struct doca_flow_pipe **pipe)
123 {
124  (void)port_id;
125 
126  struct doca_flow_match match;
127  struct doca_flow_monitor counter;
128  struct doca_flow_actions actions, *actions_arr[NB_ACTIONS_ARR];
129  struct doca_flow_pipe_cfg *pipe_cfg;
132 
133  memset(&match, 0, sizeof(match));
134  memset(&counter, 0, sizeof(counter));
135  memset(&actions, 0, sizeof(actions));
136 
138  match.outer.ip4.src_ip = 0xffffffff;
139 
141 
142  actions_arr[0] = &actions;
143 
144  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
145  if (result != DOCA_SUCCESS) {
146  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
147  return result;
148  }
149 
150  result = set_flow_pipe_cfg(pipe_cfg, "LPM_PIPE", DOCA_FLOW_PIPE_LPM, false);
151  if (result != DOCA_SUCCESS) {
152  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
153  goto destroy_pipe_cfg;
154  }
155  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
156  if (result != DOCA_SUCCESS) {
157  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
158  goto destroy_pipe_cfg;
159  }
160  result = doca_flow_pipe_cfg_set_monitor(pipe_cfg, &counter);
161  if (result != DOCA_SUCCESS) {
162  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
163  goto destroy_pipe_cfg;
164  }
165  result = doca_flow_pipe_cfg_set_actions(pipe_cfg, actions_arr, NULL, NULL, NB_ACTIONS_ARR);
166  if (result != DOCA_SUCCESS) {
167  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg actions: %s", doca_error_get_descr(result));
168  goto destroy_pipe_cfg;
169  }
170 
171  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
173  doca_flow_pipe_cfg_destroy(pipe_cfg);
174  return result;
175 }
176 
177 /*
178  * Add DOCA Flow pipe entries to the LPM pipe. one entry with full mask and one with 16 bits mask
179  *
180  * @pipe [in]: pipe of the entry
181  * @port_id [in]: port ID of the entry
182  * @status [in]: user context for adding entry
183  * @entries [out]: array of pointers to created entries
184  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
185  */
186 static doca_error_t add_lpm_pipe_entries(struct doca_flow_pipe *pipe,
187  int port_id,
188  struct entries_status *status,
189  struct doca_flow_pipe_entry **entries)
190 {
191  struct doca_flow_match match;
193  struct doca_flow_fwd fwd;
194  doca_be32_t src_ip_addr = BE_IPV4_ADDR(1, 2, 3, 4);
196 
197  memset(&match, 0, sizeof(match));
198  memset(&match_mask, 0, sizeof(match_mask));
199  memset(&fwd, 0, sizeof(fwd));
200 
201  match.outer.ip4.src_ip = src_ip_addr;
202 
203  /* add entry with full mask and fwd port */
204  match_mask.outer.ip4.src_ip = RTE_BE32(0xffffffff);
205 
207  fwd.port_id = port_id ^ 1;
208 
210  pipe,
211  &match,
212  &match_mask,
213  NULL,
214  NULL,
215  &fwd,
217  status,
218  &entries[0]);
219  if (result != DOCA_SUCCESS) {
220  DOCA_LOG_ERR("Failed to add lpm pipe entry: %s", doca_error_get_descr(result));
221  return result;
222  }
223 
224  /* add entry with mask on 16 MSBits and fwd drop */
225  match_mask.outer.ip4.src_ip = RTE_BE32(0xffff0000);
226 
228 
230  pipe,
231  &match,
232  &match_mask,
233  NULL,
234  NULL,
235  &fwd,
237  status,
238  &entries[1]);
239  if (result != DOCA_SUCCESS) {
240  DOCA_LOG_ERR("Failed to add lpm pipe entry: %s", doca_error_get_descr(result));
241  return result;
242  }
243 
244  /* add default entry with 0 bits mask and fwd drop */
245  match_mask.outer.ip4.src_ip = RTE_BE32(0x00000000);
246 
248 
250  pipe,
251  &match,
252  &match_mask,
253  NULL,
254  NULL,
255  &fwd,
257  status,
258  &entries[2]);
259  if (result != DOCA_SUCCESS) {
260  DOCA_LOG_ERR("Failed to add lpm pipe entry: %s", doca_error_get_descr(result));
261  return result;
262  }
263 
264  return DOCA_SUCCESS;
265 }
266 
267 /*
268  * Run flow_lpm sample
269  *
270  * @nb_queues [in]: number of queues the sample will use
271  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
272  */
273 doca_error_t flow_lpm(int nb_queues)
274 {
275  const int nb_ports = 2;
276  /* 1 entry for main pipe and 3 entries for LPM pipe */
277  const int num_of_entries = 4;
278  struct flow_resources resource = {.nr_counters = num_of_entries * nb_ports};
279  struct doca_flow_pipe_entry *entries[nb_ports][num_of_entries];
280  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
281  struct doca_flow_port *ports[nb_ports];
282  struct doca_dev *dev_arr[nb_ports];
283  uint32_t actions_mem_size[nb_ports];
284  struct doca_flow_pipe *main_pipe;
285  struct doca_flow_pipe *lpm_pipe;
286  struct entries_status status;
289  int port_id, lpm_entry_id;
290 
291  result = init_doca_flow(nb_queues, "vnf,hws", &resource, nr_shared_resources);
292  if (result != DOCA_SUCCESS) {
293  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
294  return result;
295  }
296 
297  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
298  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_queues, num_of_entries));
300  if (result != DOCA_SUCCESS) {
301  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
303  return result;
304  }
305 
306  for (port_id = 0; port_id < nb_ports; port_id++) {
307  memset(&status, 0, sizeof(status));
308 
309  result = create_lpm_pipe(ports[port_id], port_id, &lpm_pipe);
310  if (result != DOCA_SUCCESS) {
311  DOCA_LOG_ERR("Failed to create pipe: %s", doca_error_get_descr(result));
314  return result;
315  }
316 
317  result = add_lpm_pipe_entries(lpm_pipe, port_id, &status, &entries[port_id][1]);
318  if (result != DOCA_SUCCESS) {
321  return result;
322  }
323 
324  result = create_main_pipe(ports[port_id], lpm_pipe, &main_pipe);
325  if (result != DOCA_SUCCESS) {
326  DOCA_LOG_ERR("Failed to create main pipe: %s", doca_error_get_descr(result));
329  return result;
330  }
331 
332  result = add_main_pipe_entry(main_pipe, &status, &entries[port_id][0]);
333  if (result != DOCA_SUCCESS) {
334  DOCA_LOG_ERR("Failed to add entry: %s", doca_error_get_descr(result));
337  return result;
338  }
339 
340  result = doca_flow_entries_process(ports[port_id], 0, DEFAULT_TIMEOUT_US, 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  if (status.nb_processed != num_of_entries || status.failure) {
349  DOCA_LOG_ERR("Failed to process entries");
352  return DOCA_ERROR_BAD_STATE;
353  }
354  }
355 
356  DOCA_LOG_INFO("Wait few seconds for packets to arrive");
357  sleep(15);
358 
359  for (port_id = 0; port_id < nb_ports; port_id++) {
361  if (result != DOCA_SUCCESS) {
362  DOCA_LOG_ERR("Port %d failed to query main pipe entry: %s",
363  port_id,
365  return result;
366  }
367  DOCA_LOG_INFO("Port %d, main pipe entry received %lu packets", port_id, stats.counter.total_pkts);
368 
369  for (lpm_entry_id = 1; lpm_entry_id < num_of_entries; lpm_entry_id++) {
370  result = doca_flow_resource_query_entry(entries[port_id][lpm_entry_id], &stats);
371  if (result != DOCA_SUCCESS) {
372  DOCA_LOG_ERR("Port %d failed to query LPM pipe entry %d: %s",
373  port_id,
374  lpm_entry_id - 1,
376  return result;
377  }
378  DOCA_LOG_INFO("Port %d, LPM pipe entry %d received %lu packets",
379  port_id,
380  lpm_entry_id - 1,
381  stats.counter.total_pkts);
382  }
383  }
384 
387  return result;
388 }
#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 struct eth_l2_fwd_stats stats
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static struct doca_flow_pipe_entry * entries[NB_ENTRIES]
doca_error_t flow_lpm(int nb_queues)
DOCA_LOG_REGISTER(FLOW_LPM)
static doca_error_t add_main_pipe_entry(struct doca_flow_pipe *pipe, struct entries_status *status, struct doca_flow_pipe_entry **entry)
static doca_error_t create_main_pipe(struct doca_flow_port *port, struct doca_flow_pipe *next_pipe, struct doca_flow_pipe **pipe)
static doca_error_t add_lpm_pipe_entries(struct doca_flow_pipe *pipe, int port_id, struct entries_status *status, struct doca_flow_pipe_entry **entries)
static doca_error_t create_lpm_pipe(struct doca_flow_port *port, int port_id, struct doca_flow_pipe **pipe)
static struct doca_flow_actions actions
Definition: flow_parser.c:107
#define BE_IPV4_ADDR(a, b, c, d)
Definition: flow_parser.c:64
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 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_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_lpm_add_entry(uint16_t pipe_queue, struct doca_flow_pipe *pipe, const struct doca_flow_match *match, const struct doca_flow_match *match_mask, const struct doca_flow_actions *actions, const struct doca_flow_monitor *monitor, const struct doca_flow_fwd *fwd, const enum doca_flow_flags_type flag, void *usr_ctx, struct doca_flow_pipe_entry **entry)
Add one new entry to a lpm 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_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_PIPE_LPM
Definition: doca_flow.h:225
@ DOCA_FLOW_L3_META_IPV4
Definition: doca_flow.h:296
@ DOCA_FLOW_NO_WAIT
Definition: doca_flow.h:115
@ DOCA_FLOW_WAIT_FOR_BATCH
Definition: doca_flow.h:117
@ 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_CHANGEABLE
Definition: doca_flow.h:756
@ DOCA_FLOW_FWD_DROP
Definition: doca_flow.h:748
#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
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 ARRAY_INIT(array, val)
Definition: flow_common.h:71
doca flow actions information
Definition: doca_flow.h:684
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
struct doca_flow_header_ip4 ip4
Definition: doca_flow.h:449
enum doca_flow_l3_type l3_type
Definition: doca_flow.h:446
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
flow resource query
Definition: doca_flow.h:1101
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