| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 1 | 2 | /* Copyright (c) 2016 Facebook | 
|---|
| 2 |  | - * | 
|---|
| 3 |  | - * This program is free software; you can redistribute it and/or | 
|---|
| 4 |  | - * modify it under the terms of version 2 of the GNU General Public | 
|---|
| 5 |  | - * License as published by the Free Software Foundation. | 
|---|
| 6 | 3 | */ | 
|---|
| 7 | 4 | #include <linux/bpf.h> | 
|---|
| 8 | 5 | #include <linux/if_link.h> | 
|---|
| .. | .. | 
|---|
| 12 | 9 | #include <stdio.h> | 
|---|
| 13 | 10 | #include <stdlib.h> | 
|---|
| 14 | 11 | #include <string.h> | 
|---|
|  | 12 | +#include <net/if.h> | 
|---|
| 15 | 13 | #include <sys/resource.h> | 
|---|
| 16 | 14 | #include <arpa/inet.h> | 
|---|
| 17 | 15 | #include <netinet/ether.h> | 
|---|
| 18 | 16 | #include <unistd.h> | 
|---|
| 19 | 17 | #include <time.h> | 
|---|
| 20 |  | -#include "bpf_load.h" | 
|---|
|  | 18 | +#include <bpf/libbpf.h> | 
|---|
| 21 | 19 | #include <bpf/bpf.h> | 
|---|
| 22 | 20 | #include "bpf_util.h" | 
|---|
| 23 | 21 | #include "xdp_tx_iptunnel_common.h" | 
|---|
| .. | .. | 
|---|
| 25 | 23 | #define STATS_INTERVAL_S 2U | 
|---|
| 26 | 24 |  | 
|---|
| 27 | 25 | static int ifindex = -1; | 
|---|
| 28 |  | -static __u32 xdp_flags = 0; | 
|---|
|  | 26 | +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; | 
|---|
|  | 27 | +static int rxcnt_map_fd; | 
|---|
|  | 28 | +static __u32 prog_id; | 
|---|
| 29 | 29 |  | 
|---|
| 30 | 30 | static void int_exit(int sig) | 
|---|
| 31 | 31 | { | 
|---|
| 32 |  | -	if (ifindex > -1) | 
|---|
| 33 |  | -		bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); | 
|---|
|  | 32 | +	__u32 curr_prog_id = 0; | 
|---|
|  | 33 | + | 
|---|
|  | 34 | +	if (ifindex > -1) { | 
|---|
|  | 35 | +		if (bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags)) { | 
|---|
|  | 36 | +			printf("bpf_get_link_xdp_id failed\n"); | 
|---|
|  | 37 | +			exit(1); | 
|---|
|  | 38 | +		} | 
|---|
|  | 39 | +		if (prog_id == curr_prog_id) | 
|---|
|  | 40 | +			bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); | 
|---|
|  | 41 | +		else if (!curr_prog_id) | 
|---|
|  | 42 | +			printf("couldn't find a prog id on a given iface\n"); | 
|---|
|  | 43 | +		else | 
|---|
|  | 44 | +			printf("program on interface changed, not removing\n"); | 
|---|
|  | 45 | +	} | 
|---|
| 34 | 46 | exit(0); | 
|---|
| 35 | 47 | } | 
|---|
| 36 | 48 |  | 
|---|
| .. | .. | 
|---|
| 53 | 65 | for (proto = 0; proto < nr_protos; proto++) { | 
|---|
| 54 | 66 | __u64 sum = 0; | 
|---|
| 55 | 67 |  | 
|---|
| 56 |  | -			assert(bpf_map_lookup_elem(map_fd[0], &proto, values) == 0); | 
|---|
|  | 68 | +			assert(bpf_map_lookup_elem(rxcnt_map_fd, &proto, | 
|---|
|  | 69 | +						   values) == 0); | 
|---|
| 57 | 70 | for (i = 0; i < nr_cpus; i++) | 
|---|
| 58 | 71 | sum += (values[i] - prev[proto][i]); | 
|---|
| 59 | 72 |  | 
|---|
| .. | .. | 
|---|
| 71 | 84 | "in an IPv4/v6 header and XDP_TX it out.  The dst <VIP:PORT>\n" | 
|---|
| 72 | 85 | "is used to select packets to encapsulate\n\n"); | 
|---|
| 73 | 86 | printf("Usage: %s [...]\n", cmd); | 
|---|
| 74 |  | -	printf("    -i <ifindex> Interface Index\n"); | 
|---|
|  | 87 | +	printf("    -i <ifname|ifindex> Interface\n"); | 
|---|
| 75 | 88 | printf("    -a <vip-service-address> IPv4 or IPv6\n"); | 
|---|
| 76 | 89 | printf("    -p <vip-service-port> A port range (e.g. 433-444) is also allowed\n"); | 
|---|
| 77 | 90 | printf("    -s <source-ip> Used in the IPTunnel header\n"); | 
|---|
| .. | .. | 
|---|
| 81 | 94 | printf("    -P <IP-Protocol> Default is TCP\n"); | 
|---|
| 82 | 95 | printf("    -S use skb-mode\n"); | 
|---|
| 83 | 96 | printf("    -N enforce native mode\n"); | 
|---|
|  | 97 | +	printf("    -F Force loading the XDP prog\n"); | 
|---|
| 84 | 98 | printf("    -h Display this help\n"); | 
|---|
| 85 | 99 | } | 
|---|
| 86 | 100 |  | 
|---|
| .. | .. | 
|---|
| 138 | 152 |  | 
|---|
| 139 | 153 | int main(int argc, char **argv) | 
|---|
| 140 | 154 | { | 
|---|
| 141 |  | -	unsigned char opt_flags[256] = {}; | 
|---|
| 142 |  | -	unsigned int kill_after_s = 0; | 
|---|
| 143 |  | -	const char *optstr = "i:a:p:s:d:m:T:P:SNh"; | 
|---|
| 144 |  | -	int min_port = 0, max_port = 0; | 
|---|
| 145 |  | -	struct iptnl_info tnl = {}; | 
|---|
|  | 155 | +	struct bpf_prog_load_attr prog_load_attr = { | 
|---|
|  | 156 | +		.prog_type	= BPF_PROG_TYPE_XDP, | 
|---|
|  | 157 | +	}; | 
|---|
| 146 | 158 | struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; | 
|---|
|  | 159 | +	int min_port = 0, max_port = 0, vip2tnl_map_fd; | 
|---|
|  | 160 | +	const char *optstr = "i:a:p:s:d:m:T:P:FSNh"; | 
|---|
|  | 161 | +	unsigned char opt_flags[256] = {}; | 
|---|
|  | 162 | +	struct bpf_prog_info info = {}; | 
|---|
|  | 163 | +	__u32 info_len = sizeof(info); | 
|---|
|  | 164 | +	unsigned int kill_after_s = 0; | 
|---|
|  | 165 | +	struct iptnl_info tnl = {}; | 
|---|
|  | 166 | +	struct bpf_object *obj; | 
|---|
| 147 | 167 | struct vip vip = {}; | 
|---|
| 148 | 168 | char filename[256]; | 
|---|
| 149 |  | -	int opt; | 
|---|
| 150 |  | -	int i; | 
|---|
|  | 169 | +	int opt, prog_fd; | 
|---|
|  | 170 | +	int i, err; | 
|---|
| 151 | 171 |  | 
|---|
| 152 | 172 | tnl.family = AF_UNSPEC; | 
|---|
| 153 | 173 | vip.protocol = IPPROTO_TCP; | 
|---|
| .. | .. | 
|---|
| 162 | 182 |  | 
|---|
| 163 | 183 | switch (opt) { | 
|---|
| 164 | 184 | case 'i': | 
|---|
| 165 |  | -			ifindex = atoi(optarg); | 
|---|
|  | 185 | +			ifindex = if_nametoindex(optarg); | 
|---|
|  | 186 | +			if (!ifindex) | 
|---|
|  | 187 | +				ifindex = atoi(optarg); | 
|---|
| 166 | 188 | break; | 
|---|
| 167 | 189 | case 'a': | 
|---|
| 168 | 190 | vip.family = parse_ipstr(optarg, vip.daddr.v6); | 
|---|
| .. | .. | 
|---|
| 209 | 231 | xdp_flags |= XDP_FLAGS_SKB_MODE; | 
|---|
| 210 | 232 | break; | 
|---|
| 211 | 233 | case 'N': | 
|---|
| 212 |  | -			xdp_flags |= XDP_FLAGS_DRV_MODE; | 
|---|
|  | 234 | +			/* default, set below */ | 
|---|
|  | 235 | +			break; | 
|---|
|  | 236 | +		case 'F': | 
|---|
|  | 237 | +			xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; | 
|---|
| 213 | 238 | break; | 
|---|
| 214 | 239 | default: | 
|---|
| 215 | 240 | usage(argv[0]); | 
|---|
| .. | .. | 
|---|
| 217 | 242 | } | 
|---|
| 218 | 243 | opt_flags[opt] = 0; | 
|---|
| 219 | 244 | } | 
|---|
|  | 245 | + | 
|---|
|  | 246 | +	if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) | 
|---|
|  | 247 | +		xdp_flags |= XDP_FLAGS_DRV_MODE; | 
|---|
| 220 | 248 |  | 
|---|
| 221 | 249 | for (i = 0; i < strlen(optstr); i++) { | 
|---|
| 222 | 250 | if (opt_flags[(unsigned int)optstr[i]]) { | 
|---|
| .. | .. | 
|---|
| 231 | 259 | return 1; | 
|---|
| 232 | 260 | } | 
|---|
| 233 | 261 |  | 
|---|
| 234 |  | -	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | 
|---|
| 235 |  | - | 
|---|
| 236 |  | -	if (load_bpf_file(filename)) { | 
|---|
| 237 |  | -		printf("%s", bpf_log_buf); | 
|---|
|  | 262 | +	if (!ifindex) { | 
|---|
|  | 263 | +		fprintf(stderr, "Invalid ifname\n"); | 
|---|
| 238 | 264 | return 1; | 
|---|
| 239 | 265 | } | 
|---|
| 240 | 266 |  | 
|---|
| 241 |  | -	if (!prog_fd[0]) { | 
|---|
| 242 |  | -		printf("load_bpf_file: %s\n", strerror(errno)); | 
|---|
|  | 267 | +	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); | 
|---|
|  | 268 | +	prog_load_attr.file = filename; | 
|---|
|  | 269 | + | 
|---|
|  | 270 | +	if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) | 
|---|
|  | 271 | +		return 1; | 
|---|
|  | 272 | + | 
|---|
|  | 273 | +	if (!prog_fd) { | 
|---|
|  | 274 | +		printf("bpf_prog_load_xattr: %s\n", strerror(errno)); | 
|---|
|  | 275 | +		return 1; | 
|---|
|  | 276 | +	} | 
|---|
|  | 277 | + | 
|---|
|  | 278 | +	rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt"); | 
|---|
|  | 279 | +	vip2tnl_map_fd = bpf_object__find_map_fd_by_name(obj, "vip2tnl"); | 
|---|
|  | 280 | +	if (vip2tnl_map_fd < 0 || rxcnt_map_fd < 0) { | 
|---|
|  | 281 | +		printf("bpf_object__find_map_fd_by_name failed\n"); | 
|---|
| 243 | 282 | return 1; | 
|---|
| 244 | 283 | } | 
|---|
| 245 | 284 |  | 
|---|
| .. | .. | 
|---|
| 248 | 287 |  | 
|---|
| 249 | 288 | while (min_port <= max_port) { | 
|---|
| 250 | 289 | vip.dport = htons(min_port++); | 
|---|
| 251 |  | -		if (bpf_map_update_elem(map_fd[1], &vip, &tnl, BPF_NOEXIST)) { | 
|---|
|  | 290 | +		if (bpf_map_update_elem(vip2tnl_map_fd, &vip, &tnl, | 
|---|
|  | 291 | +					BPF_NOEXIST)) { | 
|---|
| 252 | 292 | perror("bpf_map_update_elem(&vip2tnl)"); | 
|---|
| 253 | 293 | return 1; | 
|---|
| 254 | 294 | } | 
|---|
| 255 | 295 | } | 
|---|
| 256 | 296 |  | 
|---|
| 257 |  | -	if (bpf_set_link_xdp_fd(ifindex, prog_fd[0], xdp_flags) < 0) { | 
|---|
|  | 297 | +	if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) { | 
|---|
| 258 | 298 | printf("link set xdp fd failed\n"); | 
|---|
| 259 | 299 | return 1; | 
|---|
| 260 | 300 | } | 
|---|
| 261 | 301 |  | 
|---|
|  | 302 | +	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | 
|---|
|  | 303 | +	if (err) { | 
|---|
|  | 304 | +		printf("can't get prog info - %s\n", strerror(errno)); | 
|---|
|  | 305 | +		return err; | 
|---|
|  | 306 | +	} | 
|---|
|  | 307 | +	prog_id = info.id; | 
|---|
|  | 308 | + | 
|---|
| 262 | 309 | poll_stats(kill_after_s); | 
|---|
| 263 | 310 |  | 
|---|
| 264 | 311 | bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); | 
|---|