1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */
5 #include <linux/if_link.h>
15 #include <sys/resource.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
22 #include "bpf/libbpf.h"
27 static __u32 xdp_flags
= XDP_FLAGS_UPDATE_IF_NOEXIST
;
29 static void cleanup(int sig
)
31 bpf_set_link_xdp_fd(ifindex
, -1, xdp_flags
);
36 static int get_stats(int fd
, __u16 count
, __u32 raddr
)
38 struct pinginfo pinginfo
= { 0 };
39 char inaddrbuf
[INET_ADDRSTRLEN
];
40 struct in_addr inaddr
;
43 inaddr
.s_addr
= raddr
;
45 printf("\nXDP RTT data:\n");
47 if (bpf_map_lookup_elem(fd
, &raddr
, &pinginfo
)) {
48 perror("bpf_map_lookup elem: ");
52 for (i
= 0; i
< count
; i
++) {
53 if (pinginfo
.times
[i
] == 0)
56 printf("64 bytes from %s: icmp_seq=%d ttl=64 time=%#.5f ms\n",
57 inet_ntop(AF_INET
, &inaddr
, inaddrbuf
,
60 (double)pinginfo
.times
[i
]/1000000);
64 fprintf(stderr
, "Expected %d samples, got %d.\n", count
, i
);
68 bpf_map_delete_elem(fd
, &raddr
);
73 static void show_usage(const char *prog
)
76 "usage: %s [OPTS] -I interface destination\n\n"
78 " -c count Stop after sending count requests\n"
79 " (default %d, max %d)\n"
80 " -I interface interface name\n"
81 " -N Run in driver mode\n"
83 " -S Run in skb mode\n",
84 prog
, XDPING_DEFAULT_COUNT
, XDPING_MAX_COUNT
);
87 int main(int argc
, char **argv
)
89 __u32 mode_flags
= XDP_FLAGS_DRV_MODE
| XDP_FLAGS_SKB_MODE
;
90 struct addrinfo
*a
, hints
= { .ai_family
= AF_INET
};
91 struct rlimit r
= {RLIM_INFINITY
, RLIM_INFINITY
};
92 __u16 count
= XDPING_DEFAULT_COUNT
;
93 struct pinginfo pinginfo
= { 0 };
94 const char *optstr
= "c:I:NsS";
95 struct bpf_program
*main_prog
;
96 int prog_fd
= -1, map_fd
= -1;
97 struct sockaddr_in rin
;
98 struct bpf_object
*obj
;
107 while ((opt
= getopt(argc
, argv
, optstr
)) != -1) {
110 count
= atoi(optarg
);
111 if (count
< 1 || count
> XDPING_MAX_COUNT
) {
113 "min count is 1, max count is %d\n",
120 ifindex
= if_nametoindex(ifname
);
122 fprintf(stderr
, "Could not get interface %s\n",
128 xdp_flags
|= XDP_FLAGS_DRV_MODE
;
131 /* use server program */
135 xdp_flags
|= XDP_FLAGS_SKB_MODE
;
138 show_usage(basename(argv
[0]));
144 show_usage(basename(argv
[0]));
147 if (!server
&& optind
== argc
) {
148 show_usage(basename(argv
[0]));
152 if ((xdp_flags
& mode_flags
) == mode_flags
) {
153 fprintf(stderr
, "-N or -S can be specified, not both.\n");
154 show_usage(basename(argv
[0]));
159 /* Only supports IPv4; see hints initiailization above. */
160 if (getaddrinfo(argv
[optind
], NULL
, &hints
, &a
) || !a
) {
161 fprintf(stderr
, "Could not resolve %s\n", argv
[optind
]);
164 memcpy(&rin
, a
->ai_addr
, sizeof(rin
));
165 raddr
= rin
.sin_addr
.s_addr
;
169 if (setrlimit(RLIMIT_MEMLOCK
, &r
)) {
170 perror("setrlimit(RLIMIT_MEMLOCK)");
174 snprintf(filename
, sizeof(filename
), "%s_kern.o", argv
[0]);
176 if (bpf_prog_load(filename
, BPF_PROG_TYPE_XDP
, &obj
, &prog_fd
)) {
177 fprintf(stderr
, "load of %s failed\n", filename
);
181 main_prog
= bpf_object__find_program_by_title(obj
,
182 server
? "xdpserver" :
185 prog_fd
= bpf_program__fd(main_prog
);
186 if (!main_prog
|| prog_fd
< 0) {
187 fprintf(stderr
, "could not find xdping program");
191 map
= bpf_map__next(NULL
, obj
);
193 map_fd
= bpf_map__fd(map
);
194 if (!map
|| map_fd
< 0) {
195 fprintf(stderr
, "Could not find ping map");
199 signal(SIGINT
, cleanup
);
200 signal(SIGTERM
, cleanup
);
202 printf("Setting up XDP for %s, please wait...\n", ifname
);
204 printf("XDP setup disrupts network connectivity, hit Ctrl+C to quit\n");
206 if (bpf_set_link_xdp_fd(ifindex
, prog_fd
, xdp_flags
) < 0) {
207 fprintf(stderr
, "Link set xdp fd failed for %s\n", ifname
);
214 printf("Running server on %s; press Ctrl+C to exit...\n",
219 /* Start xdping-ing from last regular ping reply, e.g. for a count
220 * of 10 ICMP requests, we start xdping-ing using reply with seq number
221 * 10. The reason the last "real" ping RTT is much higher is that
222 * the ping program sees the ICMP reply associated with the last
223 * XDP-generated packet, so ping doesn't get a reply until XDP is done.
225 pinginfo
.seq
= htons(count
);
226 pinginfo
.count
= count
;
228 if (bpf_map_update_elem(map_fd
, &raddr
, &pinginfo
, BPF_ANY
)) {
229 fprintf(stderr
, "could not communicate with BPF map: %s\n",
235 /* We need to wait for XDP setup to complete. */
238 snprintf(cmd
, sizeof(cmd
), "ping -c %d -I %s %s",
239 count
, ifname
, argv
[optind
]);
241 printf("\nNormal ping RTT data\n");
242 printf("[Ignore final RTT; it is distorted by XDP using the reply]\n");
247 ret
= get_stats(map_fd
, count
, raddr
);