Message ID | d1d96894aaa863de51ecd65efa724342c4e13063.1525898587.git.m.xhonneux@gmail.com |
---|---|
State | Changes Requested, archived |
Delegated to: | BPF Maintainers |
Headers | show |
Series | ipv6: sr: introduce seg6local End.BPF action | expand |
Hi Mathieu, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Mathieu-Xhonneux/ipv6-sr-introduce-seg6local-End-BPF-action/20180511-032546 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by >>) net/core/filter.c:112:48: sparse: expression using sizeof(void) net/core/filter.c:112:48: sparse: expression using sizeof(void) net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:206:32: sparse: cast to restricted __be16 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:233:32: sparse: cast to restricted __be32 net/core/filter.c:406:33: sparse: subtraction of functions? Share your drugs net/core/filter.c:409:33: sparse: subtraction of functions? Share your drugs net/core/filter.c:412:33: sparse: subtraction of functions? Share your drugs net/core/filter.c:415:33: sparse: subtraction of functions? Share your drugs net/core/filter.c:418:33: sparse: subtraction of functions? Share your drugs net/core/filter.c:481:27: sparse: subtraction of functions? Share your drugs net/core/filter.c:484:27: sparse: subtraction of functions? Share your drugs net/core/filter.c:487:27: sparse: subtraction of functions? Share your drugs include/linux/filter.h:615:16: sparse: expression using sizeof(void) include/linux/filter.h:615:16: sparse: expression using sizeof(void) include/linux/filter.h:615:16: sparse: expression using sizeof(void) include/linux/filter.h:615:16: sparse: expression using sizeof(void) net/core/filter.c:1368:39: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct sock_filter const *filter @@ got struct sockstruct sock_filter const *filter @@ net/core/filter.c:1368:39: expected struct sock_filter const *filter net/core/filter.c:1368:39: got struct sock_filter [noderef] <asn:1>*filter include/linux/filter.h:615:16: sparse: expression using sizeof(void) include/linux/filter.h:615:16: sparse: expression using sizeof(void) net/core/filter.c:1470:39: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct sock_filter const *filter @@ got struct sockstruct sock_filter const *filter @@ net/core/filter.c:1470:39: expected struct sock_filter const *filter net/core/filter.c:1470:39: got struct sock_filter [noderef] <asn:1>*filter include/linux/filter.h:615:16: sparse: expression using sizeof(void) net/core/filter.c:1772:43: sparse: incorrect type in argument 2 (different base types) @@ expected restricted __wsum [usertype] diff @@ got unsigned lonrestricted __wsum [usertype] diff @@ net/core/filter.c:1772:43: expected restricted __wsum [usertype] diff net/core/filter.c:1772:43: got unsigned long long [unsigned] [usertype] to net/core/filter.c:1775:36: sparse: incorrect type in argument 2 (different base types) @@ expected restricted __be16 [usertype] old @@ got unsigned lonrestricted __be16 [usertype] old @@ net/core/filter.c:1775:36: expected restricted __be16 [usertype] old net/core/filter.c:1775:36: got unsigned long long [unsigned] [usertype] from net/core/filter.c:1775:42: sparse: incorrect type in argument 3 (different base types) @@ expected restricted __be16 [usertype] new @@ got unsigned lonrestricted __be16 [usertype] new @@ net/core/filter.c:1775:42: expected restricted __be16 [usertype] new net/core/filter.c:1775:42: got unsigned long long [unsigned] [usertype] to net/core/filter.c:1778:36: sparse: incorrect type in argument 2 (different base types) @@ expected restricted __be32 [usertype] from @@ got unsigned lonrestricted __be32 [usertype] from @@ net/core/filter.c:1778:36: expected restricted __be32 [usertype] from net/core/filter.c:1778:36: got unsigned long long [unsigned] [usertype] from net/core/filter.c:1778:42: sparse: incorrect type in argument 3 (different base types) @@ expected restricted __be32 [usertype] to @@ got unsigned lonrestricted __be32 [usertype] to @@ net/core/filter.c:1778:42: expected restricted __be32 [usertype] to net/core/filter.c:1778:42: got unsigned long long [unsigned] [usertype] to net/core/filter.c:1823:59: sparse: incorrect type in argument 3 (different base types) @@ expected restricted __wsum [usertype] diff @@ got unsigned lonrestricted __wsum [usertype] diff @@ net/core/filter.c:1823:59: expected restricted __wsum [usertype] diff net/core/filter.c:1823:59: got unsigned long long [unsigned] [usertype] to net/core/filter.c:1826:52: sparse: incorrect type in argument 3 (different base types) @@ expected restricted __be16 [usertype] from @@ got unsigned lonrestricted __be16 [usertype] from @@ net/core/filter.c:1826:52: expected restricted __be16 [usertype] from net/core/filter.c:1826:52: got unsigned long long [unsigned] [usertype] from net/core/filter.c:1826:58: sparse: incorrect type in argument 4 (different base types) @@ expected restricted __be16 [usertype] to @@ got unsigned lonrestricted __be16 [usertype] to @@ net/core/filter.c:1826:58: expected restricted __be16 [usertype] to net/core/filter.c:1826:58: got unsigned long long [unsigned] [usertype] to net/core/filter.c:1829:52: sparse: incorrect type in argument 3 (different base types) @@ expected restricted __be32 [usertype] from @@ got unsigned lonrestricted __be32 [usertype] from @@ net/core/filter.c:1829:52: expected restricted __be32 [usertype] from net/core/filter.c:1829:52: got unsigned long long [unsigned] [usertype] from net/core/filter.c:1829:58: sparse: incorrect type in argument 4 (different base types) @@ expected restricted __be32 [usertype] to @@ got unsigned lonrestricted __be32 [usertype] to @@ net/core/filter.c:1829:58: expected restricted __be32 [usertype] to net/core/filter.c:1829:58: got unsigned long long [unsigned] [usertype] to net/core/filter.c:1875:28: sparse: incorrect type in return expression (different base types) @@ expected unsigned long long @@ got nsigned long long @@ net/core/filter.c:1875:28: expected unsigned long long net/core/filter.c:1875:28: got restricted __wsum net/core/filter.c:1897:35: sparse: incorrect type in return expression (different base types) @@ expected unsigned long long @@ got restricted unsigned long long @@ net/core/filter.c:1897:35: expected unsigned long long net/core/filter.c:1897:35: got restricted __wsum [usertype] csum net/core/filter.c:3708:41: sparse: expression using sizeof(void) net/core/filter.c:3712:41: sparse: expression using sizeof(void) net/core/filter.c:3716:46: sparse: expression using sizeof(void) net/core/filter.c:3716:46: sparse: expression using sizeof(void) net/core/filter.c:3784:47: sparse: expression using sizeof(void) net/core/filter.c:3990:17: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [unsigned] [usertype] spi @@ got unsigned int [unsigned] [usertype] spi @@ net/core/filter.c:3990:17: expected unsigned int [unsigned] [usertype] spi net/core/filter.c:3990:17: got restricted __be32 const [usertype] spi net/core/filter.c:3996:33: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [unsigned] [usertype] remote_ipv4 @@ got unsigned int [unsigned] [usertype] remote_ipv4 @@ net/core/filter.c:3996:33: expected unsigned int [unsigned] [usertype] remote_ipv4 net/core/filter.c:3996:33: got restricted __be32 const [usertype] a4 net/core/filter.c:4835:27: sparse: subtraction of functions? Share your drugs net/core/filter.c:4838:27: sparse: subtraction of functions? Share your drugs net/core/filter.c:4841:27: sparse: subtraction of functions? Share your drugs >> net/core/filter.c:6198:31: sparse: symbol 'lwt_seg6local_verifier_ops' was not declared. Should it be static? >> net/core/filter.c:6204:27: sparse: symbol 'lwt_seg6local_prog_ops' was not declared. Should it be static? Please review and possibly fold the followup patch. --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index cc9d7e031330..f9b24f275869 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -12,6 +12,9 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, cg_sock_addr) BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_IN, lwt_in) BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_OUT, lwt_out) BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_XMIT, lwt_xmit) +#ifdef CONFIG_IPV6_SEG6_BPF +BPF_PROG_TYPE(BPF_PROG_TYPE_LWT_SEG6LOCAL, lwt_seg6local) +#endif BPF_PROG_TYPE(BPF_PROG_TYPE_SOCK_OPS, sock_ops) BPF_PROG_TYPE(BPF_PROG_TYPE_SK_SKB, sk_skb) BPF_PROG_TYPE(BPF_PROG_TYPE_SK_MSG, sk_msg) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 39006c4a30d0..7ee36887858a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -140,6 +140,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SK_MSG, BPF_PROG_TYPE_RAW_TRACEPOINT, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_PROG_TYPE_LWT_SEG6LOCAL, }; enum bpf_attach_type { diff --git a/include/uapi/linux/seg6_local.h b/include/uapi/linux/seg6_local.h index ef2d8c3e76c1..aadcc11fb918 100644 --- a/include/uapi/linux/seg6_local.h +++ b/include/uapi/linux/seg6_local.h @@ -25,6 +25,7 @@ enum { SEG6_LOCAL_NH6, SEG6_LOCAL_IIF, SEG6_LOCAL_OIF, + SEG6_LOCAL_BPF, __SEG6_LOCAL_MAX, }; #define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1) @@ -59,6 +60,8 @@ enum { SEG6_LOCAL_ACTION_END_AS = 13, /* forward to SR-unaware VNF with masquerading */ SEG6_LOCAL_ACTION_END_AM = 14, + /* custom BPF action */ + SEG6_LOCAL_ACTION_END_BPF = 15, __SEG6_LOCAL_ACTION_MAX, }; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index d92d9c37affd..c6b5eadcad16 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1262,6 +1262,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env, switch (env->prog->type) { case BPF_PROG_TYPE_LWT_IN: case BPF_PROG_TYPE_LWT_OUT: + case BPF_PROG_TYPE_LWT_SEG6LOCAL: /* dst_input() and dst_output() can't write for now */ if (t == BPF_WRITE) return false; diff --git a/net/core/filter.c b/net/core/filter.c index 4962e3a44fcc..ce10f203b5b9 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4580,6 +4580,21 @@ lwt_xmit_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) } } +static const struct bpf_func_proto * +lwt_seg6local_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) +{ + switch (func_id) { + case BPF_FUNC_lwt_seg6_store_bytes: + return &bpf_lwt_seg6_store_bytes_proto; + case BPF_FUNC_lwt_seg6_action: + return &bpf_lwt_seg6_action_proto; + case BPF_FUNC_lwt_seg6_adjust_srh: + return &bpf_lwt_seg6_adjust_srh_proto; + default: + return lwt_out_func_proto(func_id, prog); + } +} + static bool bpf_skb_is_valid_access(int off, int size, enum bpf_access_type type, const struct bpf_prog *prog, struct bpf_insn_access_aux *info) @@ -6180,6 +6195,16 @@ const struct bpf_prog_ops lwt_xmit_prog_ops = { .test_run = bpf_prog_test_run_skb, }; +const struct bpf_verifier_ops lwt_seg6local_verifier_ops = { + .get_func_proto = lwt_seg6local_func_proto, + .is_valid_access = lwt_is_valid_access, + .convert_ctx_access = bpf_convert_ctx_access, +}; + +const struct bpf_prog_ops lwt_seg6local_prog_ops = { + .test_run = bpf_prog_test_run_skb, +}; + const struct bpf_verifier_ops cg_sock_verifier_ops = { .get_func_proto = sock_filter_func_proto, .is_valid_access = sock_filter_is_valid_access, diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c index ae68c1ef8fb0..2ac887da63e2 100644 --- a/net/ipv6/seg6_local.c +++ b/net/ipv6/seg6_local.c @@ -1,8 +1,9 @@ /* * SR-IPv6 implementation * - * Author: + * Authors: * David Lebrun <david.lebrun@uclouvain.be> + * eBPF support: Mathieu Xhonneux <m.xhonneux@gmail.com> * * * This program is free software; you can redistribute it and/or @@ -32,6 +33,7 @@ #endif #include <net/seg6_local.h> #include <linux/etherdevice.h> +#include <linux/bpf.h> struct seg6_local_lwt; @@ -42,6 +44,11 @@ struct seg6_action_desc { int static_headroom; }; +struct bpf_lwt_prog { + struct bpf_prog *prog; + char *name; +}; + struct seg6_local_lwt { int action; struct ipv6_sr_hdr *srh; @@ -50,6 +57,7 @@ struct seg6_local_lwt { struct in6_addr nh6; int iif; int oif; + struct bpf_lwt_prog bpf; int headroom; struct seg6_action_desc *desc; @@ -451,6 +459,69 @@ static int input_action_end_b6_encap(struct sk_buff *skb, DEFINE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states); +static int input_action_end_bpf(struct sk_buff *skb, + struct seg6_local_lwt *slwt) +{ + struct seg6_bpf_srh_state *srh_state = + this_cpu_ptr(&seg6_bpf_srh_states); + struct seg6_bpf_srh_state local_srh_state; + struct ipv6_sr_hdr *srh; + int srhoff = 0; + int ret; + + srh = get_and_validate_srh(skb); + if (!srh) + goto drop; + advance_nextseg(srh, &ipv6_hdr(skb)->daddr); + + /* preempt_disable is needed to protect the per-CPU buffer srh_state, + * which is also accessed by the bpf_lwt_seg6_* helpers + */ + preempt_disable(); + srh_state->hdrlen = srh->hdrlen << 3; + srh_state->valid = 1; + + rcu_read_lock(); + bpf_compute_data_pointers(skb); + ret = bpf_prog_run_save_cb(slwt->bpf.prog, skb); + rcu_read_unlock(); + + local_srh_state = *srh_state; + preempt_enable(); + + switch (ret) { + case BPF_OK: + case BPF_REDIRECT: + break; + case BPF_DROP: + goto drop; + default: + pr_warn_once("bpf-seg6local: Illegal return value %u\n", ret); + goto drop; + } + + if (unlikely((local_srh_state.hdrlen & 7) != 0)) + goto drop; + + if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0) + goto drop; + srh = (struct ipv6_sr_hdr *)(skb->data + srhoff); + srh->hdrlen = (u8)(local_srh_state.hdrlen >> 3); + + if (!local_srh_state.valid && + unlikely(!seg6_validate_srh(srh, (srh->hdrlen + 1) << 3))) + goto drop; + + if (ret != BPF_REDIRECT) + seg6_lookup_nexthop(skb, NULL, 0); + + return dst_input(skb); + +drop: + kfree_skb(skb); + return -EINVAL; +} + static struct seg6_action_desc seg6_action_table[] = { { .action = SEG6_LOCAL_ACTION_END, @@ -497,7 +568,13 @@ static struct seg6_action_desc seg6_action_table[] = { .attrs = (1 << SEG6_LOCAL_SRH), .input = input_action_end_b6_encap, .static_headroom = sizeof(struct ipv6hdr), - } + }, + { + .action = SEG6_LOCAL_ACTION_END_BPF, + .attrs = (1 << SEG6_LOCAL_BPF), + .input = input_action_end_bpf, + }, + }; static struct seg6_action_desc *__get_action_desc(int action) @@ -542,6 +619,7 @@ static const struct nla_policy seg6_local_policy[SEG6_LOCAL_MAX + 1] = { .len = sizeof(struct in6_addr) }, [SEG6_LOCAL_IIF] = { .type = NLA_U32 }, [SEG6_LOCAL_OIF] = { .type = NLA_U32 }, + [SEG6_LOCAL_BPF] = { .type = NLA_NESTED }, }; static int parse_nla_srh(struct nlattr **attrs, struct seg6_local_lwt *slwt) @@ -719,6 +797,71 @@ static int cmp_nla_oif(struct seg6_local_lwt *a, struct seg6_local_lwt *b) return 0; } +#define MAX_PROG_NAME 256 +static const struct nla_policy bpf_prog_policy[LWT_BPF_PROG_MAX + 1] = { + [LWT_BPF_PROG_FD] = { .type = NLA_U32, }, + [LWT_BPF_PROG_NAME] = { .type = NLA_NUL_STRING, + .len = MAX_PROG_NAME }, +}; + +static int parse_nla_bpf(struct nlattr **attrs, struct seg6_local_lwt *slwt) +{ + struct nlattr *tb[LWT_BPF_PROG_MAX + 1]; + struct bpf_prog *p; + int ret; + u32 fd; + + ret = nla_parse_nested(tb, LWT_BPF_PROG_MAX, attrs[SEG6_LOCAL_BPF], + bpf_prog_policy, NULL); + if (ret < 0) + return ret; + + if (!tb[LWT_BPF_PROG_FD] || !tb[LWT_BPF_PROG_NAME]) + return -EINVAL; + + slwt->bpf.name = nla_memdup(tb[LWT_BPF_PROG_NAME], GFP_KERNEL); + if (!slwt->bpf.name) + return -ENOMEM; + + fd = nla_get_u32(tb[LWT_BPF_PROG_FD]); + p = bpf_prog_get_type(fd, BPF_PROG_TYPE_LWT_SEG6LOCAL); + if (IS_ERR(p)) + return PTR_ERR(p); + + slwt->bpf.prog = p; + + return 0; +} + +static int put_nla_bpf(struct sk_buff *skb, struct seg6_local_lwt *slwt) +{ + struct nlattr *nest; + + if (!slwt->bpf.prog) + return 0; + + nest = nla_nest_start(skb, SEG6_LOCAL_BPF); + if (!nest) + return -EMSGSIZE; + + if (slwt->bpf.name && + nla_put_string(skb, LWT_BPF_PROG_NAME, slwt->bpf.name)) + return -EMSGSIZE; + + return nla_nest_end(skb, nest); +} + +static int cmp_nla_bpf(struct seg6_local_lwt *a, struct seg6_local_lwt *b) +{ + if (!a->bpf.name && !b->bpf.name) + return 0; + + if (!a->bpf.name || !b->bpf.name) + return 1; + + return strcmp(a->bpf.name, b->bpf.name); +} + struct seg6_action_param { int (*parse)(struct nlattr **attrs, struct seg6_local_lwt *slwt); int (*put)(struct sk_buff *skb, struct seg6_local_lwt *slwt); @@ -749,6 +892,11 @@ static struct seg6_action_param seg6_action_params[SEG6_LOCAL_MAX + 1] = { [SEG6_LOCAL_OIF] = { .parse = parse_nla_oif, .put = put_nla_oif, .cmp = cmp_nla_oif }, + + [SEG6_LOCAL_BPF] = { .parse = parse_nla_bpf, + .put = put_nla_bpf, + .cmp = cmp_nla_bpf }, + }; static int parse_nla_action(struct nlattr **attrs, struct seg6_local_lwt *slwt) @@ -797,7 +945,6 @@ static int seg6_local_build_state(struct nlattr *nla, unsigned int family, err = nla_parse_nested(tb, SEG6_LOCAL_MAX, nla, seg6_local_policy, extack); - if (err < 0) return err; @@ -886,6 +1033,11 @@ static int seg6_local_get_encap_size(struct lwtunnel_state *lwt) if (attrs & (1 << SEG6_LOCAL_OIF)) nlsize += nla_total_size(4); + if (attrs & (1 << SEG6_LOCAL_BPF)) + nlsize += nla_total_size(sizeof(struct nlattr)) + + nla_total_size(MAX_PROG_NAME) + + nla_total_size(4); + return nlsize; }