0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #define _GNU_SOURCE
0020
0021 #include <stdio.h>
0022 #include <stdlib.h>
0023 #include <stddef.h>
0024 #include <string.h>
0025 #include <unistd.h>
0026 #include <assert.h>
0027 #include <errno.h>
0028 #include <fcntl.h>
0029
0030 #include <linux/bpf.h>
0031 #include <bpf/bpf.h>
0032
0033 #include "bpf_insn.h"
0034 #include "bpf_util.h"
0035
0036 enum {
0037 MAP_KEY_PACKETS,
0038 MAP_KEY_BYTES,
0039 };
0040
0041 char bpf_log_buf[BPF_LOG_BUF_SIZE];
0042
0043 static int prog_load(int map_fd, int verdict)
0044 {
0045 struct bpf_insn prog[] = {
0046 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
0047
0048
0049 BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS),
0050 BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),
0051 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
0052 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
0053 BPF_LD_MAP_FD(BPF_REG_1, map_fd),
0054 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
0055 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
0056 BPF_MOV64_IMM(BPF_REG_1, 1),
0057 BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0),
0058
0059
0060 BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES),
0061 BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),
0062 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
0063 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
0064 BPF_LD_MAP_FD(BPF_REG_1, map_fd),
0065 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
0066 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
0067 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)),
0068
0069 BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0),
0070
0071 BPF_MOV64_IMM(BPF_REG_0, verdict),
0072 BPF_EXIT_INSN(),
0073 };
0074 size_t insns_cnt = ARRAY_SIZE(prog);
0075 LIBBPF_OPTS(bpf_prog_load_opts, opts,
0076 .log_buf = bpf_log_buf,
0077 .log_size = BPF_LOG_BUF_SIZE,
0078 );
0079
0080 return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SKB, NULL, "GPL",
0081 prog, insns_cnt, &opts);
0082 }
0083
0084 static int usage(const char *argv0)
0085 {
0086 printf("Usage: %s [-d] [-D] <cg-path> <egress|ingress>\n", argv0);
0087 printf(" -d Drop Traffic\n");
0088 printf(" -D Detach filter, and exit\n");
0089 return EXIT_FAILURE;
0090 }
0091
0092 static int attach_filter(int cg_fd, int type, int verdict)
0093 {
0094 int prog_fd, map_fd, ret, key;
0095 long long pkt_cnt, byte_cnt;
0096
0097 map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL,
0098 sizeof(key), sizeof(byte_cnt),
0099 256, NULL);
0100 if (map_fd < 0) {
0101 printf("Failed to create map: '%s'\n", strerror(errno));
0102 return EXIT_FAILURE;
0103 }
0104
0105 prog_fd = prog_load(map_fd, verdict);
0106 printf("Output from kernel verifier:\n%s\n-------\n", bpf_log_buf);
0107
0108 if (prog_fd < 0) {
0109 printf("Failed to load prog: '%s'\n", strerror(errno));
0110 return EXIT_FAILURE;
0111 }
0112
0113 ret = bpf_prog_attach(prog_fd, cg_fd, type, 0);
0114 if (ret < 0) {
0115 printf("Failed to attach prog to cgroup: '%s'\n",
0116 strerror(errno));
0117 return EXIT_FAILURE;
0118 }
0119 while (1) {
0120 key = MAP_KEY_PACKETS;
0121 assert(bpf_map_lookup_elem(map_fd, &key, &pkt_cnt) == 0);
0122
0123 key = MAP_KEY_BYTES;
0124 assert(bpf_map_lookup_elem(map_fd, &key, &byte_cnt) == 0);
0125
0126 printf("cgroup received %lld packets, %lld bytes\n",
0127 pkt_cnt, byte_cnt);
0128 sleep(1);
0129 }
0130
0131 return EXIT_SUCCESS;
0132 }
0133
0134 int main(int argc, char **argv)
0135 {
0136 int detach_only = 0, verdict = 1;
0137 enum bpf_attach_type type;
0138 int opt, cg_fd, ret;
0139
0140 while ((opt = getopt(argc, argv, "Dd")) != -1) {
0141 switch (opt) {
0142 case 'd':
0143 verdict = 0;
0144 break;
0145 case 'D':
0146 detach_only = 1;
0147 break;
0148 default:
0149 return usage(argv[0]);
0150 }
0151 }
0152
0153 if (argc - optind < 2)
0154 return usage(argv[0]);
0155
0156 if (strcmp(argv[optind + 1], "ingress") == 0)
0157 type = BPF_CGROUP_INET_INGRESS;
0158 else if (strcmp(argv[optind + 1], "egress") == 0)
0159 type = BPF_CGROUP_INET_EGRESS;
0160 else
0161 return usage(argv[0]);
0162
0163 cg_fd = open(argv[optind], O_DIRECTORY | O_RDONLY);
0164 if (cg_fd < 0) {
0165 printf("Failed to open cgroup path: '%s'\n", strerror(errno));
0166 return EXIT_FAILURE;
0167 }
0168
0169 if (detach_only) {
0170 ret = bpf_prog_detach(cg_fd, type);
0171 printf("bpf_prog_detach() returned '%s' (%d)\n",
0172 strerror(errno), errno);
0173 } else
0174 ret = attach_filter(cg_fd, type, verdict);
0175
0176 return ret;
0177 }