NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_rss_esp_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 <string.h>
27 #include <unistd.h>
28 
29 #include <rte_ethdev.h>
30 
31 #include <doca_log.h>
32 #include <doca_flow.h>
33 
34 #include "flow_common.h"
35 
36 DOCA_LOG_REGISTER(FLOW_RSS_ESP);
37 
38 /* The number of packets in the rx queue */
39 #define PACKET_BURST 256
40 
41 /* Get the percentage according to part and total */
42 #define GET_PERCENTAGE(part, total) (((double)part / (double)total) * 100)
43 
44 /* The number of seconds app waits for traffic to come */
45 #define WAITING_TIME 15
46 
47 /*
48  * Create DOCA Flow pipe with header existence match, copy action, counter and forward RSS.
49  *
50  * @port [in]: port of the pipe.
51  * @nb_rss_queues [in]: number of RSS queues used by pipe FWD action.
52  * @pipe [out]: created pipe pointer.
53  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
54  */
55 static doca_error_t create_rss_esp_pipe(struct doca_flow_port *port,
56  uint32_t nb_rss_queues,
57  struct doca_flow_pipe **pipe)
58 {
59  struct doca_flow_match match;
60  struct doca_flow_action_desc desc;
61  struct doca_flow_action_descs descs = {.nb_action_desc = 1, .desc_array = &desc};
62  struct doca_flow_action_descs *desc_list[] = {&descs};
63  struct doca_flow_monitor counter;
64  struct doca_flow_fwd fwd;
65  struct doca_flow_fwd fwd_miss;
66  struct doca_flow_pipe_cfg *pipe_cfg;
67  uint16_t *rss_queues;
69  uint32_t i;
70 
71  memset(&match, 0, sizeof(match));
72  memset(&desc, 0, sizeof(desc));
73  memset(&counter, 0, sizeof(counter));
74  memset(&fwd, 0, sizeof(fwd));
75  memset(&fwd_miss, 0, sizeof(fwd_miss));
76 
77  rss_queues = calloc(nb_rss_queues, sizeof(*rss_queues));
78  if (rss_queues == NULL) {
79  DOCA_LOG_ERR("Failed to allocate RSS queues array memory");
80  return DOCA_ERROR_NO_MEMORY;
81  }
82 
83  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
84  if (result != DOCA_SUCCESS) {
85  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
86  free(rss_queues);
87  return result;
88  }
89 
90  result = set_flow_pipe_cfg(pipe_cfg, "RSS_ESP_PIPE", DOCA_FLOW_PIPE_BASIC, true);
91  if (result != DOCA_SUCCESS) {
92  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
93  goto destroy_pipe_cfg;
94  }
95 
97  if (result != DOCA_SUCCESS) {
98  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
99  goto destroy_pipe_cfg;
100  }
101 
102  /* IPv4 and ESP existing match */
105  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
106  if (result != DOCA_SUCCESS) {
107  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
108  goto destroy_pipe_cfg;
109  }
110 
111  /* prepare copy action */
113  desc.field_op.src.field_string = "tunnel.esp.spi";
114  desc.field_op.dst.field_string = "meta.data";
115  desc.field_op.width = 32;
117  if (result != DOCA_SUCCESS) {
118  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg descs: %s", doca_error_get_descr(result));
119  goto destroy_pipe_cfg;
120  }
121 
123  result = doca_flow_pipe_cfg_set_monitor(pipe_cfg, &counter);
124  if (result != DOCA_SUCCESS) {
125  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg counter: %s", doca_error_get_descr(result));
126  goto destroy_pipe_cfg;
127  }
128 
129  /* RSS queue - distribute matched traffic between queues */
130  for (i = 0; i < nb_rss_queues; ++i)
131  rss_queues[i] = i;
132 
137  fwd.rss.nr_queues = nb_rss_queues;
138 
140 
141  result = doca_flow_pipe_create(pipe_cfg, &fwd, &fwd_miss, pipe);
143  doca_flow_pipe_cfg_destroy(pipe_cfg);
144  free(rss_queues);
145  return result;
146 }
147 
148 /*
149  * Add DOCA Flow pipe entry.
150  *
151  * @pipe [in]: pipe of the entry.
152  * @port [in]: port of the entry.
153  * @status [in]: user context for adding entry
154  * @entry [out]: created entry pointer.
155  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
156  */
157 static doca_error_t add_rss_esp_pipe_entry(struct doca_flow_pipe *pipe,
158  struct doca_flow_port *port,
159  struct entries_status *status,
160  struct doca_flow_pipe_entry **entry)
161 {
162  struct doca_flow_match match;
164 
165  memset(&match, 0, sizeof(match));
166  memset(status, 0, sizeof(*status));
167 
168  result = doca_flow_pipe_add_entry(0, pipe, &match, NULL, NULL, NULL, 0, status, entry);
169  if (result != DOCA_SUCCESS) {
170  DOCA_LOG_ERR("Failed to insert ESP RSS entry: %s", doca_error_get_descr(result));
171  return result;
172  }
173 
174  result = flow_process_entries(port, status, 1);
175  if (result != DOCA_SUCCESS) {
176  DOCA_LOG_ERR("Failed to process ESP RSS entry: %s", doca_error_get_descr(result));
177  return result;
178  }
179 
180  return DOCA_SUCCESS;
181 }
182 
183 /*
184  * Dequeue packets from DPDK queues and calculates the distribution.
185  *
186  * @port_id [in]: port id for dequeue packets.
187  * @nb_queues [in]: number of RSS queues.
188  * @entry [in]: entry sent packets before distribution.
189  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
190  */
191 static doca_error_t rss_distribution_results(uint16_t port_id, uint16_t nb_queues, struct doca_flow_pipe_entry *entry)
192 {
193  struct rte_mbuf *packets[PACKET_BURST];
195  double actuall_percentage;
196  uint32_t total_packets;
197  uint16_t nb_packets;
198  uint16_t queue_index;
200  int i, j;
201 
203  if (result != DOCA_SUCCESS) {
204  DOCA_LOG_ERR("Port %u failed to query RSS ESP entry: %s", port_id, doca_error_get_descr(result));
205  return result;
206  }
207 
208  total_packets = stats.counter.total_pkts;
209  if (total_packets == 0) {
210  DOCA_LOG_DBG("Port %d doesn't receive any packet", port_id);
211  return DOCA_SUCCESS;
212  }
213 
214  DOCA_LOG_INFO("Port %d RSS distribution information:", port_id);
215 
216  for (i = 0; i < nb_queues; i++) {
217  queue_index = i;
218  nb_packets = rte_eth_rx_burst(port_id, queue_index, packets, PACKET_BURST);
219  actuall_percentage = GET_PERCENTAGE(nb_packets, total_packets);
220 
221  DOCA_LOG_INFO("Queue %u received %u packets which is %g%% of the traffic (%u/%u)",
222  queue_index,
223  nb_packets,
224  actuall_percentage,
225  nb_packets,
226  total_packets);
227 
228  for (j = 0; j < nb_packets; j++) {
229  uint32_t metadata = 0;
230 
231  if (rte_flow_dynf_metadata_avail())
232  metadata = *RTE_FLOW_DYNF_METADATA(packets[j]);
233 
234  DOCA_LOG_DBG("Queue %u packet %d ESP SPI is 0x%08x", queue_index, j, metadata);
235  }
236  }
237 
238  return DOCA_SUCCESS;
239 }
240 
241 /*
242  * Run flow_rss_esp sample
243  *
244  * @nb_steering_queues [in]: number of steering queues the sample will use
245  * @nb_rss_queues [in]: number of rss queues the sample will use
246  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
247  */
248 doca_error_t flow_rss_esp(int nb_steering_queues, int nb_rss_queues)
249 {
250  const int nb_ports = 2;
251  struct flow_resources resource = {.nr_counters = 1};
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_entry *entries[nb_ports];
257  struct doca_flow_pipe *pipe;
258  struct entries_status status;
260  int port_id;
261 
262  result = init_doca_flow(nb_steering_queues, "vnf,hws", &resource, nr_shared_resources);
263  if (result != DOCA_SUCCESS) {
264  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
265  return result;
266  }
267 
268  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
269  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_steering_queues, 1));
271  if (result != DOCA_SUCCESS) {
272  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
274  return result;
275  }
276 
277  for (port_id = 0; port_id < nb_ports; port_id++) {
278  result = create_rss_esp_pipe(ports[port_id], nb_rss_queues, &pipe);
279  if (result != DOCA_SUCCESS) {
280  DOCA_LOG_ERR("Port %d failed to create pipe: %s", port_id, doca_error_get_descr(result));
283  return result;
284  }
285 
286  result = add_rss_esp_pipe_entry(pipe, ports[port_id], &status, &entries[port_id]);
287  if (result != DOCA_SUCCESS) {
288  DOCA_LOG_ERR("Port %d failed to add entry: %s", port_id, doca_error_get_descr(result));
291  return result;
292  }
293  }
294 
295  DOCA_LOG_INFO("Wait %d seconds for packets to arrive", WAITING_TIME);
296  sleep(WAITING_TIME);
297 
298  for (port_id = 0; port_id < nb_ports; port_id++) {
299  result = rss_distribution_results(port_id, nb_rss_queues, entries[port_id]);
300  if (result != DOCA_SUCCESS) {
301  DOCA_LOG_ERR("Port %d failed to query entry: %s", port_id, doca_error_get_descr(result));
304  return result;
305  }
306  }
307 
310  return result;
311 }
#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]
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]
static doca_error_t create_rss_esp_pipe(struct doca_flow_port *port, uint32_t nb_rss_queues, struct doca_flow_pipe **pipe)
DOCA_LOG_REGISTER(FLOW_RSS_ESP)
#define PACKET_BURST
#define GET_PERCENTAGE(part, total)
static doca_error_t add_rss_esp_pipe_entry(struct doca_flow_pipe *pipe, struct doca_flow_port *port, struct entries_status *status, struct doca_flow_pipe_entry **entry)
#define WAITING_TIME
static doca_error_t rss_distribution_results(uint16_t port_id, uint16_t nb_queues, struct doca_flow_pipe_entry *entry)
doca_error_t flow_rss_esp(int nb_steering_queues, int nb_rss_queues)
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_ERROR_NO_MEMORY
Definition: doca_error.h:45
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_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_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_RSS_ESP
Definition: doca_flow.h:772
@ DOCA_FLOW_PIPE_BASIC
Definition: doca_flow.h:221
@ DOCA_FLOW_L3_META_IPV4
Definition: doca_flow.h:296
@ DOCA_FLOW_ACTION_COPY
Definition: doca_flow.h:1012
@ DOCA_FLOW_RESOURCE_TYPE_NON_SHARED
Definition: doca_flow.h:615
@ DOCA_FLOW_FWD_DROP
Definition: doca_flow.h:748
@ DOCA_FLOW_FWD_RSS
Definition: doca_flow.h:742
@ 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
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
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 ARRAY_INIT(array, val)
Definition: flow_common.h:71
action description
Definition: doca_flow.h:1019
enum doca_flow_action_type type
Definition: doca_flow.h:1020
struct doca_flow_action_desc::@108::@110 field_op
action descriptor array
Definition: doca_flow.h:1033
forwarding configuration
Definition: doca_flow.h:779
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
doca flow matcher information
Definition: doca_flow.h:491
struct doca_flow_parser_meta parser_meta
Definition: doca_flow.h:496
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
enum doca_flow_l4_meta outer_l4_type
Definition: doca_flow.h:383
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