xdp_redirect_user.c (4425B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright (c) 2016 John Fastabend <john.r.fastabend@intel.com> 3 */ 4static const char *__doc__ = 5"XDP redirect tool, using bpf_redirect helper\n" 6"Usage: xdp_redirect <IFINDEX|IFNAME>_IN <IFINDEX|IFNAME>_OUT\n"; 7 8#include <linux/bpf.h> 9#include <linux/if_link.h> 10#include <assert.h> 11#include <errno.h> 12#include <signal.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <stdbool.h> 16#include <string.h> 17#include <net/if.h> 18#include <unistd.h> 19#include <libgen.h> 20#include <getopt.h> 21#include <bpf/bpf.h> 22#include <bpf/libbpf.h> 23#include "bpf_util.h" 24#include "xdp_sample_user.h" 25#include "xdp_redirect.skel.h" 26 27static int mask = SAMPLE_RX_CNT | SAMPLE_REDIRECT_ERR_CNT | 28 SAMPLE_EXCEPTION_CNT | SAMPLE_DEVMAP_XMIT_CNT_MULTI; 29 30DEFINE_SAMPLE_INIT(xdp_redirect); 31 32static const struct option long_options[] = { 33 {"help", no_argument, NULL, 'h' }, 34 {"skb-mode", no_argument, NULL, 'S' }, 35 {"force", no_argument, NULL, 'F' }, 36 {"stats", no_argument, NULL, 's' }, 37 {"interval", required_argument, NULL, 'i' }, 38 {"verbose", no_argument, NULL, 'v' }, 39 {} 40}; 41 42int main(int argc, char **argv) 43{ 44 int ifindex_in, ifindex_out, opt; 45 char str[2 * IF_NAMESIZE + 1]; 46 char ifname_out[IF_NAMESIZE]; 47 char ifname_in[IF_NAMESIZE]; 48 int ret = EXIT_FAIL_OPTION; 49 unsigned long interval = 2; 50 struct xdp_redirect *skel; 51 bool generic = false; 52 bool force = false; 53 bool error = true; 54 55 while ((opt = getopt_long(argc, argv, "hSFi:vs", 56 long_options, NULL)) != -1) { 57 switch (opt) { 58 case 'S': 59 generic = true; 60 mask &= ~(SAMPLE_DEVMAP_XMIT_CNT | 61 SAMPLE_DEVMAP_XMIT_CNT_MULTI); 62 break; 63 case 'F': 64 force = true; 65 break; 66 case 'i': 67 interval = strtoul(optarg, NULL, 0); 68 break; 69 case 'v': 70 sample_switch_mode(); 71 break; 72 case 's': 73 mask |= SAMPLE_REDIRECT_CNT; 74 break; 75 case 'h': 76 error = false; 77 default: 78 sample_usage(argv, long_options, __doc__, mask, error); 79 return ret; 80 } 81 } 82 83 if (argc <= optind + 1) { 84 sample_usage(argv, long_options, __doc__, mask, true); 85 return ret; 86 } 87 88 ifindex_in = if_nametoindex(argv[optind]); 89 if (!ifindex_in) 90 ifindex_in = strtoul(argv[optind], NULL, 0); 91 92 ifindex_out = if_nametoindex(argv[optind + 1]); 93 if (!ifindex_out) 94 ifindex_out = strtoul(argv[optind + 1], NULL, 0); 95 96 if (!ifindex_in || !ifindex_out) { 97 fprintf(stderr, "Bad interface index or name\n"); 98 sample_usage(argv, long_options, __doc__, mask, true); 99 goto end; 100 } 101 102 skel = xdp_redirect__open(); 103 if (!skel) { 104 fprintf(stderr, "Failed to xdp_redirect__open: %s\n", strerror(errno)); 105 ret = EXIT_FAIL_BPF; 106 goto end; 107 } 108 109 ret = sample_init_pre_load(skel); 110 if (ret < 0) { 111 fprintf(stderr, "Failed to sample_init_pre_load: %s\n", strerror(-ret)); 112 ret = EXIT_FAIL_BPF; 113 goto end_destroy; 114 } 115 116 skel->rodata->from_match[0] = ifindex_in; 117 skel->rodata->to_match[0] = ifindex_out; 118 skel->rodata->ifindex_out = ifindex_out; 119 120 ret = xdp_redirect__load(skel); 121 if (ret < 0) { 122 fprintf(stderr, "Failed to xdp_redirect__load: %s\n", strerror(errno)); 123 ret = EXIT_FAIL_BPF; 124 goto end_destroy; 125 } 126 127 ret = sample_init(skel, mask); 128 if (ret < 0) { 129 fprintf(stderr, "Failed to initialize sample: %s\n", strerror(-ret)); 130 ret = EXIT_FAIL; 131 goto end_destroy; 132 } 133 134 ret = EXIT_FAIL_XDP; 135 if (sample_install_xdp(skel->progs.xdp_redirect_prog, ifindex_in, 136 generic, force) < 0) 137 goto end_destroy; 138 139 /* Loading dummy XDP prog on out-device */ 140 sample_install_xdp(skel->progs.xdp_redirect_dummy_prog, ifindex_out, 141 generic, force); 142 143 ret = EXIT_FAIL; 144 if (!if_indextoname(ifindex_in, ifname_in)) { 145 fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_in, 146 strerror(errno)); 147 goto end_destroy; 148 } 149 150 if (!if_indextoname(ifindex_out, ifname_out)) { 151 fprintf(stderr, "Failed to if_indextoname for %d: %s\n", ifindex_out, 152 strerror(errno)); 153 goto end_destroy; 154 } 155 156 safe_strncpy(str, get_driver_name(ifindex_in), sizeof(str)); 157 printf("Redirecting from %s (ifindex %d; driver %s) to %s (ifindex %d; driver %s)\n", 158 ifname_in, ifindex_in, str, ifname_out, ifindex_out, get_driver_name(ifindex_out)); 159 snprintf(str, sizeof(str), "%s->%s", ifname_in, ifname_out); 160 161 ret = sample_run(interval, NULL, NULL); 162 if (ret < 0) { 163 fprintf(stderr, "Failed during sample run: %s\n", strerror(-ret)); 164 ret = EXIT_FAIL; 165 goto end_destroy; 166 } 167 ret = EXIT_OK; 168end_destroy: 169 xdp_redirect__destroy(skel); 170end: 171 sample_exit(ret); 172}