NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
ip_frag.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2025 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 <doca_argp.h>
27 #include <doca_dpdk.h>
28 #include <doca_log.h>
29 #include <dpdk_utils.h>
30 #include <doca_flow.h>
31 
32 #include <rte_ethdev.h>
33 
34 #include <signal.h>
35 #include <stdlib.h>
36 
37 #include "ip_frag_dp.h"
38 
39 #define IP_FRAG_TBL_TIMEOUT_MS 2
40 #define IP_FRAG_TBL_SIZE 2048
41 
43 
44 /*
45  * Handle a given signal
46  *
47  * @signum [in]: signal number
48  */
49 static void signal_handler(int signum)
50 {
51  if (signum == SIGINT || signum == SIGTERM) {
52  DOCA_LOG_INFO("Signal %d received, preparing to exit", signum);
53  force_stop = true;
54  }
55 }
56 
57 /*
58  * Callback to handle application mode
59  *
60  * @param [in]: mode string.
61  * @config [in]: Ip_frag config.
62  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
63  */
64 static doca_error_t ip_frag_mode_callback(void *param, void *config)
65 {
66  struct ip_frag_config *cfg = config;
67  const char *mode_str = param;
68 
69  if (!strcmp(mode_str, "bidir")) {
71  } else if (!strcmp(mode_str, "multiport")) {
73  } else {
74  DOCA_LOG_ERR("Unsupported mode: %s", mode_str);
76  }
77 
78  return DOCA_SUCCESS;
79 }
80 
81 /*
82  * Callback to handle application mtu
83  *
84  * @param [in]: MTU integer.
85  * @config [in]: Ip_frag config.
86  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
87  */
88 static doca_error_t ip_frag_mtu_callback(void *param, void *config)
89 {
90  const uint32_t mtu = *(const uint32_t *)param;
91  struct ip_frag_config *cfg = config;
92 
93  if (mtu < RTE_ETHER_MIN_MTU || mtu > RTE_ETHER_MAX_JUMBO_FRAME_LEN) {
94  DOCA_LOG_ERR("Invalid MTU: %u", mtu);
96  }
97  cfg->mtu = mtu;
98 
99  return DOCA_SUCCESS;
100 }
101 
102 /*
103  * Callback to handle fragmentation table timeout in ms
104  *
105  * @param [in]: timeout integer in ms.
106  * @config [in]: Ip_frag config.
107  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
108  */
109 static doca_error_t ip_frag_tbl_timeout_callback(void *param, void *config)
110 {
111  const uint32_t timeout = *(const uint32_t *)param;
112  struct ip_frag_config *cfg = config;
113 
114  cfg->frag_tbl_timeout = timeout;
115 
116  return DOCA_SUCCESS;
117 }
118 
119 /*
120  * Callback to handle fragmentation table size
121  *
122  * @param [in]: size integer.
123  * @config [in]: Ip_frag config.
124  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
125  */
126 static doca_error_t ip_frag_tbl_size_callback(void *param, void *config)
127 {
128  const uint32_t size = *(const uint32_t *)param;
129  struct ip_frag_config *cfg = config;
130 
131  cfg->frag_tbl_size = size;
132 
133  return DOCA_SUCCESS;
134 }
135 
136 /*
137  * Callback to handle fragmentation table size
138  *
139  * @param [in]: size integer.
140  * @config [in]: Ip_frag config.
141  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
142  */
143 static doca_error_t ip_frag_mbuf_chain_callback(void *param, void *config)
144 {
145  const bool mbuf_chain = *(const bool *)param;
146  struct ip_frag_config *cfg = config;
147 
149 
150  return DOCA_SUCCESS;
151 }
152 
153 /*
154  * Callback to handle hardware checksum
155  *
156  * @param [in]: size integer.
157  * @config [in]: Ip_frag config.
158  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
159  */
160 static doca_error_t ip_frag_mbuf_hw_cksum_callback(void *param, void *config)
161 {
162  const bool hw_cksum_disable = *(const bool *)param;
163  struct ip_frag_config *cfg = config;
164 
165  cfg->hw_cksum = !hw_cksum_disable;
166 
167  return DOCA_SUCCESS;
168 }
169 
170 /*
171  * Handle application parameters registration
172  *
173  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
174  */
176 {
177  struct doca_argp_param *app_mode_param;
178  struct doca_argp_param *mtu_param;
179  struct doca_argp_param *frag_tbl_timeout_param;
180  struct doca_argp_param *frag_tbl_size_param;
181  struct doca_argp_param *mbuf_chain_param;
183 
184  /* Create and register ip_frag application mode */
185  result = doca_argp_param_create(&app_mode_param);
186  if (result != DOCA_SUCCESS) {
187  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
188  return result;
189  }
190  doca_argp_param_set_short_name(app_mode_param, "m");
191  doca_argp_param_set_long_name(app_mode_param, "mode");
193  app_mode_param,
194  "Ip_frag application mode."
195  " Bidirectional mode forwards packets between a single reassembly port and a single fragmentation port (two ports in total)."
196  " Multiport mode forwards packets between two pairs of reassembly and fragmentation ports (four ports in total)."
197  " For more information consult DOCA IP Fragmentation Application Guide."
198  " Format: bidir, multiport");
201  doca_argp_param_set_mandatory(app_mode_param);
202  result = doca_argp_register_param(app_mode_param);
203  if (result != DOCA_SUCCESS) {
204  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
205  return result;
206  }
207 
208  /* Create and register ip_frag maximum MTU size */
209  result = doca_argp_param_create(&mtu_param);
210  if (result != DOCA_SUCCESS) {
211  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
212  return result;
213  }
214  doca_argp_param_set_short_name(mtu_param, "u");
215  doca_argp_param_set_long_name(mtu_param, "mtu");
216  doca_argp_param_set_description(mtu_param, "MTU size");
219  result = doca_argp_register_param(mtu_param);
220  if (result != DOCA_SUCCESS) {
221  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
222  return result;
223  }
224 
225  /* Create and register frag table timeout */
226  result = doca_argp_param_create(&frag_tbl_timeout_param);
227  if (result != DOCA_SUCCESS) {
228  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
229  return result;
230  }
231  doca_argp_param_set_short_name(frag_tbl_timeout_param, "t");
232  doca_argp_param_set_long_name(frag_tbl_timeout_param, "frag-aging-timeout");
234  frag_tbl_timeout_param,
235  "Aging timeout of fragments pending packet reassembly in the fragmentation table (in ms)");
237  doca_argp_param_set_type(frag_tbl_timeout_param, DOCA_ARGP_TYPE_INT);
238  result = doca_argp_register_param(frag_tbl_timeout_param);
239  if (result != DOCA_SUCCESS) {
240  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
241  return result;
242  }
243 
244  /* Create and register frag table size */
245  result = doca_argp_param_create(&frag_tbl_size_param);
246  if (result != DOCA_SUCCESS) {
247  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
248  return result;
249  }
250  doca_argp_param_set_short_name(frag_tbl_size_param, "s");
251  doca_argp_param_set_long_name(frag_tbl_size_param, "frag-tbl-size");
253  frag_tbl_size_param,
254  "Frag table size, i.e. maximum amount of concurrent defragmentation contexts per worker thread");
256  doca_argp_param_set_type(frag_tbl_size_param, DOCA_ARGP_TYPE_INT);
257  result = doca_argp_register_param(frag_tbl_size_param);
258  if (result != DOCA_SUCCESS) {
259  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
260  return result;
261  }
262 
263  /* Create and register ip_frag mbuf chaining optimization toggle */
264  result = doca_argp_param_create(&mbuf_chain_param);
265  if (result != DOCA_SUCCESS) {
266  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
267  return result;
268  }
269  doca_argp_param_set_short_name(mbuf_chain_param, "c");
270  doca_argp_param_set_long_name(mbuf_chain_param, "mbuf-chain");
271  doca_argp_param_set_description(mbuf_chain_param,
272  "Enable mbuf chaining (required for IPv6 fragmentation support)");
275  result = doca_argp_register_param(mbuf_chain_param);
276  if (result != DOCA_SUCCESS) {
277  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
278  return result;
279  }
280 
281  /* Create and register ip_frag hardware checksum toggle */
282  result = doca_argp_param_create(&mbuf_chain_param);
283  if (result != DOCA_SUCCESS) {
284  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
285  return result;
286  }
287  doca_argp_param_set_short_name(mbuf_chain_param, "w");
288  doca_argp_param_set_long_name(mbuf_chain_param, "cksum-accel-disable");
289  doca_argp_param_set_description(mbuf_chain_param, "Disable hardware-accelerated checksum calculation");
292  result = doca_argp_register_param(mbuf_chain_param);
293  if (result != DOCA_SUCCESS) {
294  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
295  return result;
296  }
297 
298  return DOCA_SUCCESS;
299 }
300 
302 {
303  uint16_t nb_ports = rte_eth_dev_count_avail();
304 
305  if (nb_ports > IP_FRAG_PORT_NUM) {
306  DOCA_LOG_ERR("Invalid number (%u) of ports, max %u", nb_ports, IP_FRAG_PORT_NUM);
308  }
309  dpdk_config->port_config.nb_ports = nb_ports;
310 
311  return DOCA_SUCCESS;
312 }
313 
314 /*
315  * Set DPDK port tx offload flags
316  *
317  * @cfg [in]: application config
318  * @dpdk_cfg [out]: application DPDK configuration values
319  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
320  */
322  struct application_dpdk_config *dpdk_config)
323 {
324  if (cfg->mbuf_chain)
325  dpdk_config->port_config.tx_offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
326  if (cfg->hw_cksum)
327  dpdk_config->port_config.tx_offloads |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_UDP_CKSUM;
328 
329  return DOCA_SUCCESS;
330 }
331 
332 /*
333  * Validate application mode fits the number of operating ports.
334  *
335  * @mode [in]: application mode.
336  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
337  */
339 {
340  uint32_t num_ports = rte_eth_dev_count_avail();
341 
342  switch (mode) {
343  case IP_FRAG_MODE_BIDIR:
344  if (num_ports != 2) {
345  DOCA_LOG_ERR("Bidir mode requires two ports.");
347  }
348  break;
350  if (num_ports != 4) {
351  DOCA_LOG_ERR("Multiport mode requires four ports.");
353  }
354  break;
355  default:
356  DOCA_LOG_ERR("Unsupported application mode: %u", mode);
358  };
359 
360  return DOCA_SUCCESS;
361 }
362 
363 /*
364  * Application main function
365  *
366  * @argc [in]: command line arguments size
367  * @argv [in]: array of command line arguments
368  * @return: EXIT_SUCCESS on success and EXIT_FAILURE otherwise
369  */
370 int main(int argc, char **argv)
371 {
372  struct application_dpdk_config dpdk_config = {0};
373  struct ip_frag_config cfg = {
374  .mtu = RTE_ETHER_MAX_LEN,
375  .mbuf_chain = false,
376  .hw_cksum = true,
377  .frag_tbl_timeout = IP_FRAG_TBL_TIMEOUT_MS,
378  .frag_tbl_size = IP_FRAG_TBL_SIZE,
379  };
380  struct doca_log_backend *sdk_log;
381  int exit_status = EXIT_FAILURE;
383 
384  /* Register a logger backend */
386  if (result != DOCA_SUCCESS)
387  goto app_exit;
388 
389  /* Register a logger backend for internal SDK errors and warnings */
390  result = doca_log_backend_create_with_file_sdk(stderr, &sdk_log);
391  if (result != DOCA_SUCCESS)
392  goto app_exit;
394  if (result != DOCA_SUCCESS)
395  goto app_exit;
396 
397  DOCA_LOG_INFO("Starting the application, pid %d", getpid());
398 
400  if (result != DOCA_SUCCESS) {
401  DOCA_LOG_ERR("Failed to init ARGP resources: %s", doca_error_get_descr(result));
402  goto app_exit;
403  }
405 
407  if (result != DOCA_SUCCESS) {
408  DOCA_LOG_ERR("Failed to register Flow Ct application parameters: %s", doca_error_get_descr(result));
409  goto argp_cleanup;
410  }
411 
412  result = doca_argp_start(argc, argv);
413  if (result != DOCA_SUCCESS) {
414  DOCA_LOG_ERR("Failed to parse application input: %s", doca_error_get_descr(result));
415  goto argp_cleanup;
416  }
417 
419  if (result != DOCA_SUCCESS) {
420  DOCA_LOG_ERR("Failed to validate mode");
421  goto dpdk_cleanup;
422  }
423 
424  result = ip_frag_dpdk_config_num_ports(&dpdk_config);
425  if (result != DOCA_SUCCESS) {
426  DOCA_LOG_ERR("Failed to configure num ports");
427  goto dpdk_cleanup;
428  }
429 
430  result = ip_frag_dpdk_config_tx_offloads(&cfg, &dpdk_config);
431  if (result != DOCA_SUCCESS) {
432  DOCA_LOG_ERR("Failed to configure tx offloads");
433  goto dpdk_cleanup;
434  }
435 
436  /* update queues and ports */
437  result = dpdk_queues_and_ports_init(&dpdk_config);
438  if (result != DOCA_SUCCESS) {
439  DOCA_LOG_ERR("Failed to update ports and queues");
440  goto dpdk_cleanup;
441  }
442 
443  signal(SIGINT, signal_handler);
444  signal(SIGTERM, signal_handler);
445 
446  /* run app */
447  result = ip_frag(&cfg, &dpdk_config);
448  if (result != DOCA_SUCCESS) {
449  DOCA_LOG_ERR("ip_frag() encountered an error: %s", doca_error_get_descr(result));
450  goto dpdk_ports_queues_cleanup;
451  }
452 
453  exit_status = EXIT_SUCCESS;
454 dpdk_ports_queues_cleanup:
455  dpdk_queues_and_ports_fini(&dpdk_config);
456 dpdk_cleanup:
457  dpdk_fini();
458 argp_cleanup:
460 app_exit:
461  if (exit_status == EXIT_SUCCESS)
462  DOCA_LOG_INFO("Application finished successfully");
463  else
464  DOCA_LOG_INFO("Application finished with errors");
465  return exit_status;
466 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
doca_error_t dpdk_init(int argc, char **argv)
Definition: dpdk_utils.c:907
void dpdk_fini(void)
Definition: dpdk_utils.c:919
doca_error_t dpdk_queues_and_ports_init(struct application_dpdk_config *app_dpdk_config)
Definition: dpdk_utils.c:515
void dpdk_queues_and_ports_fini(struct application_dpdk_config *app_dpdk_config)
Definition: dpdk_utils.c:564
DOCA_EXPERIMENTAL void doca_argp_param_set_description(struct doca_argp_param *param, const char *description)
Set the description of the program param, used during program usage.
DOCA_EXPERIMENTAL void doca_argp_param_set_long_name(struct doca_argp_param *param, const char *name)
Set the long name of the program param.
DOCA_EXPERIMENTAL doca_error_t doca_argp_start(int argc, char **argv)
Parse incoming arguments (cmd line/json).
DOCA_EXPERIMENTAL doca_error_t doca_argp_init(const char *program_name, void *program_config)
Initialize the parser interface.
DOCA_EXPERIMENTAL void doca_argp_set_dpdk_program(doca_argp_dpdk_cb_t callback)
Mark the program as based on DPDK API.
DOCA_EXPERIMENTAL void doca_argp_param_set_callback(struct doca_argp_param *param, doca_argp_param_cb_t callback)
Set the callback function of the program param.
DOCA_EXPERIMENTAL void doca_argp_param_set_mandatory(struct doca_argp_param *param)
Mark the program param as mandatory.
DOCA_EXPERIMENTAL doca_error_t doca_argp_param_create(struct doca_argp_param **param)
Create new program param.
DOCA_EXPERIMENTAL void doca_argp_param_set_type(struct doca_argp_param *param, enum doca_argp_type type)
Set the type of the param arguments.
DOCA_EXPERIMENTAL void doca_argp_param_set_short_name(struct doca_argp_param *param, const char *name)
Set the short name of the program param.
DOCA_EXPERIMENTAL doca_error_t doca_argp_destroy(void)
ARG Parser destroy.
DOCA_EXPERIMENTAL doca_error_t doca_argp_register_param(struct doca_argp_param *input_param)
Register a program flag.
@ DOCA_ARGP_TYPE_STRING
Definition: doca_argp.h:56
@ DOCA_ARGP_TYPE_BOOLEAN
Definition: doca_argp.h:58
@ DOCA_ARGP_TYPE_INT
Definition: doca_argp.h:57
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_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_ERROR_NOT_SUPPORTED
Definition: doca_error.h:42
@ DOCA_SUCCESS
Definition: doca_error.h:38
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_create_standard(void)
Create default, non configurable backend for application messages.
#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_EXPERIMENTAL doca_error_t doca_log_backend_create_with_file_sdk(FILE *fptr, struct doca_log_backend **backend)
Create a logging backend with a FILE* stream for SDK messages.
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_set_sdk_level(struct doca_log_backend *backend, uint32_t level)
Set the log level limit for SDK logging backends.
@ DOCA_LOG_LEVEL_WARNING
Definition: doca_log.h:47
static doca_error_t ip_frag_mode_callback(void *param, void *config)
Definition: ip_frag.c:64
static doca_error_t validate_mode(enum ip_frag_mode mode)
Definition: ip_frag.c:338
#define IP_FRAG_TBL_SIZE
Definition: ip_frag.c:40
int main(int argc, char **argv)
Definition: ip_frag.c:370
static doca_error_t ip_frag_dpdk_config_num_ports(struct application_dpdk_config *dpdk_config)
Definition: ip_frag.c:301
static doca_error_t ip_frag_mtu_callback(void *param, void *config)
Definition: ip_frag.c:88
static doca_error_t ip_frag_tbl_size_callback(void *param, void *config)
Definition: ip_frag.c:126
DOCA_LOG_REGISTER(IP_FRAG)
static doca_error_t ip_frag_register_params(void)
Definition: ip_frag.c:175
#define IP_FRAG_TBL_TIMEOUT_MS
Definition: ip_frag.c:39
static doca_error_t ip_frag_dpdk_config_tx_offloads(struct ip_frag_config *cfg, struct application_dpdk_config *dpdk_config)
Definition: ip_frag.c:321
static doca_error_t ip_frag_mbuf_chain_callback(void *param, void *config)
Definition: ip_frag.c:143
static doca_error_t ip_frag_tbl_timeout_callback(void *param, void *config)
Definition: ip_frag.c:109
static doca_error_t ip_frag_mbuf_hw_cksum_callback(void *param, void *config)
Definition: ip_frag.c:160
static void signal_handler(int signum)
Definition: ip_frag.c:49
doca_error_t ip_frag(struct ip_frag_config *cfg, struct application_dpdk_config *dpdk_cfg)
Definition: ip_frag_dp.c:1243
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
bool force_stop
Definition: ip_frag_dp.c:71
ip_frag_mode
Definition: ip_frag_dp.h:37
@ IP_FRAG_MODE_MULTIPORT
Definition: ip_frag_dp.h:39
@ IP_FRAG_MODE_BIDIR
Definition: ip_frag_dp.h:38
@ IP_FRAG_PORT_NUM
Definition: ip_frag_dp.h:47
struct application_port_config port_config
Definition: dpdk_utils.h:70
uint32_t frag_tbl_size
Definition: ip_frag_dp.h:64
enum ip_frag_mode mode
Definition: ip_frag_dp.h:57
uint32_t frag_tbl_timeout
Definition: ip_frag_dp.h:63
uint16_t mtu
Definition: ip_frag_dp.h:60
static int nb_ports
Definition: switch_core.c:44