2021-10-26 15:17:39 +02:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <linux/if_link.h> /* XDP_FLAGS_* depend on kernel-headers installed */
|
|
|
|
#include <linux/if_xdp.h>
|
2021-11-16 20:12:04 +01:00
|
|
|
#include <sched.h>
|
2021-10-26 15:17:39 +02:00
|
|
|
|
|
|
|
#include "common_params.h"
|
|
|
|
|
|
|
|
int verbose = 1;
|
2021-10-29 15:54:10 +02:00
|
|
|
int debug = 0;
|
2021-10-29 14:53:33 +02:00
|
|
|
int debug_pkt = 0;
|
2021-10-29 15:54:10 +02:00
|
|
|
int debug_meta = 0;
|
2022-01-07 17:38:19 +01:00
|
|
|
int debug_time = 0;
|
2021-10-26 15:17:39 +02:00
|
|
|
|
|
|
|
#define BUFSIZE 30
|
|
|
|
|
|
|
|
void _print_options(const struct option_wrapper *long_options, bool required)
|
|
|
|
{
|
|
|
|
int i, pos;
|
|
|
|
char buf[BUFSIZE];
|
|
|
|
|
|
|
|
for (i = 0; long_options[i].option.name != 0; i++) {
|
|
|
|
if (long_options[i].required != required)
|
|
|
|
continue;
|
|
|
|
|
2021-12-14 13:52:27 +01:00
|
|
|
if (long_options[i].option.val > 64) /* ord('A') = 65 = 0x41 */
|
2021-10-26 15:17:39 +02:00
|
|
|
printf(" -%c,", long_options[i].option.val);
|
|
|
|
else
|
|
|
|
printf(" ");
|
|
|
|
pos = snprintf(buf, BUFSIZE, " --%s", long_options[i].option.name);
|
|
|
|
if (long_options[i].metavar)
|
|
|
|
snprintf(&buf[pos], BUFSIZE-pos, " %s", long_options[i].metavar);
|
|
|
|
printf("%-22s", buf);
|
|
|
|
printf(" %s", long_options[i].help);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void usage(const char *prog_name, const char *doc,
|
|
|
|
const struct option_wrapper *long_options, bool full)
|
|
|
|
{
|
|
|
|
printf("Usage: %s [options]\n", prog_name);
|
|
|
|
|
|
|
|
if (!full) {
|
|
|
|
printf("Use --help (or -h) to see full option list.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("\nDOCUMENTATION:\n %s\n", doc);
|
|
|
|
printf("Required options:\n");
|
|
|
|
_print_options(long_options, true);
|
|
|
|
printf("\n");
|
|
|
|
printf("Other options:\n");
|
|
|
|
_print_options(long_options, false);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int option_wrappers_to_options(const struct option_wrapper *wrapper,
|
|
|
|
struct option **options)
|
|
|
|
{
|
|
|
|
int i, num;
|
|
|
|
struct option *new_options;
|
|
|
|
for (i = 0; wrapper[i].option.name != 0; i++) {}
|
|
|
|
num = i;
|
|
|
|
|
|
|
|
new_options = malloc(sizeof(struct option) * num);
|
|
|
|
if (!new_options)
|
|
|
|
return -1;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
memcpy(&new_options[i], &wrapper[i], sizeof(struct option));
|
|
|
|
}
|
|
|
|
|
|
|
|
*options = new_options;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_cmdline_args(int argc, char **argv,
|
|
|
|
const struct option_wrapper *options_wrapper,
|
|
|
|
struct config *cfg, const char *doc)
|
|
|
|
{
|
|
|
|
struct option *long_options;
|
|
|
|
bool full_help = false;
|
|
|
|
int longindex = 0;
|
|
|
|
char *dest;
|
|
|
|
int opt;
|
|
|
|
|
|
|
|
if (option_wrappers_to_options(options_wrapper, &long_options)) {
|
|
|
|
fprintf(stderr, "Unable to malloc()\n");
|
|
|
|
exit(EXIT_FAIL_OPTION);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse commands line args */
|
2022-01-14 11:12:24 +01:00
|
|
|
while ((opt = getopt_long(argc, argv, "hd:r:L:R:BASNFUMQ:G:H:czqp:ti:",
|
2021-10-26 15:17:39 +02:00
|
|
|
long_options, &longindex)) != -1) {
|
|
|
|
switch (opt) {
|
|
|
|
case 'd':
|
|
|
|
if (strlen(optarg) >= IF_NAMESIZE) {
|
|
|
|
fprintf(stderr, "ERR: --dev name too long\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
cfg->ifname = (char *)&cfg->ifname_buf;
|
|
|
|
strncpy(cfg->ifname, optarg, IF_NAMESIZE);
|
|
|
|
cfg->ifindex = if_nametoindex(cfg->ifname);
|
|
|
|
if (cfg->ifindex == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"ERR: --dev name unknown err(%d):%s\n",
|
|
|
|
errno, strerror(errno));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
if (strlen(optarg) >= IF_NAMESIZE) {
|
|
|
|
fprintf(stderr, "ERR: --redirect-dev name too long\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
cfg->redirect_ifname = (char *)&cfg->redirect_ifname_buf;
|
|
|
|
strncpy(cfg->redirect_ifname, optarg, IF_NAMESIZE);
|
|
|
|
cfg->redirect_ifindex = if_nametoindex(cfg->redirect_ifname);
|
|
|
|
if (cfg->redirect_ifindex == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"ERR: --redirect-dev name unknown err(%d):%s\n",
|
|
|
|
errno, strerror(errno));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
2021-12-14 13:52:27 +01:00
|
|
|
case 'G':
|
|
|
|
if (!ether_aton_r(optarg,
|
|
|
|
(struct ether_addr *)&cfg->opt_tx_dmac)) {
|
|
|
|
fprintf(stderr, "Invalid dest MAC address:%s\n",
|
|
|
|
optarg);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
if (!ether_aton_r(optarg,
|
|
|
|
(struct ether_addr *)&cfg->opt_tx_smac)) {
|
|
|
|
fprintf(stderr, "Invalid src MAC address:%s\n",
|
|
|
|
optarg);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
break;
|
2021-12-14 12:26:12 +01:00
|
|
|
case 'B':
|
|
|
|
cfg->opt_busy_poll = true;
|
|
|
|
break;
|
2021-10-26 15:17:39 +02:00
|
|
|
case 'A':
|
|
|
|
cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */
|
|
|
|
cfg->xdp_flags |= XDP_FLAGS_SKB_MODE; /* Set flag */
|
2021-11-16 17:12:29 +01:00
|
|
|
cfg->xsk_bind_flags &= ~XDP_ZEROCOPY; /* Clear flag */
|
|
|
|
cfg->xsk_bind_flags |= XDP_COPY; /* Set flag */
|
2021-10-26 15:17:39 +02:00
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */
|
|
|
|
cfg->xdp_flags |= XDP_FLAGS_DRV_MODE; /* Set flag */
|
|
|
|
break;
|
|
|
|
case 3: /* --offload-mode */
|
|
|
|
cfg->xdp_flags &= ~XDP_FLAGS_MODES; /* Clear flags */
|
|
|
|
cfg->xdp_flags |= XDP_FLAGS_HW_MODE; /* Set flag */
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
cfg->xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
cfg->reuse_maps = true;
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
cfg->do_unload = true;
|
|
|
|
break;
|
2021-11-12 10:59:37 +01:00
|
|
|
case 'w':
|
|
|
|
cfg->xsk_wakeup_mode = true;
|
2021-10-26 15:17:39 +02:00
|
|
|
break;
|
2021-11-12 11:47:48 +01:00
|
|
|
case 's':
|
|
|
|
cfg->xsk_wakeup_mode = false;
|
|
|
|
break;
|
2021-10-26 15:17:39 +02:00
|
|
|
case 'q':
|
|
|
|
verbose = false;
|
|
|
|
break;
|
2021-10-29 15:54:10 +02:00
|
|
|
case 'D':
|
|
|
|
debug = true;
|
|
|
|
break;
|
2021-10-29 14:53:33 +02:00
|
|
|
case 'P':
|
|
|
|
debug_pkt = true;
|
|
|
|
break;
|
2021-11-16 20:12:04 +01:00
|
|
|
case 'p':
|
|
|
|
cfg->sched_prio = atoi(optarg);
|
|
|
|
cfg->sched_policy = SCHED_FIFO;
|
|
|
|
break;
|
2021-10-29 15:54:10 +02:00
|
|
|
case 'm':
|
|
|
|
debug_meta = true;
|
|
|
|
break;
|
2022-01-07 17:38:19 +01:00
|
|
|
case 't':
|
|
|
|
debug_time = true;
|
|
|
|
break;
|
2021-10-26 15:17:39 +02:00
|
|
|
case 'Q':
|
|
|
|
cfg->xsk_if_queue = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 1: /* --filename */
|
|
|
|
dest = (char *)&cfg->filename;
|
|
|
|
strncpy(dest, optarg, sizeof(cfg->filename));
|
|
|
|
break;
|
|
|
|
case 2: /* --progsec */
|
|
|
|
dest = (char *)&cfg->progsec;
|
|
|
|
strncpy(dest, optarg, sizeof(cfg->progsec));
|
|
|
|
break;
|
|
|
|
case 'L': /* --src-mac */
|
|
|
|
dest = (char *)&cfg->src_mac;
|
|
|
|
strncpy(dest, optarg, sizeof(cfg->src_mac));
|
|
|
|
break;
|
|
|
|
case 'R': /* --dest-mac */
|
|
|
|
dest = (char *)&cfg->dest_mac;
|
|
|
|
strncpy(dest, optarg, sizeof(cfg->dest_mac));
|
|
|
|
break;
|
2022-01-14 11:12:24 +01:00
|
|
|
case 'i':
|
|
|
|
cfg->interval = atoi(optarg);
|
|
|
|
break;
|
2021-10-26 15:17:39 +02:00
|
|
|
case 'c':
|
2021-11-16 17:12:29 +01:00
|
|
|
cfg->xsk_bind_flags &= ~XDP_ZEROCOPY; /* Clear flag */
|
|
|
|
cfg->xsk_bind_flags |= XDP_COPY; /* Set flag */
|
2021-10-26 15:17:39 +02:00
|
|
|
break;
|
|
|
|
case 'z':
|
2021-11-16 17:12:29 +01:00
|
|
|
cfg->xsk_bind_flags &= ~XDP_COPY; /* Clear flag */
|
|
|
|
cfg->xsk_bind_flags |= XDP_ZEROCOPY; /* Set flag */
|
2021-10-26 15:17:39 +02:00
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
full_help = true;
|
|
|
|
/* fall-through */
|
|
|
|
error:
|
|
|
|
default:
|
|
|
|
usage(argv[0], doc, options_wrapper, full_help);
|
|
|
|
free(long_options);
|
|
|
|
exit(EXIT_FAIL_OPTION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(long_options);
|
|
|
|
}
|