NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_hash_pipe_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 <string.h>
27 #include <unistd.h>
28 
29 #include <rte_byteorder.h>
30 
31 #include <doca_log.h>
32 #include <doca_flow.h>
33 
34 #include "flow_common.h"
35 #include "flow_switch_common.h"
36 
37 DOCA_LOG_REGISTER(FLOW_HASH_PIPE);
38 
39 #define NB_ENTRIES 2 /* number of entries in the created hash pipe */
40 
41 static struct doca_flow_pipe_entry *entries[NB_ENTRIES]; /* array for storing created entries */
42 
43 /*
44  * Create DOCA Flow hash pipe on the switch port.
45  * The hash pipe calculates the entry index based on IPv4 destination address;
46  * the indicated fields in match_mask variable.
47  *
48  * @port [in]: port of the pipe
49  * @pipe [out]: created pipe pointer
50  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
51  */
52 static doca_error_t create_hash_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
53 {
56  struct doca_flow_fwd fwd;
57  struct doca_flow_pipe_cfg *pipe_cfg;
59 
60  memset(&match_mask, 0, sizeof(match_mask));
61  memset(&monitor, 0, sizeof(monitor));
62  memset(&fwd, 0, sizeof(fwd));
63 
64  /* match mask defines which header fields to use in order to calculate the entry index */
66  match_mask.outer.ip4.dst_ip = 0xffffffff;
67 
69 
70  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
71  if (result != DOCA_SUCCESS) {
72  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
73  return result;
74  }
75 
76  result = set_flow_pipe_cfg(pipe_cfg, "HASH_PIPE", DOCA_FLOW_PIPE_HASH, true);
77  if (result != DOCA_SUCCESS) {
78  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
79  goto destroy_pipe_cfg;
80  }
82  if (result != DOCA_SUCCESS) {
83  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
84  goto destroy_pipe_cfg;
85  }
87  if (result != DOCA_SUCCESS) {
88  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
89  goto destroy_pipe_cfg;
90  }
92  if (result != DOCA_SUCCESS) {
93  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
94  goto destroy_pipe_cfg;
95  }
96 
97  /* FWD component is defined per entry */
99  fwd.port_id = 0xffff;
100 
101  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
103  doca_flow_pipe_cfg_destroy(pipe_cfg);
104  return result;
105 }
106 
107 /*
108  * Create DOCA Flow hash pipe on the switch port.
109  * The hash pipe is used only by SW to manually calculate the hash
110  *
111  * @port [in]: port of the pipe
112  * @pipe [out]: created pipe pointer
113  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
114  */
115 static doca_error_t create_hash_pipe_sw(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
116 {
118  struct doca_flow_monitor monitor;
119  struct doca_flow_fwd fwd;
120  struct doca_flow_pipe_cfg *pipe_cfg;
122 
123  memset(&match_mask, 0, sizeof(match_mask));
124  memset(&monitor, 0, sizeof(monitor));
125  memset(&fwd, 0, sizeof(fwd));
126 
127  /*
128  * Since we want to calculate the hash for the pipe in the HW
129  * we must use exactly the same matching.
130  */
132  match_mask.outer.ip4.dst_ip = 0xffffffff;
133 
134  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
135  if (result != DOCA_SUCCESS) {
136  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
137  return result;
138  }
139 
140  result = set_flow_pipe_cfg(pipe_cfg, "HASH_PIPE", DOCA_FLOW_PIPE_HASH, false);
141  if (result != DOCA_SUCCESS) {
142  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
143  goto destroy_pipe_cfg;
144  }
146  if (result != DOCA_SUCCESS) {
147  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %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  }
156  if (result != DOCA_SUCCESS) {
157  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
158  goto destroy_pipe_cfg;
159  }
160 
161  /* The action must be fixed */
163  fwd.port_id = 0x1;
164 
165  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
167  doca_flow_pipe_cfg_destroy(pipe_cfg);
168  return result;
169 }
170 
171 /*
172  * Add DOCA Flow pipe entries to the hash pipe.
173  * First entry forwards "matched" packets to the first port representor, and the second entry forwards "matched" packets
174  * to the second one.
175  *
176  * @pipe [in]: pipe of the entry
177  * @status [in]: user context for adding entry
178  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
179  */
180 static doca_error_t add_hash_pipe_entries(struct doca_flow_pipe *pipe, struct entries_status *status)
181 {
182  struct doca_flow_fwd fwd;
185  int entry_index = 0;
186 
187  memset(&fwd, 0, sizeof(fwd));
188 
189  for (entry_index = 0; entry_index < NB_ENTRIES; entry_index++) {
190  /* entry index is calculated as follows: hash_func( destination IPv4 address ) mod nb_flows; the hash
191  * output is the entry index to be used */
193  fwd.port_id = entry_index + 1; /* The port to forward to is defined based on the entry index */
194 
195  /* last entry should be inserted with DOCA_FLOW_NO_WAIT flag */
196  if (entry_index == NB_ENTRIES - 1)
197  flags = DOCA_FLOW_NO_WAIT;
198 
200  pipe,
201  entry_index,
202  NULL,
203  NULL,
204  &fwd,
205  flags,
206  status,
207  &entries[entry_index]);
208 
209  if (result != DOCA_SUCCESS) {
210  DOCA_LOG_ERR("Failed to add hash pipe entry: %s", doca_error_get_descr(result));
211  return result;
212  }
213  }
214 
215  return DOCA_SUCCESS;
216 }
217 
218 /*
219  * Calculate hash for a given pipe
220  *
221  * @pipe [in]: pipe to be used for hash calculation
222  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
223  */
224 static doca_error_t calc_hash(struct doca_flow_pipe *pipe)
225 {
226  struct doca_flow_match match;
227  uint32_t hash;
228 
229  memset(&match, 0, sizeof(match));
230 
231  /* match mask defines which header fields to use in order to calculate the entry index */
233  match.outer.ip4.dst_ip = htobe32(0xc0a80101); /* 192.168.1.1 */
234 
235  doca_flow_pipe_calc_hash(pipe, &match, &hash);
236  DOCA_LOG_INFO("Hash value for %x is %u", match.outer.ip4.dst_ip, hash);
237 
238  return DOCA_SUCCESS;
239 }
240 
241 /*
242  * Run flow_hash_pipe sample
243  *
244  * @nb_queues [in]: number of queues the sample will use
245  * @nb_ports [in]: number of ports the sample will use
246  * @ctx [in]: flow switch context the sample will use
247  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
248  */
250 {
251  struct flow_resources resource = {0};
252  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
253  struct doca_flow_port *ports[nb_ports];
254  struct doca_dev *dev_arr[nb_ports];
255  uint32_t actions_mem_size[nb_ports];
256  struct doca_flow_pipe *hash_pipe;
257  struct doca_flow_pipe *hash_pipe_sw;
258  struct doca_flow_resource_query query_stats;
259  struct entries_status status;
260  int num_of_entries = NB_ENTRIES;
262  int entry_idx;
263 
264  memset(&status, 0, sizeof(status));
265  resource.nr_counters = NB_ENTRIES; /* counter per entry */
266 
267  result = init_doca_flow(nb_queues, "switch,hws", &resource, nr_shared_resources);
268  if (result != DOCA_SUCCESS) {
269  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
270  return result;
271  }
272 
273  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
274  dev_arr[0] = ctx->doca_dev[0];
275  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_queues, num_of_entries));
277  if (result != DOCA_SUCCESS) {
278  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
280  return result;
281  }
282 
284  if (result != DOCA_SUCCESS) {
285  DOCA_LOG_ERR("Failed to create pipe: %s", doca_error_get_descr(result));
288  return result;
289  }
290 
292  if (result != DOCA_SUCCESS) {
293  DOCA_LOG_ERR("Failed to create pipe: %s", doca_error_get_descr(result));
296  return result;
297  }
298 
299  result = add_hash_pipe_entries(hash_pipe, &status);
300  if (result != DOCA_SUCCESS) {
301  DOCA_LOG_ERR("Failed to add entries to hash pipe: %s", doca_error_get_descr(result));
304  return result;
305  }
306  calc_hash(hash_pipe_sw);
308  if (result != DOCA_SUCCESS) {
309  DOCA_LOG_ERR("Failed to process entries: %s", doca_error_get_descr(result));
312  return result;
313  }
314 
315  if (status.nb_processed != num_of_entries || status.failure) {
316  DOCA_LOG_ERR("Failed to process entries");
319  return DOCA_ERROR_BAD_STATE;
320  }
321 
322  DOCA_LOG_INFO("Wait few seconds for packets to arrive");
323  sleep(15);
324 
325  /* dump entries counters */
326  for (entry_idx = 0; entry_idx < NB_ENTRIES; entry_idx++) {
328  if (result != DOCA_SUCCESS) {
329  DOCA_LOG_ERR("Failed to query entry: %s", doca_error_get_descr(result));
332  return result;
333  }
334  DOCA_LOG_INFO("Entry in index: %d", entry_idx);
335  DOCA_LOG_INFO("Total bytes: %ld", query_stats.counter.total_bytes);
336  DOCA_LOG_INFO("Total packets: %ld", query_stats.counter.total_pkts);
337  }
338 
341  return result;
342 }
#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 destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static doca_error_t add_hash_pipe_entries(struct doca_flow_pipe *pipe, struct entries_status *status)
static doca_error_t create_hash_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
static struct doca_flow_pipe_entry * entries[NB_ENTRIES]
static doca_error_t calc_hash(struct doca_flow_pipe *pipe)
#define NB_ENTRIES
DOCA_LOG_REGISTER(FLOW_HASH_PIPE)
doca_error_t flow_hash_pipe(int nb_queues, int nb_ports, struct flow_switch_ctx *ctx)
static doca_error_t create_hash_pipe_sw(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
static struct doca_flow_monitor monitor
Definition: flow_parser.c:108
static struct doca_flow_fwd fwd
Definition: flow_parser.c:109
static struct doca_flow_match match_mask
Definition: flow_parser.c:106
#define DEFAULT_TIMEOUT_US
Definition: flow_skeleton.c:36
static uint8_t entry_idx
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_flow_flags_type
doca flow flags type
Definition: doca_flow.h:114
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_calc_hash(struct doca_flow_pipe *pipe, const struct doca_flow_match *match, uint32_t *hash)
calc the hash for a given match on a given pipe.
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_STABLE void doca_flow_destroy(void)
Destroy the doca flow.
DOCA_EXPERIMENTAL doca_error_t doca_flow_pipe_hash_add_entry(uint16_t pipe_queue, struct doca_flow_pipe *pipe, uint32_t entry_index, const struct doca_flow_actions *actions, const struct doca_flow_monitor *monitor, const struct doca_flow_fwd *fwd, const enum doca_flow_flags_type flags, void *usr_ctx, struct doca_flow_pipe_entry **entry)
Add one new entry to an hash pipe.
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 struct doca_flow_port * doca_flow_port_switch_get(const struct doca_flow_port *port)
Get doca flow switch port.
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_HASH
Definition: doca_flow.h:233
@ 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
#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
#define htobe32
Definition: os_utils.hpp:40
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 * 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_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
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
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
struct upf_accel_ctx * ctx