NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
flow_random_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 <rte_ethdev.h>
31 
32 #include <doca_log.h>
33 #include <doca_flow.h>
34 #include <doca_bitfield.h>
35 
36 #include "doca_error.h"
37 #include "flow_common.h"
38 
39 DOCA_LOG_REGISTER(FLOW_RANDOM);
40 
41 /* The number of packets in the rx queue */
42 #define PACKET_BURST 256
43 
44 /* The number of bits in random field */
45 #define RANDOM_WIDTH 16
46 
47 /* Get the percentage according to part and total */
48 #define GET_PERCENTAGE(part, total) (((double)part / (double)total) * 100)
49 
50 /*
51  * Create DOCA Flow pipe with changeable 5 tuple match as root
52  *
53  * @port [in]: port of the pipe
54  * @pipe [out]: created pipe pointer
55  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
56  */
57 static doca_error_t create_root_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
58 {
59  struct doca_flow_match match;
61  struct doca_flow_fwd fwd;
62  struct doca_flow_pipe_cfg *pipe_cfg;
64 
65  memset(&match, 0, sizeof(match));
66  memset(&monitor, 0, sizeof(monitor));
67  memset(&fwd, 0, sizeof(fwd));
68 
69  /* 5 tuple match */
74  match.outer.ip4.src_ip = 0xffffffff;
75  match.outer.ip4.dst_ip = 0xffffffff;
76  match.outer.tcp.l4_port.src_port = 0xffff;
77  match.outer.tcp.l4_port.dst_port = 0xffff;
78 
79  /* Add counter to see how many packet arrived before sampling/distribution */
81 
82  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
83  if (result != DOCA_SUCCESS) {
84  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
85  return result;
86  }
87 
88  result = set_flow_pipe_cfg(pipe_cfg, "ROOT_PIPE", DOCA_FLOW_PIPE_BASIC, true);
89  if (result != DOCA_SUCCESS) {
90  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
91  goto destroy_pipe_cfg;
92  }
94  if (result != DOCA_SUCCESS) {
95  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
96  goto destroy_pipe_cfg;
97  }
98  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, NULL);
99  if (result != DOCA_SUCCESS) {
100  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
101  goto destroy_pipe_cfg;
102  }
104  if (result != DOCA_SUCCESS) {
105  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
106  goto destroy_pipe_cfg;
107  }
108 
110  fwd.next_pipe = NULL;
111 
112  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
114  doca_flow_pipe_cfg_destroy(pipe_cfg);
115  return result;
116 }
117 
118 /*
119  * Add DOCA Flow pipe entry to the root pipe that forwards the traffic to specific random pipe.
120  *
121  * @pipe [in]: pipe of the entries.
122  * @next_pipe [in]: random pipe to forward the matched traffic.
123  * @src_ip_addr [in]: the source IP address to match on in this entry.
124  * @status [in]: user context for adding entry.
125  * @entry [out]: created entry pointer.
126  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
127  */
128 static doca_error_t add_root_pipe_entry(struct doca_flow_pipe *pipe,
129  struct doca_flow_pipe *next_pipe,
130  doca_be32_t src_ip_addr,
131  struct entries_status *status,
132  struct doca_flow_pipe_entry **entry)
133 {
134  struct doca_flow_match match;
135  struct doca_flow_fwd fwd;
136 
137  memset(&match, 0, sizeof(match));
138  memset(&fwd, 0, sizeof(fwd));
139 
140  match.outer.ip4.dst_ip = BE_IPV4_ADDR(8, 8, 8, 8);
141  match.outer.ip4.src_ip = src_ip_addr;
142  match.outer.tcp.l4_port.dst_port = rte_cpu_to_be_16(80);
143  match.outer.tcp.l4_port.src_port = rte_cpu_to_be_16(1234);
144 
147 
148  return doca_flow_pipe_add_entry(0, pipe, &match, NULL, NULL, &fwd, 0, status, entry);
149 }
150 
151 /*
152  * Add DOCA Flow pipe entries to the root pipe that forwards the traffic to random pipes.
153  *
154  * @pipe [in]: pipe of the entries.
155  * @status [in]: user context for adding entry
156  * @distribution_pipe [in]: distribution random pipe to forward the matched traffic.
157  * @sampling_pipe [in]: sampling random pipe to forward the matched traffic.
158  * @distribution_entry [out]: created distribution entry pointer.
159  * @sampling_entry [out]: created sampling entry pointer.
160  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
161  */
162 static doca_error_t add_root_pipe_entries(struct doca_flow_pipe *pipe,
163  struct entries_status *status,
164  struct doca_flow_pipe *distribution_pipe,
165  struct doca_flow_pipe *sampling_pipe,
166  struct doca_flow_pipe_entry **distribution_entry,
167  struct doca_flow_pipe_entry **sampling_entry)
168 {
169  doca_be32_t src_ip_addr;
171 
172  src_ip_addr = BE_IPV4_ADDR(1, 1, 1, 1);
173  result = add_root_pipe_entry(pipe, sampling_pipe, src_ip_addr, status, sampling_entry);
174  if (result != DOCA_SUCCESS) {
175  DOCA_LOG_ERR("Failed to add entry - go to sampling pipe: %s", doca_error_get_descr(result));
176  return result;
177  }
178 
179  src_ip_addr = BE_IPV4_ADDR(2, 2, 2, 2);
180  result = add_root_pipe_entry(pipe, distribution_pipe, src_ip_addr, status, distribution_entry);
181  if (result != DOCA_SUCCESS) {
182  DOCA_LOG_ERR("Failed to add entry - go to distribution pipe: %s", doca_error_get_descr(result));
183  return result;
184  }
185 
186  return DOCA_SUCCESS;
187 }
188 
189 /*
190  * Calculate the mask used to achieve given certain percentage.
191  *
192  * The function finds the nearest supported percentage which is not bigger than requested
193  * percentage and calculates mask for it.
194  * The supported percentages are: [50, 25, 12.5, ... , 0.0015258789].
195  *
196  * @percentage [in]: the certain percentage user wish to get in sampling.
197  * @return: value to use in match_mask.parser_meta.random field for getting this percentage.
198  */
199 static uint16_t get_random_mask(double percentage)
200 {
201  double next_highest_supported_percentage = 50;
202  uint16_t mask;
203  uint8_t i;
204 
205  for (i = 1; i <= RANDOM_WIDTH; ++i) {
206  if (percentage >= next_highest_supported_percentage)
207  break;
208 
209  next_highest_supported_percentage /= 2;
210  }
211 
212  if (percentage > next_highest_supported_percentage)
213  DOCA_LOG_WARN("Requested %g%% is not supported, converted to %g%% instead",
214  percentage,
215  next_highest_supported_percentage);
216 
217  mask = (1 << i) - 1;
218  DOCA_LOG_DBG("Get random mask 0x%04x for sampling %g%% of traffic", mask, next_highest_supported_percentage);
219 
220  return mask;
221 }
222 
223 /*
224  * Add DOCA Flow pipe for sampling according to random value
225  *
226  * @port [in]: port of the pipe
227  * @port_id [in]: port ID of the pipe
228  * @percentage [in]: the certain percentage user wish to get in sampling
229  * @pipe [out]: created pipe pointer
230  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
231  */
232 static doca_error_t create_random_sampling_pipe(struct doca_flow_port *port,
233  int port_id,
234  double percentage,
235  struct doca_flow_pipe **pipe)
236 {
237  struct doca_flow_match match;
239  struct doca_flow_monitor monitor;
240  struct doca_flow_fwd fwd;
241  struct doca_flow_pipe_cfg *pipe_cfg;
243 
244  memset(&match, 0, sizeof(match));
245  memset(&match_mask, 0, sizeof(match_mask));
246  memset(&monitor, 0, sizeof(monitor));
247  memset(&fwd, 0, sizeof(fwd));
248 
249  /* Calculate the mask according to requested percentage */
251  /*
252  * Specific value 0, 0 is valid value for any supported percentage.
253  */
254  match.parser_meta.random = 0;
255 
256  /* Add counter to see how many packet are sampled */
258 
259  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
260  if (result != DOCA_SUCCESS) {
261  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
262  return result;
263  }
264 
265  result = set_flow_pipe_cfg(pipe_cfg, "SAMPLING_PIPE", DOCA_FLOW_PIPE_BASIC, false);
266  if (result != DOCA_SUCCESS) {
267  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
268  goto destroy_pipe_cfg;
269  }
271  if (result != DOCA_SUCCESS) {
272  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
273  goto destroy_pipe_cfg;
274  }
275  result = doca_flow_pipe_cfg_set_match(pipe_cfg, &match, &match_mask);
276  if (result != DOCA_SUCCESS) {
277  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
278  goto destroy_pipe_cfg;
279  }
281  if (result != DOCA_SUCCESS) {
282  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg monitor: %s", doca_error_get_descr(result));
283  goto destroy_pipe_cfg;
284  }
285 
287  fwd.port_id = port_id ^ 1;
288 
289  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
291  doca_flow_pipe_cfg_destroy(pipe_cfg);
292  return result;
293 }
294 
295 /*
296  * Add DOCA Flow pipe entry to the random sampling pipe.
297  *
298  * @pipe [in]: pipe of the entries
299  * @status [in]: user context for adding entry
300  * @entry [out]: created entry pointer.
301  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
302  */
303 static doca_error_t add_random_sampling_pipe_entry(struct doca_flow_pipe *pipe,
304  struct entries_status *status,
305  struct doca_flow_pipe_entry **entry)
306 {
307  struct doca_flow_match match;
308 
309  memset(&match, 0, sizeof(match));
310 
311  /*
312  * The values for both fwd and match structures was provided as specific in pipe creation,
313  * no need to provide fresh information here again.
314  */
315 
316  return doca_flow_pipe_add_entry(0, pipe, &match, NULL, NULL, NULL, 0, status, entry);
317 }
318 
319 /*
320  * Add DOCA Flow hash pipe for distribution according to random value.
321  *
322  * @port [in]: port of the pipe
323  * @nb_flows [in]: number of entries for this pipe.
324  * @pipe [out]: created pipe pointer
325  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
326  */
327 static doca_error_t create_random_distribution_pipe(struct doca_flow_port *port,
328  int nb_flows,
329  struct doca_flow_pipe **pipe)
330 {
332  struct doca_flow_fwd fwd;
333  uint16_t rss_queues = 0;
334  struct doca_flow_pipe_cfg *pipe_cfg;
336 
337  memset(&match_mask, 0, sizeof(match_mask));
338  memset(&fwd, 0, sizeof(fwd));
339 
340  /* The distribution is determined by number of entries, we can use full mask */
342 
343  result = doca_flow_pipe_cfg_create(&pipe_cfg, port);
344  if (result != DOCA_SUCCESS) {
345  DOCA_LOG_ERR("Failed to create doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
346  return result;
347  }
348 
349  result = set_flow_pipe_cfg(pipe_cfg, "DISTRIBUTION_PIPE", DOCA_FLOW_PIPE_HASH, false);
350  if (result != DOCA_SUCCESS) {
351  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg: %s", doca_error_get_descr(result));
352  goto destroy_pipe_cfg;
353  }
354  result = doca_flow_pipe_cfg_set_nr_entries(pipe_cfg, nb_flows);
355  if (result != DOCA_SUCCESS) {
356  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg nr_entries: %s", doca_error_get_descr(result));
357  goto destroy_pipe_cfg;
358  }
360  if (result != DOCA_SUCCESS) {
361  DOCA_LOG_ERR("Failed to set doca_flow_pipe_cfg match: %s", doca_error_get_descr(result));
362  goto destroy_pipe_cfg;
363  }
364 
368  fwd.rss.nr_queues = UINT32_MAX;
369 
370  result = doca_flow_pipe_create(pipe_cfg, &fwd, NULL, pipe);
372  doca_flow_pipe_cfg_destroy(pipe_cfg);
373  return result;
374 }
375 
376 /*
377  * Add DOCA Flow pipe entries to the random distribution pipe.
378  *
379  * @pipe [in]: pipe of the entries.
380  * @nb_entries [in]: number of entries to add.
381  * @status [in]: user context for adding entry.
382  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
383  */
384 static doca_error_t add_random_distribution_pipe_entries(struct doca_flow_pipe *pipe,
385  int nb_entries,
386  struct entries_status *status)
387 {
389  struct doca_flow_pipe_entry *entry;
390  struct doca_flow_fwd fwd;
392  uint16_t queue;
393  uint16_t i;
394 
395  memset(&fwd, 0, sizeof(fwd));
396 
399  fwd.rss.queues_array = &queue;
400  fwd.rss.nr_queues = 1;
401 
402  for (i = 0; i < nb_entries; i++) {
403  queue = i;
404 
405  if (i == nb_entries - 1)
406  flags = DOCA_FLOW_NO_WAIT;
407 
408  result = doca_flow_pipe_hash_add_entry(0, pipe, i, NULL, NULL, &fwd, flags, status, &entry);
409  if (result != DOCA_SUCCESS) {
410  DOCA_LOG_ERR("Failed to add hash pipe entry %u: %s", i, doca_error_get_descr(result));
411  return result;
412  }
413  }
414 
415  return DOCA_SUCCESS;
416 }
417 
418 /*
419  * Get results about certain percentage sampling.
420  *
421  * @port_id [in]: port id.
422  * @root_entry [in]: entry sent packets to sampling.
423  * @random_entry [in]: entry samples certain percentage of traffic.
424  * @requested_percentage [in]: the certain percentage user wished to get in sampling.
425  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
426  */
428  struct doca_flow_pipe_entry *root_entry,
429  struct doca_flow_pipe_entry *random_entry,
430  double requested_percentage)
431 {
432  struct doca_flow_resource_query root_query_stats;
433  struct doca_flow_resource_query random_query_stats;
434  double actuall_percentage;
435  uint32_t total_packets;
436  uint32_t nb_packets;
438 
439  result = doca_flow_resource_query_entry(root_entry, &root_query_stats);
440  if (result != DOCA_SUCCESS) {
441  DOCA_LOG_ERR("Failed to query root entry: %s", doca_error_get_descr(result));
442  return result;
443  }
444 
445  total_packets = root_query_stats.counter.total_pkts;
446  if (total_packets == 0)
447  return DOCA_SUCCESS;
448 
449  result = doca_flow_resource_query_entry(random_entry, &random_query_stats);
450  if (result != DOCA_SUCCESS) {
451  DOCA_LOG_ERR("Failed to query random entry: %s", doca_error_get_descr(result));
452  return result;
453  }
454 
455  nb_packets = random_query_stats.counter.total_pkts;
456  actuall_percentage = GET_PERCENTAGE(nb_packets, total_packets);
457 
458  DOCA_LOG_INFO("Port %d sampling information (%g%% is requested):", port_id, requested_percentage);
459  DOCA_LOG_INFO("This pipeline samples %u packets which is %g%% of the traffic (%u/%u)",
460  nb_packets,
461  actuall_percentage,
462  nb_packets,
463  total_packets);
464 
465  return DOCA_SUCCESS;
466 }
467 
468 /*
469  * Dequeue packets from DPDK queues and calculates the distribution.
470  *
471  * @port_id [in]: port id for dequeue packets.
472  * @nb_queues [in]: number of Rx queues.
473  * @root_entry [in]: entry sent packets before distribution.
474  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
475  */
477  uint16_t nb_queues,
478  struct doca_flow_pipe_entry *root_entry)
479 {
480  struct rte_mbuf *packets[PACKET_BURST];
481  struct doca_flow_resource_query root_query_stats;
482  double actuall_percentage, total_percentage = 0;
483  uint32_t total_packets, total_dist_packets = 0;
484  uint16_t nb_packets, nb_hit_queues = 0;
486  int i;
487 
488  result = doca_flow_resource_query_entry(root_entry, &root_query_stats);
489  if (result != DOCA_SUCCESS) {
490  DOCA_LOG_ERR("Failed to query root entry in port %u: %s", port_id, doca_error_get_descr(result));
491  return result;
492  }
493 
494  total_packets = root_query_stats.counter.total_pkts;
495  if (total_packets == 0)
496  return DOCA_SUCCESS;
497 
498  DOCA_LOG_INFO("Port %d distribution information:", port_id);
499 
500  for (i = 0; i < nb_queues; i++) {
501  nb_packets = rte_eth_rx_burst(port_id, i, packets, PACKET_BURST);
502  actuall_percentage = GET_PERCENTAGE(nb_packets, total_packets);
503  total_dist_packets += nb_packets;
504  total_percentage += actuall_percentage;
505  nb_hit_queues += nb_packets ? 1 : 0;
506 
507  DOCA_LOG_INFO("Queue %u received %u packets which is %g%% of the traffic (%u/%u)",
508  i,
509  nb_packets,
510  actuall_percentage,
511  nb_packets,
512  total_packets);
513  }
514 
515  DOCA_LOG_INFO("The distribution pipe received %u packets which is %g%% of the traffic (%u/%u)",
516  total_dist_packets,
517  total_percentage,
518  total_dist_packets,
519  total_packets);
520 
521  if (nb_hit_queues > 1) {
522  DOCA_LOG_INFO("Traffic is distributed on multiple queues");
523  }
524 
525  return DOCA_SUCCESS;
526 }
527 
528 /*
529  * Run flow_random sample.
530  *
531  * This sample tests the 2 common use-cases of random matching:
532  * 1. Sampling certain percentage of traffic.
533  * 2. Random distribution over port/queues.
534  *
535  * @nb_steering_queues [in]: number of steering queues the sample will use
536  * @nb_rss_queues [in]: number of rss queues the sample will use
537  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise.
538  */
539 doca_error_t flow_random(int nb_steering_queues, int nb_rss_queues)
540 {
541  int nb_ports = 2;
542  struct flow_resources resource = {0};
543  uint32_t nr_shared_resources[SHARED_RESOURCE_NUM_VALUES] = {0};
544  struct doca_flow_port *ports[nb_ports];
545  struct doca_dev *dev_arr[nb_ports];
546  uint32_t actions_mem_size[nb_ports];
547  struct doca_flow_pipe *root_pipe;
548  struct doca_flow_pipe *sampling_pipe;
549  struct doca_flow_pipe *distribution_pipe;
550  struct doca_flow_pipe_entry *root2sampling_entry[nb_ports];
551  struct doca_flow_pipe_entry *root2distribution_entry[nb_ports];
552  struct doca_flow_pipe_entry *random_entry[nb_ports];
553  struct entries_status status;
554  double requested_percentage = 12.5;
555  uint32_t num_of_entries = 3 + nb_rss_queues;
557  int port_id;
558 
559  memset(&status, 0, sizeof(status));
560  resource.nr_counters = num_of_entries;
561 
562  result = init_doca_flow(nb_steering_queues, "vnf,hws", &resource, nr_shared_resources);
563  if (result != DOCA_SUCCESS) {
564  DOCA_LOG_ERR("Failed to init DOCA Flow: %s", doca_error_get_descr(result));
565  return result;
566  }
567 
568  memset(dev_arr, 0, sizeof(struct doca_dev *) * nb_ports);
569  ARRAY_INIT(actions_mem_size, ACTIONS_MEM_SIZE(nb_steering_queues, num_of_entries));
571  if (result != DOCA_SUCCESS) {
572  DOCA_LOG_ERR("Failed to init DOCA ports: %s", doca_error_get_descr(result));
574  return result;
575  }
576 
577  for (port_id = 0; port_id < nb_ports; port_id++) {
578  memset(&status, 0, sizeof(status));
579 
580  result = create_random_distribution_pipe(ports[port_id], nb_rss_queues, &distribution_pipe);
581  if (result != DOCA_SUCCESS) {
582  DOCA_LOG_ERR("Failed to create random distribution pipe: %s", doca_error_get_descr(result));
585  return result;
586  }
587 
588  result = add_random_distribution_pipe_entries(distribution_pipe, nb_rss_queues, &status);
589  if (result != DOCA_SUCCESS) {
590  DOCA_LOG_ERR("Failed to add random distribution pipe entries: %s",
594  return result;
595  }
596 
597  result = create_random_sampling_pipe(ports[port_id], port_id, requested_percentage, &sampling_pipe);
598  if (result != DOCA_SUCCESS) {
599  DOCA_LOG_ERR("Failed to create random sampling pipe: %s", doca_error_get_descr(result));
602  return result;
603  }
604 
605  result = add_random_sampling_pipe_entry(sampling_pipe, &status, &random_entry[port_id]);
606  if (result != DOCA_SUCCESS) {
607  DOCA_LOG_ERR("Failed to add random sampling pipe entry: %s", doca_error_get_descr(result));
610  return result;
611  }
612 
613  result = create_root_pipe(ports[port_id], &root_pipe);
614  if (result != DOCA_SUCCESS) {
615  DOCA_LOG_ERR("Failed to create root pipe: %s", doca_error_get_descr(result));
618  return result;
619  }
620 
621  result = add_root_pipe_entries(root_pipe,
622  &status,
623  distribution_pipe,
624  sampling_pipe,
625  &root2distribution_entry[port_id],
626  &root2sampling_entry[port_id]);
627  if (result != DOCA_SUCCESS) {
628  DOCA_LOG_ERR("Failed to add root pipe entries: %s", doca_error_get_descr(result));
631  return result;
632  }
633 
634  result = flow_process_entries(ports[port_id], &status, num_of_entries);
635  if (result != DOCA_SUCCESS) {
636  DOCA_LOG_ERR("Failed to process entries: %s", doca_error_get_descr(result));
639  return result;
640  }
641  }
642 
643  DOCA_LOG_INFO("Wait few seconds for packets to arrive");
644  sleep(15);
645 
646  for (port_id = 0; port_id < nb_ports; port_id++) {
647  /* Show the results for sampling */
649  root2sampling_entry[port_id],
650  random_entry[port_id],
651  requested_percentage);
652  if (result != DOCA_SUCCESS) {
653  DOCA_LOG_ERR("Failed to show sampling results in port %u: %s",
654  port_id,
658  return result;
659  }
660 
661  /* Show the results for distribution */
662  result = random_distribution_results(port_id, nb_rss_queues, root2distribution_entry[port_id]);
663  if (result != DOCA_SUCCESS) {
664  DOCA_LOG_ERR("Failed to show distribution results in port %u: %s",
665  port_id,
669  return result;
670  }
671  }
672 
675  return result;
676 }
#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 int nb_entries
static doca_error_t destroy_pipe_cfg(struct doca_flow_pipe_cfg *cfg)
static uint16_t * rss_queues
Definition: flow_parser.c:114
#define BE_IPV4_ADDR(a, b, c, d)
Definition: flow_parser.c:64
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
static struct doca_flow_pipe_entry * entry[MAX_ENTRIES]
static doca_error_t add_random_sampling_pipe_entry(struct doca_flow_pipe *pipe, struct entries_status *status, struct doca_flow_pipe_entry **entry)
static doca_error_t create_random_sampling_pipe(struct doca_flow_port *port, int port_id, double percentage, struct doca_flow_pipe **pipe)
#define PACKET_BURST
#define GET_PERCENTAGE(part, total)
doca_error_t flow_random(int nb_steering_queues, int nb_rss_queues)
static doca_error_t random_distribution_results(uint16_t port_id, uint16_t nb_queues, struct doca_flow_pipe_entry *root_entry)
static doca_error_t add_random_distribution_pipe_entries(struct doca_flow_pipe *pipe, int nb_entries, struct entries_status *status)
static doca_error_t add_root_pipe_entries(struct doca_flow_pipe *pipe, struct entries_status *status, struct doca_flow_pipe *distribution_pipe, struct doca_flow_pipe *sampling_pipe, struct doca_flow_pipe_entry **distribution_entry, struct doca_flow_pipe_entry **sampling_entry)
static uint16_t get_random_mask(double percentage)
static doca_error_t create_random_distribution_pipe(struct doca_flow_port *port, int nb_flows, struct doca_flow_pipe **pipe)
static doca_error_t create_root_pipe(struct doca_flow_port *port, struct doca_flow_pipe **pipe)
static doca_error_t random_sampling_results(uint16_t port_id, struct doca_flow_pipe_entry *root_entry, struct doca_flow_pipe_entry *random_entry, double requested_percentage)
DOCA_LOG_REGISTER(FLOW_RANDOM)
#define RANDOM_WIDTH
static doca_error_t add_root_pipe_entry(struct doca_flow_pipe *pipe, struct doca_flow_pipe *next_pipe, doca_be32_t src_ip_addr, struct entries_status *status, struct doca_flow_pipe_entry **entry)
#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
@ DOCA_FLOW_L4_TYPE_EXT_TCP
@ 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_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_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_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_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_HASH
Definition: doca_flow.h:233
@ 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_RSS
Definition: doca_flow.h:742
@ DOCA_FLOW_L4_META_TCP
Definition: doca_flow.h:308
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_WARN(format,...)
Generates a WARNING application log message.
Definition: doca_log.h:476
#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
uint32_t doca_be32_t
Definition: doca_types.h:121
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
enum doca_flow_resource_type rss_type
Definition: doca_flow.h:784
struct doca_flow_resource_rss_cfg rss
Definition: doca_flow.h:787
struct doca_flow_header_ip4 ip4
Definition: doca_flow.h:449
enum doca_flow_l4_type_ext l4_type_ext
Definition: doca_flow.h:454
enum doca_flow_l3_type l3_type
Definition: doca_flow.h:446
struct doca_flow_header_tcp tcp
Definition: doca_flow.h:461
struct doca_flow_header_l4_port l4_port
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
enum doca_flow_l4_meta outer_l4_type
Definition: doca_flow.h:383
doca_be16_t random
Definition: doca_flow.h:376
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