diff options
author | Lawrence Brakmo <brakmo@fb.com> | 2018-01-25 19:14:13 -0500 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-01-25 19:41:14 -0500 |
commit | 6f9bd3d731aac0d2ac21dd78a642af5df38fb5c5 (patch) | |
tree | df671f4091e123537da0639e818023b109d6bc22 /net | |
parent | 44f0e43037d3a17b043843ba67610ac7c7e37db6 (diff) |
bpf: Add sock_ops R/W access to tclass
Adds direct write access to sk_txhash and access to tclass for ipv6
flows through getsockopt and setsockopt. Sample usage for tclass:
bpf_getsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, sizeof(v))
where skops is a pointer to the ctx (struct bpf_sock_ops).
Signed-off-by: Lawrence Brakmo <brakmo@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/filter.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index a858ebc4ece4..fe2c7937351f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -3232,6 +3232,29 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
3232 | ret = -EINVAL; | 3232 | ret = -EINVAL; |
3233 | } | 3233 | } |
3234 | #ifdef CONFIG_INET | 3234 | #ifdef CONFIG_INET |
3235 | #if IS_ENABLED(CONFIG_IPV6) | ||
3236 | } else if (level == SOL_IPV6) { | ||
3237 | if (optlen != sizeof(int) || sk->sk_family != AF_INET6) | ||
3238 | return -EINVAL; | ||
3239 | |||
3240 | val = *((int *)optval); | ||
3241 | /* Only some options are supported */ | ||
3242 | switch (optname) { | ||
3243 | case IPV6_TCLASS: | ||
3244 | if (val < -1 || val > 0xff) { | ||
3245 | ret = -EINVAL; | ||
3246 | } else { | ||
3247 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
3248 | |||
3249 | if (val == -1) | ||
3250 | val = 0; | ||
3251 | np->tclass = val; | ||
3252 | } | ||
3253 | break; | ||
3254 | default: | ||
3255 | ret = -EINVAL; | ||
3256 | } | ||
3257 | #endif | ||
3235 | } else if (level == SOL_TCP && | 3258 | } else if (level == SOL_TCP && |
3236 | sk->sk_prot->setsockopt == tcp_setsockopt) { | 3259 | sk->sk_prot->setsockopt == tcp_setsockopt) { |
3237 | if (optname == TCP_CONGESTION) { | 3260 | if (optname == TCP_CONGESTION) { |
@@ -3241,7 +3264,8 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
3241 | strncpy(name, optval, min_t(long, optlen, | 3264 | strncpy(name, optval, min_t(long, optlen, |
3242 | TCP_CA_NAME_MAX-1)); | 3265 | TCP_CA_NAME_MAX-1)); |
3243 | name[TCP_CA_NAME_MAX-1] = 0; | 3266 | name[TCP_CA_NAME_MAX-1] = 0; |
3244 | ret = tcp_set_congestion_control(sk, name, false, reinit); | 3267 | ret = tcp_set_congestion_control(sk, name, false, |
3268 | reinit); | ||
3245 | } else { | 3269 | } else { |
3246 | struct tcp_sock *tp = tcp_sk(sk); | 3270 | struct tcp_sock *tp = tcp_sk(sk); |
3247 | 3271 | ||
@@ -3307,6 +3331,22 @@ BPF_CALL_5(bpf_getsockopt, struct bpf_sock_ops_kern *, bpf_sock, | |||
3307 | } else { | 3331 | } else { |
3308 | goto err_clear; | 3332 | goto err_clear; |
3309 | } | 3333 | } |
3334 | #if IS_ENABLED(CONFIG_IPV6) | ||
3335 | } else if (level == SOL_IPV6) { | ||
3336 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
3337 | |||
3338 | if (optlen != sizeof(int) || sk->sk_family != AF_INET6) | ||
3339 | goto err_clear; | ||
3340 | |||
3341 | /* Only some options are supported */ | ||
3342 | switch (optname) { | ||
3343 | case IPV6_TCLASS: | ||
3344 | *((int *)optval) = (int)np->tclass; | ||
3345 | break; | ||
3346 | default: | ||
3347 | goto err_clear; | ||
3348 | } | ||
3349 | #endif | ||
3310 | } else { | 3350 | } else { |
3311 | goto err_clear; | 3351 | goto err_clear; |
3312 | } | 3352 | } |
@@ -3871,6 +3911,7 @@ static bool sock_ops_is_valid_access(int off, int size, | |||
3871 | if (type == BPF_WRITE) { | 3911 | if (type == BPF_WRITE) { |
3872 | switch (off) { | 3912 | switch (off) { |
3873 | case offsetof(struct bpf_sock_ops, reply): | 3913 | case offsetof(struct bpf_sock_ops, reply): |
3914 | case offsetof(struct bpf_sock_ops, sk_txhash): | ||
3874 | if (size != size_default) | 3915 | if (size != size_default) |
3875 | return false; | 3916 | return false; |
3876 | break; | 3917 | break; |
@@ -4690,7 +4731,8 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, | |||
4690 | break; | 4731 | break; |
4691 | 4732 | ||
4692 | case offsetof(struct bpf_sock_ops, sk_txhash): | 4733 | case offsetof(struct bpf_sock_ops, sk_txhash): |
4693 | SOCK_OPS_GET_FIELD(sk_txhash, sk_txhash, struct sock); | 4734 | SOCK_OPS_GET_OR_SET_FIELD(sk_txhash, sk_txhash, |
4735 | struct sock, type); | ||
4694 | break; | 4736 | break; |
4695 | 4737 | ||
4696 | case offsetof(struct bpf_sock_ops, bytes_received): | 4738 | case offsetof(struct bpf_sock_ops, bytes_received): |
@@ -4701,6 +4743,7 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, | |||
4701 | case offsetof(struct bpf_sock_ops, bytes_acked): | 4743 | case offsetof(struct bpf_sock_ops, bytes_acked): |
4702 | SOCK_OPS_GET_FIELD(bytes_acked, bytes_acked, struct tcp_sock); | 4744 | SOCK_OPS_GET_FIELD(bytes_acked, bytes_acked, struct tcp_sock); |
4703 | break; | 4745 | break; |
4746 | |||
4704 | } | 4747 | } |
4705 | return insn - insn_buf; | 4748 | return insn - insn_buf; |
4706 | } | 4749 | } |