tc, bpf, examples: further bpf_api improvements
Add a couple of improvements to tc's BPF api, that facilitate program development. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
9450c5ec63
commit
92a36995b3
|
|
@ -11,9 +11,7 @@ BPF_PROG_ARRAY(jmp_tc, JMP_MAP_ID, PIN_OBJECT_NS, 1);
|
||||||
__section_tail(JMP_MAP_ID, 0)
|
__section_tail(JMP_MAP_ID, 0)
|
||||||
int cls_loop(struct __sk_buff *skb)
|
int cls_loop(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "cb: %u\n";
|
printt("cb: %u\n", skb->cb[0]++);
|
||||||
|
|
||||||
trace_printk(fmt, sizeof(fmt), skb->cb[0]++);
|
|
||||||
tail_call(skb, &jmp_tc, 0);
|
tail_call(skb, &jmp_tc, 0);
|
||||||
|
|
||||||
skb->tc_classid = TC_H_MAKE(1, 42);
|
skb->tc_classid = TC_H_MAKE(1, 42);
|
||||||
|
|
|
||||||
|
|
@ -38,29 +38,22 @@ BPF_PROG_ARRAY(jmp_tc, 0, PIN_GLOBAL_NS, 1);
|
||||||
__section("aaa")
|
__section("aaa")
|
||||||
int cls_aaa(struct __sk_buff *skb)
|
int cls_aaa(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "aaa\n";
|
printt("aaa\n");
|
||||||
|
|
||||||
trace_printk(fmt, sizeof(fmt));
|
|
||||||
return TC_H_MAKE(1, 42);
|
return TC_H_MAKE(1, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
__section("bbb")
|
__section("bbb")
|
||||||
int cls_bbb(struct __sk_buff *skb)
|
int cls_bbb(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "bbb\n";
|
printt("bbb\n");
|
||||||
|
|
||||||
trace_printk(fmt, sizeof(fmt));
|
|
||||||
return TC_H_MAKE(1, 43);
|
return TC_H_MAKE(1, 43);
|
||||||
}
|
}
|
||||||
|
|
||||||
__section_cls_entry
|
__section_cls_entry
|
||||||
int cls_entry(struct __sk_buff *skb)
|
int cls_entry(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "fallthrough\n";
|
|
||||||
|
|
||||||
tail_call(skb, &jmp_tc, 0);
|
tail_call(skb, &jmp_tc, 0);
|
||||||
trace_printk(fmt, sizeof(fmt));
|
printt("fallthrough\n");
|
||||||
|
|
||||||
return BPF_H_DEFAULT;
|
return BPF_H_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ struct flow_keys {
|
||||||
__u8 ip_proto;
|
__u8 ip_proto;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int flow_ports_offset(__u8 ip_proto)
|
static __inline__ int flow_ports_offset(__u8 ip_proto)
|
||||||
{
|
{
|
||||||
switch (ip_proto) {
|
switch (ip_proto) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
|
|
@ -249,14 +249,14 @@ static inline int flow_ports_offset(__u8 ip_proto)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool flow_is_frag(struct __sk_buff *skb, int nh_off)
|
static __inline__ bool flow_is_frag(struct __sk_buff *skb, int nh_off)
|
||||||
{
|
{
|
||||||
return !!(load_half(skb, nh_off + offsetof(struct iphdr, frag_off)) &
|
return !!(load_half(skb, nh_off + offsetof(struct iphdr, frag_off)) &
|
||||||
(IP_MF | IP_OFFSET));
|
(IP_MF | IP_OFFSET));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int flow_parse_ipv4(struct __sk_buff *skb, int nh_off,
|
static __inline__ int flow_parse_ipv4(struct __sk_buff *skb, int nh_off,
|
||||||
__u8 *ip_proto, struct flow_keys *flow)
|
__u8 *ip_proto, struct flow_keys *flow)
|
||||||
{
|
{
|
||||||
__u8 ip_ver_len;
|
__u8 ip_ver_len;
|
||||||
|
|
||||||
|
|
@ -279,7 +279,7 @@ static inline int flow_parse_ipv4(struct __sk_buff *skb, int nh_off,
|
||||||
return nh_off;
|
return nh_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off)
|
static __inline__ __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off)
|
||||||
{
|
{
|
||||||
__u32 w0 = load_word(skb, off);
|
__u32 w0 = load_word(skb, off);
|
||||||
__u32 w1 = load_word(skb, off + sizeof(w0));
|
__u32 w1 = load_word(skb, off + sizeof(w0));
|
||||||
|
|
@ -289,8 +289,8 @@ static inline __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off)
|
||||||
return w0 ^ w1 ^ w2 ^ w3;
|
return w0 ^ w1 ^ w2 ^ w3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int flow_parse_ipv6(struct __sk_buff *skb, int nh_off,
|
static __inline__ int flow_parse_ipv6(struct __sk_buff *skb, int nh_off,
|
||||||
__u8 *ip_proto, struct flow_keys *flow)
|
__u8 *ip_proto, struct flow_keys *flow)
|
||||||
{
|
{
|
||||||
*ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
|
*ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr));
|
||||||
|
|
||||||
|
|
@ -300,8 +300,8 @@ static inline int flow_parse_ipv6(struct __sk_buff *skb, int nh_off,
|
||||||
return nh_off + sizeof(struct ipv6hdr);
|
return nh_off + sizeof(struct ipv6hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool flow_dissector(struct __sk_buff *skb,
|
static __inline__ bool flow_dissector(struct __sk_buff *skb,
|
||||||
struct flow_keys *flow)
|
struct flow_keys *flow)
|
||||||
{
|
{
|
||||||
int poff, nh_off = BPF_LL_OFF + ETH_HLEN;
|
int poff, nh_off = BPF_LL_OFF + ETH_HLEN;
|
||||||
__be16 proto = skb->protocol;
|
__be16 proto = skb->protocol;
|
||||||
|
|
@ -381,8 +381,8 @@ static inline bool flow_dissector(struct __sk_buff *skb,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cls_update_proto_map(const struct __sk_buff *skb,
|
static __inline__ void cls_update_proto_map(const struct __sk_buff *skb,
|
||||||
const struct flow_keys *flow)
|
const struct flow_keys *flow)
|
||||||
{
|
{
|
||||||
uint8_t proto = flow->ip_proto;
|
uint8_t proto = flow->ip_proto;
|
||||||
struct count_tuple *ct, _ct;
|
struct count_tuple *ct, _ct;
|
||||||
|
|
@ -401,7 +401,7 @@ static inline void cls_update_proto_map(const struct __sk_buff *skb,
|
||||||
map_update_elem(&map_proto, &proto, &_ct, BPF_ANY);
|
map_update_elem(&map_proto, &proto, &_ct, BPF_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cls_update_queue_map(const struct __sk_buff *skb)
|
static __inline__ void cls_update_queue_map(const struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
uint32_t queue = skb->queue_mapping;
|
uint32_t queue = skb->queue_mapping;
|
||||||
struct count_queue *cq, _cq;
|
struct count_queue *cq, _cq;
|
||||||
|
|
@ -453,7 +453,7 @@ int cls_main(struct __sk_buff *skb)
|
||||||
return flow.ip_proto;
|
return flow.ip_proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void act_update_drop_map(void)
|
static __inline__ void act_update_drop_map(void)
|
||||||
{
|
{
|
||||||
uint32_t *count, cpu = get_smp_processor_id();
|
uint32_t *count, cpu = get_smp_processor_id();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,11 @@ int emain(struct __sk_buff *skb)
|
||||||
__section("ingress")
|
__section("ingress")
|
||||||
int imain(struct __sk_buff *skb)
|
int imain(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "map val: %d\n";
|
|
||||||
int key = 0, *val;
|
int key = 0, *val;
|
||||||
|
|
||||||
val = map_lookup_elem(&map_sh, &key);
|
val = map_lookup_elem(&map_sh, &key);
|
||||||
if (val)
|
if (val)
|
||||||
trace_printk(fmt, sizeof(fmt), *val);
|
printt("map val: %d\n", *val);
|
||||||
|
|
||||||
return BPF_H_DEFAULT;
|
return BPF_H_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,11 @@ BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1);
|
||||||
__section_tail(FOO, ENTRY_0)
|
__section_tail(FOO, ENTRY_0)
|
||||||
int cls_case1(struct __sk_buff *skb)
|
int cls_case1(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "case1: map-val: %d from:%u\n";
|
|
||||||
int key = 0, *val;
|
int key = 0, *val;
|
||||||
|
|
||||||
val = map_lookup_elem(&map_sh, &key);
|
val = map_lookup_elem(&map_sh, &key);
|
||||||
if (val)
|
if (val)
|
||||||
trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]);
|
printt("case1: map-val: %d from:%u\n", *val, skb->cb[0]);
|
||||||
|
|
||||||
skb->cb[0] = ENTRY_0;
|
skb->cb[0] = ENTRY_0;
|
||||||
tail_call(skb, &jmp_ex, ENTRY_0);
|
tail_call(skb, &jmp_ex, ENTRY_0);
|
||||||
|
|
@ -50,12 +49,11 @@ int cls_case1(struct __sk_buff *skb)
|
||||||
__section_tail(FOO, ENTRY_1)
|
__section_tail(FOO, ENTRY_1)
|
||||||
int cls_case2(struct __sk_buff *skb)
|
int cls_case2(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "case2: map-val: %d from:%u\n";
|
|
||||||
int key = 0, *val;
|
int key = 0, *val;
|
||||||
|
|
||||||
val = map_lookup_elem(&map_sh, &key);
|
val = map_lookup_elem(&map_sh, &key);
|
||||||
if (val)
|
if (val)
|
||||||
trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]);
|
printt("case2: map-val: %d from:%u\n", *val, skb->cb[0]);
|
||||||
|
|
||||||
skb->cb[0] = ENTRY_1;
|
skb->cb[0] = ENTRY_1;
|
||||||
tail_call(skb, &jmp_tc, ENTRY_0);
|
tail_call(skb, &jmp_tc, ENTRY_0);
|
||||||
|
|
@ -66,12 +64,11 @@ int cls_case2(struct __sk_buff *skb)
|
||||||
__section_tail(BAR, ENTRY_0)
|
__section_tail(BAR, ENTRY_0)
|
||||||
int cls_exit(struct __sk_buff *skb)
|
int cls_exit(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "exit: map-val: %d from:%u\n";
|
|
||||||
int key = 0, *val;
|
int key = 0, *val;
|
||||||
|
|
||||||
val = map_lookup_elem(&map_sh, &key);
|
val = map_lookup_elem(&map_sh, &key);
|
||||||
if (val)
|
if (val)
|
||||||
trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]);
|
printt("exit: map-val: %d from:%u\n", *val, skb->cb[0]);
|
||||||
|
|
||||||
/* Termination point. */
|
/* Termination point. */
|
||||||
return BPF_H_DEFAULT;
|
return BPF_H_DEFAULT;
|
||||||
|
|
@ -80,7 +77,6 @@ int cls_exit(struct __sk_buff *skb)
|
||||||
__section_cls_entry
|
__section_cls_entry
|
||||||
int cls_entry(struct __sk_buff *skb)
|
int cls_entry(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
char fmt[] = "fallthrough\n";
|
|
||||||
int key = 0, *val;
|
int key = 0, *val;
|
||||||
|
|
||||||
/* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */
|
/* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */
|
||||||
|
|
@ -92,7 +88,7 @@ int cls_entry(struct __sk_buff *skb)
|
||||||
tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1));
|
tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_printk(fmt, sizeof(fmt));
|
printt("fallthrough\n");
|
||||||
return BPF_H_DEFAULT;
|
return BPF_H_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,10 @@
|
||||||
# define ntohl(X) __constant_ntohl((X))
|
# define ntohl(X) __constant_ntohl((X))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __inline__
|
||||||
|
# define __inline__ __attribute__((always_inline))
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Section helper macros. */
|
/** Section helper macros. */
|
||||||
|
|
||||||
#ifndef __section
|
#ifndef __section
|
||||||
|
|
@ -146,7 +150,7 @@
|
||||||
# define BPF_H_DEFAULT -1
|
# define BPF_H_DEFAULT -1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** BPF helper functions for tc. */
|
/** BPF helper functions for tc. Individual flags are in linux/bpf.h */
|
||||||
|
|
||||||
#ifndef BPF_FUNC
|
#ifndef BPF_FUNC
|
||||||
# define BPF_FUNC(NAME, ...) \
|
# define BPF_FUNC(NAME, ...) \
|
||||||
|
|
@ -163,8 +167,22 @@ static int BPF_FUNC(map_delete_elem, void *map, const void *key);
|
||||||
static uint64_t BPF_FUNC(ktime_get_ns);
|
static uint64_t BPF_FUNC(ktime_get_ns);
|
||||||
|
|
||||||
/* Debugging */
|
/* Debugging */
|
||||||
|
|
||||||
|
/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless
|
||||||
|
* llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved.
|
||||||
|
* It would require ____fmt to be made const, which generates a reloc
|
||||||
|
* entry (non-map).
|
||||||
|
*/
|
||||||
static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
|
static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
|
||||||
|
|
||||||
|
#ifndef printt
|
||||||
|
# define printt(fmt, ...) \
|
||||||
|
({ \
|
||||||
|
char ____fmt[] = fmt; \
|
||||||
|
trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Random numbers */
|
/* Random numbers */
|
||||||
static uint32_t BPF_FUNC(get_prandom_u32);
|
static uint32_t BPF_FUNC(get_prandom_u32);
|
||||||
|
|
||||||
|
|
@ -185,12 +203,11 @@ static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex,
|
||||||
uint32_t flags);
|
uint32_t flags);
|
||||||
|
|
||||||
/* Packet manipulation */
|
/* Packet manipulation */
|
||||||
#define BPF_PSEUDO_HDR 0x10
|
static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off,
|
||||||
#define BPF_HAS_PSEUDO_HDR(flags) ((flags) & BPF_PSEUDO_HDR)
|
void *to, uint32_t len);
|
||||||
#define BPF_HDR_FIELD_SIZE(flags) ((flags) & 0x0f)
|
|
||||||
|
|
||||||
static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
|
static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off,
|
||||||
void *from, uint32_t len, uint32_t flags);
|
const void *from, uint32_t len, uint32_t flags);
|
||||||
|
|
||||||
static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
|
static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off,
|
||||||
uint32_t from, uint32_t to, uint32_t flags);
|
uint32_t from, uint32_t to, uint32_t flags);
|
||||||
static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
|
static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off,
|
||||||
|
|
@ -205,14 +222,37 @@ static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb);
|
||||||
static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
|
static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb,
|
||||||
struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
|
struct bpf_tunnel_key *to, uint32_t size, uint32_t flags);
|
||||||
static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
|
static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb,
|
||||||
struct bpf_tunnel_key *from, uint32_t size, uint32_t flags);
|
const struct bpf_tunnel_key *from, uint32_t size,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
/** LLVM built-ins */
|
/** LLVM built-ins, mem*() routines work for constant size */
|
||||||
|
|
||||||
#ifndef lock_xadd
|
#ifndef lock_xadd
|
||||||
# define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val))
|
# define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef memset
|
||||||
|
# define memset(s, c, n) __builtin_memset((s), (c), (n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef memcpy
|
||||||
|
# define memcpy(d, s, n) __builtin_memcpy((d), (s), (n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef memmove
|
||||||
|
# define memmove(d, s, n) __builtin_memmove((d), (s), (n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FIXME: __builtin_memcmp() is not yet fully useable unless llvm bug
|
||||||
|
* https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also
|
||||||
|
* this one would generate a reloc entry (non-map), otherwise.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#ifndef memcmp
|
||||||
|
# define memcmp(a, b, n) __builtin_memcmp((a), (b), (n))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned long long load_byte(void *skb, unsigned long long off)
|
unsigned long long load_byte(void *skb, unsigned long long off)
|
||||||
asm ("llvm.bpf.load.byte");
|
asm ("llvm.bpf.load.byte");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue