diff options
author | Alexei Starovoitov <ast@plumgrid.com> | 2015-03-13 14:57:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-15 22:02:28 -0400 |
commit | 614cd3bd3758a806cea497d493b584e6157561f7 (patch) | |
tree | 3c294086671617614f672aeb0d14bd2496fdb23c /samples | |
parent | 9bac3d6d548e5cc925570b263f35b70a00a00ffd (diff) |
samples: bpf: add skb->field examples and tests
- modify sockex1 example to count number of bytes in outgoing packets
- modify sockex2 example to count number of bytes and packets per flow
- add 4 stress tests that exercise 'skb->field' code path of verifier
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples')
-rw-r--r-- | samples/bpf/sockex1_kern.c | 8 | ||||
-rw-r--r-- | samples/bpf/sockex1_user.c | 2 | ||||
-rw-r--r-- | samples/bpf/sockex2_kern.c | 26 | ||||
-rw-r--r-- | samples/bpf/sockex2_user.c | 11 | ||||
-rw-r--r-- | samples/bpf/test_verifier.c | 70 |
5 files changed, 101 insertions, 16 deletions
diff --git a/samples/bpf/sockex1_kern.c b/samples/bpf/sockex1_kern.c index 066892662915..ed18e9a4909c 100644 --- a/samples/bpf/sockex1_kern.c +++ b/samples/bpf/sockex1_kern.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <uapi/linux/bpf.h> | 1 | #include <uapi/linux/bpf.h> |
2 | #include <uapi/linux/if_ether.h> | 2 | #include <uapi/linux/if_ether.h> |
3 | #include <uapi/linux/if_packet.h> | ||
3 | #include <uapi/linux/ip.h> | 4 | #include <uapi/linux/ip.h> |
4 | #include "bpf_helpers.h" | 5 | #include "bpf_helpers.h" |
5 | 6 | ||
@@ -11,14 +12,17 @@ struct bpf_map_def SEC("maps") my_map = { | |||
11 | }; | 12 | }; |
12 | 13 | ||
13 | SEC("socket1") | 14 | SEC("socket1") |
14 | int bpf_prog1(struct sk_buff *skb) | 15 | int bpf_prog1(struct __sk_buff *skb) |
15 | { | 16 | { |
16 | int index = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol)); | 17 | int index = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol)); |
17 | long *value; | 18 | long *value; |
18 | 19 | ||
20 | if (skb->pkt_type != PACKET_OUTGOING) | ||
21 | return 0; | ||
22 | |||
19 | value = bpf_map_lookup_elem(&my_map, &index); | 23 | value = bpf_map_lookup_elem(&my_map, &index); |
20 | if (value) | 24 | if (value) |
21 | __sync_fetch_and_add(value, 1); | 25 | __sync_fetch_and_add(value, skb->len); |
22 | 26 | ||
23 | return 0; | 27 | return 0; |
24 | } | 28 | } |
diff --git a/samples/bpf/sockex1_user.c b/samples/bpf/sockex1_user.c index 34a443ff3831..678ce4693551 100644 --- a/samples/bpf/sockex1_user.c +++ b/samples/bpf/sockex1_user.c | |||
@@ -40,7 +40,7 @@ int main(int ac, char **argv) | |||
40 | key = IPPROTO_ICMP; | 40 | key = IPPROTO_ICMP; |
41 | assert(bpf_lookup_elem(map_fd[0], &key, &icmp_cnt) == 0); | 41 | assert(bpf_lookup_elem(map_fd[0], &key, &icmp_cnt) == 0); |
42 | 42 | ||
43 | printf("TCP %lld UDP %lld ICMP %lld packets\n", | 43 | printf("TCP %lld UDP %lld ICMP %lld bytes\n", |
44 | tcp_cnt, udp_cnt, icmp_cnt); | 44 | tcp_cnt, udp_cnt, icmp_cnt); |
45 | sleep(1); | 45 | sleep(1); |
46 | } | 46 | } |
diff --git a/samples/bpf/sockex2_kern.c b/samples/bpf/sockex2_kern.c index 6f0135f0f217..ba0e177ff561 100644 --- a/samples/bpf/sockex2_kern.c +++ b/samples/bpf/sockex2_kern.c | |||
@@ -42,13 +42,13 @@ static inline int proto_ports_offset(__u64 proto) | |||
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
45 | static inline int ip_is_fragment(struct sk_buff *ctx, __u64 nhoff) | 45 | static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff) |
46 | { | 46 | { |
47 | return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off)) | 47 | return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off)) |
48 | & (IP_MF | IP_OFFSET); | 48 | & (IP_MF | IP_OFFSET); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline __u32 ipv6_addr_hash(struct sk_buff *ctx, __u64 off) | 51 | static inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off) |
52 | { | 52 | { |
53 | __u64 w0 = load_word(ctx, off); | 53 | __u64 w0 = load_word(ctx, off); |
54 | __u64 w1 = load_word(ctx, off + 4); | 54 | __u64 w1 = load_word(ctx, off + 4); |
@@ -58,7 +58,7 @@ static inline __u32 ipv6_addr_hash(struct sk_buff *ctx, __u64 off) | |||
58 | return (__u32)(w0 ^ w1 ^ w2 ^ w3); | 58 | return (__u32)(w0 ^ w1 ^ w2 ^ w3); |
59 | } | 59 | } |
60 | 60 | ||
61 | static inline __u64 parse_ip(struct sk_buff *skb, __u64 nhoff, __u64 *ip_proto, | 61 | static inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto, |
62 | struct flow_keys *flow) | 62 | struct flow_keys *flow) |
63 | { | 63 | { |
64 | __u64 verlen; | 64 | __u64 verlen; |
@@ -82,7 +82,7 @@ static inline __u64 parse_ip(struct sk_buff *skb, __u64 nhoff, __u64 *ip_proto, | |||
82 | return nhoff; | 82 | return nhoff; |
83 | } | 83 | } |
84 | 84 | ||
85 | static inline __u64 parse_ipv6(struct sk_buff *skb, __u64 nhoff, __u64 *ip_proto, | 85 | static inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto, |
86 | struct flow_keys *flow) | 86 | struct flow_keys *flow) |
87 | { | 87 | { |
88 | *ip_proto = load_byte(skb, | 88 | *ip_proto = load_byte(skb, |
@@ -96,7 +96,7 @@ static inline __u64 parse_ipv6(struct sk_buff *skb, __u64 nhoff, __u64 *ip_proto | |||
96 | return nhoff; | 96 | return nhoff; |
97 | } | 97 | } |
98 | 98 | ||
99 | static inline bool flow_dissector(struct sk_buff *skb, struct flow_keys *flow) | 99 | static inline bool flow_dissector(struct __sk_buff *skb, struct flow_keys *flow) |
100 | { | 100 | { |
101 | __u64 nhoff = ETH_HLEN; | 101 | __u64 nhoff = ETH_HLEN; |
102 | __u64 ip_proto; | 102 | __u64 ip_proto; |
@@ -183,18 +183,23 @@ static inline bool flow_dissector(struct sk_buff *skb, struct flow_keys *flow) | |||
183 | return true; | 183 | return true; |
184 | } | 184 | } |
185 | 185 | ||
186 | struct pair { | ||
187 | long packets; | ||
188 | long bytes; | ||
189 | }; | ||
190 | |||
186 | struct bpf_map_def SEC("maps") hash_map = { | 191 | struct bpf_map_def SEC("maps") hash_map = { |
187 | .type = BPF_MAP_TYPE_HASH, | 192 | .type = BPF_MAP_TYPE_HASH, |
188 | .key_size = sizeof(__be32), | 193 | .key_size = sizeof(__be32), |
189 | .value_size = sizeof(long), | 194 | .value_size = sizeof(struct pair), |
190 | .max_entries = 1024, | 195 | .max_entries = 1024, |
191 | }; | 196 | }; |
192 | 197 | ||
193 | SEC("socket2") | 198 | SEC("socket2") |
194 | int bpf_prog2(struct sk_buff *skb) | 199 | int bpf_prog2(struct __sk_buff *skb) |
195 | { | 200 | { |
196 | struct flow_keys flow; | 201 | struct flow_keys flow; |
197 | long *value; | 202 | struct pair *value; |
198 | u32 key; | 203 | u32 key; |
199 | 204 | ||
200 | if (!flow_dissector(skb, &flow)) | 205 | if (!flow_dissector(skb, &flow)) |
@@ -203,9 +208,10 @@ int bpf_prog2(struct sk_buff *skb) | |||
203 | key = flow.dst; | 208 | key = flow.dst; |
204 | value = bpf_map_lookup_elem(&hash_map, &key); | 209 | value = bpf_map_lookup_elem(&hash_map, &key); |
205 | if (value) { | 210 | if (value) { |
206 | __sync_fetch_and_add(value, 1); | 211 | __sync_fetch_and_add(&value->packets, 1); |
212 | __sync_fetch_and_add(&value->bytes, skb->len); | ||
207 | } else { | 213 | } else { |
208 | long val = 1; | 214 | struct pair val = {1, skb->len}; |
209 | 215 | ||
210 | bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY); | 216 | bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY); |
211 | } | 217 | } |
diff --git a/samples/bpf/sockex2_user.c b/samples/bpf/sockex2_user.c index d2d5f5a790d3..29a276d766fc 100644 --- a/samples/bpf/sockex2_user.c +++ b/samples/bpf/sockex2_user.c | |||
@@ -6,6 +6,11 @@ | |||
6 | #include <unistd.h> | 6 | #include <unistd.h> |
7 | #include <arpa/inet.h> | 7 | #include <arpa/inet.h> |
8 | 8 | ||
9 | struct pair { | ||
10 | __u64 packets; | ||
11 | __u64 bytes; | ||
12 | }; | ||
13 | |||
9 | int main(int ac, char **argv) | 14 | int main(int ac, char **argv) |
10 | { | 15 | { |
11 | char filename[256]; | 16 | char filename[256]; |
@@ -29,13 +34,13 @@ int main(int ac, char **argv) | |||
29 | 34 | ||
30 | for (i = 0; i < 5; i++) { | 35 | for (i = 0; i < 5; i++) { |
31 | int key = 0, next_key; | 36 | int key = 0, next_key; |
32 | long long value; | 37 | struct pair value; |
33 | 38 | ||
34 | while (bpf_get_next_key(map_fd[0], &key, &next_key) == 0) { | 39 | while (bpf_get_next_key(map_fd[0], &key, &next_key) == 0) { |
35 | bpf_lookup_elem(map_fd[0], &next_key, &value); | 40 | bpf_lookup_elem(map_fd[0], &next_key, &value); |
36 | printf("ip %s count %lld\n", | 41 | printf("ip %s bytes %lld packets %lld\n", |
37 | inet_ntoa((struct in_addr){htonl(next_key)}), | 42 | inet_ntoa((struct in_addr){htonl(next_key)}), |
38 | value); | 43 | value.bytes, value.packets); |
39 | key = next_key; | 44 | key = next_key; |
40 | } | 45 | } |
41 | sleep(1); | 46 | sleep(1); |
diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 7b56b59fad8e..df6dbb6576f6 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/unistd.h> | 14 | #include <linux/unistd.h> |
15 | #include <string.h> | 15 | #include <string.h> |
16 | #include <linux/filter.h> | 16 | #include <linux/filter.h> |
17 | #include <stddef.h> | ||
17 | #include "libbpf.h" | 18 | #include "libbpf.h" |
18 | 19 | ||
19 | #define MAX_INSNS 512 | 20 | #define MAX_INSNS 512 |
@@ -642,6 +643,75 @@ static struct bpf_test tests[] = { | |||
642 | }, | 643 | }, |
643 | .result = ACCEPT, | 644 | .result = ACCEPT, |
644 | }, | 645 | }, |
646 | { | ||
647 | "access skb fields ok", | ||
648 | .insns = { | ||
649 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
650 | offsetof(struct __sk_buff, len)), | ||
651 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), | ||
652 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
653 | offsetof(struct __sk_buff, mark)), | ||
654 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), | ||
655 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
656 | offsetof(struct __sk_buff, pkt_type)), | ||
657 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), | ||
658 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
659 | offsetof(struct __sk_buff, queue_mapping)), | ||
660 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), | ||
661 | BPF_EXIT_INSN(), | ||
662 | }, | ||
663 | .result = ACCEPT, | ||
664 | }, | ||
665 | { | ||
666 | "access skb fields bad1", | ||
667 | .insns = { | ||
668 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -4), | ||
669 | BPF_EXIT_INSN(), | ||
670 | }, | ||
671 | .errstr = "invalid bpf_context access", | ||
672 | .result = REJECT, | ||
673 | }, | ||
674 | { | ||
675 | "access skb fields bad2", | ||
676 | .insns = { | ||
677 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 9), | ||
678 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
679 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
680 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
681 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
682 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | ||
683 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
684 | BPF_EXIT_INSN(), | ||
685 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
686 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
687 | offsetof(struct __sk_buff, pkt_type)), | ||
688 | BPF_EXIT_INSN(), | ||
689 | }, | ||
690 | .fixup = {4}, | ||
691 | .errstr = "different pointers", | ||
692 | .result = REJECT, | ||
693 | }, | ||
694 | { | ||
695 | "access skb fields bad3", | ||
696 | .insns = { | ||
697 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | ||
698 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | ||
699 | offsetof(struct __sk_buff, pkt_type)), | ||
700 | BPF_EXIT_INSN(), | ||
701 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | ||
702 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
703 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | ||
704 | BPF_LD_MAP_FD(BPF_REG_1, 0), | ||
705 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | ||
706 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
707 | BPF_EXIT_INSN(), | ||
708 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | ||
709 | BPF_JMP_IMM(BPF_JA, 0, 0, -12), | ||
710 | }, | ||
711 | .fixup = {6}, | ||
712 | .errstr = "different pointers", | ||
713 | .result = REJECT, | ||
714 | }, | ||
645 | }; | 715 | }; |
646 | 716 | ||
647 | static int probe_filter_length(struct bpf_insn *fp) | 717 | static int probe_filter_length(struct bpf_insn *fp) |