Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.14-rc1 217 lines 5.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright (c) 2016 John Fastabend <john.r.fastabend@intel.com> 3 */ 4#include <linux/bpf.h> 5#include <linux/if_link.h> 6#include <assert.h> 7#include <errno.h> 8#include <signal.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <stdbool.h> 12#include <string.h> 13#include <net/if.h> 14#include <unistd.h> 15#include <libgen.h> 16#include <sys/resource.h> 17 18#include "bpf_util.h" 19#include <bpf/bpf.h> 20#include <bpf/libbpf.h> 21 22static int ifindex_in; 23static int ifindex_out; 24static bool ifindex_out_xdp_dummy_attached = true; 25static __u32 prog_id; 26static __u32 dummy_prog_id; 27 28static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; 29static int rxcnt_map_fd; 30 31static void int_exit(int sig) 32{ 33 __u32 curr_prog_id = 0; 34 35 if (bpf_get_link_xdp_id(ifindex_in, &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_in, -1, xdp_flags); 41 else if (!curr_prog_id) 42 printf("couldn't find a prog id on iface IN\n"); 43 else 44 printf("program on iface IN changed, not removing\n"); 45 46 if (ifindex_out_xdp_dummy_attached) { 47 curr_prog_id = 0; 48 if (bpf_get_link_xdp_id(ifindex_out, &curr_prog_id, 49 xdp_flags)) { 50 printf("bpf_get_link_xdp_id failed\n"); 51 exit(1); 52 } 53 if (dummy_prog_id == curr_prog_id) 54 bpf_set_link_xdp_fd(ifindex_out, -1, xdp_flags); 55 else if (!curr_prog_id) 56 printf("couldn't find a prog id on iface OUT\n"); 57 else 58 printf("program on iface OUT changed, not removing\n"); 59 } 60 exit(0); 61} 62 63static void poll_stats(int interval, int ifindex) 64{ 65 unsigned int nr_cpus = bpf_num_possible_cpus(); 66 __u64 values[nr_cpus], prev[nr_cpus]; 67 68 memset(prev, 0, sizeof(prev)); 69 70 while (1) { 71 __u64 sum = 0; 72 __u32 key = 0; 73 int i; 74 75 sleep(interval); 76 assert(bpf_map_lookup_elem(rxcnt_map_fd, &key, values) == 0); 77 for (i = 0; i < nr_cpus; i++) 78 sum += (values[i] - prev[i]); 79 if (sum) 80 printf("ifindex %i: %10llu pkt/s\n", 81 ifindex, sum / interval); 82 memcpy(prev, values, sizeof(values)); 83 } 84} 85 86static void usage(const char *prog) 87{ 88 fprintf(stderr, 89 "usage: %s [OPTS] <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n\n" 90 "OPTS:\n" 91 " -S use skb-mode\n" 92 " -N enforce native mode\n" 93 " -F force loading prog\n", 94 prog); 95} 96 97 98int main(int argc, char **argv) 99{ 100 struct bpf_prog_load_attr prog_load_attr = { 101 .prog_type = BPF_PROG_TYPE_XDP, 102 }; 103 struct bpf_program *prog, *dummy_prog; 104 int prog_fd, tx_port_map_fd, opt; 105 struct bpf_prog_info info = {}; 106 __u32 info_len = sizeof(info); 107 const char *optstr = "FSN"; 108 struct bpf_object *obj; 109 char filename[256]; 110 int dummy_prog_fd; 111 int ret, key = 0; 112 113 while ((opt = getopt(argc, argv, optstr)) != -1) { 114 switch (opt) { 115 case 'S': 116 xdp_flags |= XDP_FLAGS_SKB_MODE; 117 break; 118 case 'N': 119 /* default, set below */ 120 break; 121 case 'F': 122 xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST; 123 break; 124 default: 125 usage(basename(argv[0])); 126 return 1; 127 } 128 } 129 130 if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) 131 xdp_flags |= XDP_FLAGS_DRV_MODE; 132 133 if (optind + 2 != argc) { 134 printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", argv[0]); 135 return 1; 136 } 137 138 ifindex_in = if_nametoindex(argv[optind]); 139 if (!ifindex_in) 140 ifindex_in = strtoul(argv[optind], NULL, 0); 141 142 ifindex_out = if_nametoindex(argv[optind + 1]); 143 if (!ifindex_out) 144 ifindex_out = strtoul(argv[optind + 1], NULL, 0); 145 146 printf("input: %d output: %d\n", ifindex_in, ifindex_out); 147 148 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 149 prog_load_attr.file = filename; 150 151 if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) 152 return 1; 153 154 prog = bpf_program__next(NULL, obj); 155 dummy_prog = bpf_program__next(prog, obj); 156 if (!prog || !dummy_prog) { 157 printf("finding a prog in obj file failed\n"); 158 return 1; 159 } 160 /* bpf_prog_load_xattr gives us the pointer to first prog's fd, 161 * so we're missing only the fd for dummy prog 162 */ 163 dummy_prog_fd = bpf_program__fd(dummy_prog); 164 if (prog_fd < 0 || dummy_prog_fd < 0) { 165 printf("bpf_prog_load_xattr: %s\n", strerror(errno)); 166 return 1; 167 } 168 169 tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port"); 170 rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt"); 171 if (tx_port_map_fd < 0 || rxcnt_map_fd < 0) { 172 printf("bpf_object__find_map_fd_by_name failed\n"); 173 return 1; 174 } 175 176 if (bpf_set_link_xdp_fd(ifindex_in, prog_fd, xdp_flags) < 0) { 177 printf("ERROR: link set xdp fd failed on %d\n", ifindex_in); 178 return 1; 179 } 180 181 ret = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); 182 if (ret) { 183 printf("can't get prog info - %s\n", strerror(errno)); 184 return ret; 185 } 186 prog_id = info.id; 187 188 /* Loading dummy XDP prog on out-device */ 189 if (bpf_set_link_xdp_fd(ifindex_out, dummy_prog_fd, 190 (xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) { 191 printf("WARN: link set xdp fd failed on %d\n", ifindex_out); 192 ifindex_out_xdp_dummy_attached = false; 193 } 194 195 memset(&info, 0, sizeof(info)); 196 ret = bpf_obj_get_info_by_fd(dummy_prog_fd, &info, &info_len); 197 if (ret) { 198 printf("can't get prog info - %s\n", strerror(errno)); 199 return ret; 200 } 201 dummy_prog_id = info.id; 202 203 signal(SIGINT, int_exit); 204 signal(SIGTERM, int_exit); 205 206 /* bpf redirect port */ 207 ret = bpf_map_update_elem(tx_port_map_fd, &key, &ifindex_out, 0); 208 if (ret) { 209 perror("bpf_update_elem"); 210 goto out; 211 } 212 213 poll_stats(2, ifindex_out); 214 215out: 216 return ret; 217}