0001
0002
0003
0004 #include <linux/bpf.h>
0005 #include <linux/if_link.h>
0006 #include <arpa/inet.h>
0007 #include <assert.h>
0008 #include <errno.h>
0009 #include <signal.h>
0010 #include <stdio.h>
0011 #include <stdlib.h>
0012 #include <string.h>
0013 #include <unistd.h>
0014 #include <libgen.h>
0015 #include <net/if.h>
0016 #include <sys/types.h>
0017 #include <sys/socket.h>
0018 #include <netdb.h>
0019
0020 #include "bpf/bpf.h"
0021 #include "bpf/libbpf.h"
0022
0023 #include "xdping.h"
0024 #include "testing_helpers.h"
0025
0026 static int ifindex;
0027 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
0028
0029 static void cleanup(int sig)
0030 {
0031 bpf_xdp_detach(ifindex, xdp_flags, NULL);
0032 if (sig)
0033 exit(1);
0034 }
0035
0036 static int get_stats(int fd, __u16 count, __u32 raddr)
0037 {
0038 struct pinginfo pinginfo = { 0 };
0039 char inaddrbuf[INET_ADDRSTRLEN];
0040 struct in_addr inaddr;
0041 __u16 i;
0042
0043 inaddr.s_addr = raddr;
0044
0045 printf("\nXDP RTT data:\n");
0046
0047 if (bpf_map_lookup_elem(fd, &raddr, &pinginfo)) {
0048 perror("bpf_map_lookup elem");
0049 return 1;
0050 }
0051
0052 for (i = 0; i < count; i++) {
0053 if (pinginfo.times[i] == 0)
0054 break;
0055
0056 printf("64 bytes from %s: icmp_seq=%d ttl=64 time=%#.5f ms\n",
0057 inet_ntop(AF_INET, &inaddr, inaddrbuf,
0058 sizeof(inaddrbuf)),
0059 count + i + 1,
0060 (double)pinginfo.times[i]/1000000);
0061 }
0062
0063 if (i < count) {
0064 fprintf(stderr, "Expected %d samples, got %d.\n", count, i);
0065 return 1;
0066 }
0067
0068 bpf_map_delete_elem(fd, &raddr);
0069
0070 return 0;
0071 }
0072
0073 static void show_usage(const char *prog)
0074 {
0075 fprintf(stderr,
0076 "usage: %s [OPTS] -I interface destination\n\n"
0077 "OPTS:\n"
0078 " -c count Stop after sending count requests\n"
0079 " (default %d, max %d)\n"
0080 " -I interface interface name\n"
0081 " -N Run in driver mode\n"
0082 " -s Server mode\n"
0083 " -S Run in skb mode\n",
0084 prog, XDPING_DEFAULT_COUNT, XDPING_MAX_COUNT);
0085 }
0086
0087 int main(int argc, char **argv)
0088 {
0089 __u32 mode_flags = XDP_FLAGS_DRV_MODE | XDP_FLAGS_SKB_MODE;
0090 struct addrinfo *a, hints = { .ai_family = AF_INET };
0091 __u16 count = XDPING_DEFAULT_COUNT;
0092 struct pinginfo pinginfo = { 0 };
0093 const char *optstr = "c:I:NsS";
0094 struct bpf_program *main_prog;
0095 int prog_fd = -1, map_fd = -1;
0096 struct sockaddr_in rin;
0097 struct bpf_object *obj;
0098 struct bpf_map *map;
0099 char *ifname = NULL;
0100 char filename[256];
0101 int opt, ret = 1;
0102 __u32 raddr = 0;
0103 int server = 0;
0104 char cmd[256];
0105
0106 while ((opt = getopt(argc, argv, optstr)) != -1) {
0107 switch (opt) {
0108 case 'c':
0109 count = atoi(optarg);
0110 if (count < 1 || count > XDPING_MAX_COUNT) {
0111 fprintf(stderr,
0112 "min count is 1, max count is %d\n",
0113 XDPING_MAX_COUNT);
0114 return 1;
0115 }
0116 break;
0117 case 'I':
0118 ifname = optarg;
0119 ifindex = if_nametoindex(ifname);
0120 if (!ifindex) {
0121 fprintf(stderr, "Could not get interface %s\n",
0122 ifname);
0123 return 1;
0124 }
0125 break;
0126 case 'N':
0127 xdp_flags |= XDP_FLAGS_DRV_MODE;
0128 break;
0129 case 's':
0130
0131 server = 1;
0132 break;
0133 case 'S':
0134 xdp_flags |= XDP_FLAGS_SKB_MODE;
0135 break;
0136 default:
0137 show_usage(basename(argv[0]));
0138 return 1;
0139 }
0140 }
0141
0142 if (!ifname) {
0143 show_usage(basename(argv[0]));
0144 return 1;
0145 }
0146 if (!server && optind == argc) {
0147 show_usage(basename(argv[0]));
0148 return 1;
0149 }
0150
0151 if ((xdp_flags & mode_flags) == mode_flags) {
0152 fprintf(stderr, "-N or -S can be specified, not both.\n");
0153 show_usage(basename(argv[0]));
0154 return 1;
0155 }
0156
0157 if (!server) {
0158
0159 if (getaddrinfo(argv[optind], NULL, &hints, &a) || !a) {
0160 fprintf(stderr, "Could not resolve %s\n", argv[optind]);
0161 return 1;
0162 }
0163 memcpy(&rin, a->ai_addr, sizeof(rin));
0164 raddr = rin.sin_addr.s_addr;
0165 freeaddrinfo(a);
0166 }
0167
0168
0169 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
0170
0171 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
0172
0173 if (bpf_prog_test_load(filename, BPF_PROG_TYPE_XDP, &obj, &prog_fd)) {
0174 fprintf(stderr, "load of %s failed\n", filename);
0175 return 1;
0176 }
0177
0178 main_prog = bpf_object__find_program_by_name(obj,
0179 server ? "xdping_server" : "xdping_client");
0180 if (main_prog)
0181 prog_fd = bpf_program__fd(main_prog);
0182 if (!main_prog || prog_fd < 0) {
0183 fprintf(stderr, "could not find xdping program");
0184 return 1;
0185 }
0186
0187 map = bpf_object__next_map(obj, NULL);
0188 if (map)
0189 map_fd = bpf_map__fd(map);
0190 if (!map || map_fd < 0) {
0191 fprintf(stderr, "Could not find ping map");
0192 goto done;
0193 }
0194
0195 signal(SIGINT, cleanup);
0196 signal(SIGTERM, cleanup);
0197
0198 printf("Setting up XDP for %s, please wait...\n", ifname);
0199
0200 printf("XDP setup disrupts network connectivity, hit Ctrl+C to quit\n");
0201
0202 if (bpf_xdp_attach(ifindex, prog_fd, xdp_flags, NULL) < 0) {
0203 fprintf(stderr, "Link set xdp fd failed for %s\n", ifname);
0204 goto done;
0205 }
0206
0207 if (server) {
0208 close(prog_fd);
0209 close(map_fd);
0210 printf("Running server on %s; press Ctrl+C to exit...\n",
0211 ifname);
0212 do { } while (1);
0213 }
0214
0215
0216
0217
0218
0219
0220
0221 pinginfo.seq = htons(count);
0222 pinginfo.count = count;
0223
0224 if (bpf_map_update_elem(map_fd, &raddr, &pinginfo, BPF_ANY)) {
0225 fprintf(stderr, "could not communicate with BPF map: %s\n",
0226 strerror(errno));
0227 cleanup(0);
0228 goto done;
0229 }
0230
0231
0232 sleep(10);
0233
0234 snprintf(cmd, sizeof(cmd), "ping -c %d -I %s %s",
0235 count, ifname, argv[optind]);
0236
0237 printf("\nNormal ping RTT data\n");
0238 printf("[Ignore final RTT; it is distorted by XDP using the reply]\n");
0239
0240 ret = system(cmd);
0241
0242 if (!ret)
0243 ret = get_stats(map_fd, count, raddr);
0244
0245 cleanup(0);
0246
0247 done:
0248 if (prog_fd > 0)
0249 close(prog_fd);
0250 if (map_fd > 0)
0251 close(map_fd);
0252
0253 return ret;
0254 }