bpf: Add sock_ops R/W access to ipv4 tos
authorNikita V. Shirokov <tehnerd@fb.com>
Mon, 26 Mar 2018 15:36:57 +0000 (08:36 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Wed, 28 Mar 2018 19:05:35 +0000 (21:05 +0200)
Sample usage for tos ...

  bpf_getsockopt(skops, SOL_IP, IP_TOS, &v, sizeof(v))

... where skops is a pointer to the ctx (struct bpf_sock_ops).

Signed-off-by: Nikita V. Shirokov <tehnerd@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
net/core/filter.c

index 00c711c5f1a2965d6333aedccabf40843d92a4a3..afd825534ac465f09023c2324740093a98b48609 100644 (file)
@@ -3462,6 +3462,27 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                        ret = -EINVAL;
                }
 #ifdef CONFIG_INET
+       } else if (level == SOL_IP) {
+               if (optlen != sizeof(int) || sk->sk_family != AF_INET)
+                       return -EINVAL;
+
+               val = *((int *)optval);
+               /* Only some options are supported */
+               switch (optname) {
+               case IP_TOS:
+                       if (val < -1 || val > 0xff) {
+                               ret = -EINVAL;
+                       } else {
+                               struct inet_sock *inet = inet_sk(sk);
+
+                               if (val == -1)
+                                       val = 0;
+                               inet->tos = val;
+                       }
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
 #if IS_ENABLED(CONFIG_IPV6)
        } else if (level == SOL_IPV6) {
                if (optlen != sizeof(int) || sk->sk_family != AF_INET6)
@@ -3561,6 +3582,20 @@ BPF_CALL_5(bpf_getsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                } else {
                        goto err_clear;
                }
+       } else if (level == SOL_IP) {
+               struct inet_sock *inet = inet_sk(sk);
+
+               if (optlen != sizeof(int) || sk->sk_family != AF_INET)
+                       goto err_clear;
+
+               /* Only some options are supported */
+               switch (optname) {
+               case IP_TOS:
+                       *((int *)optval) = (int)inet->tos;
+                       break;
+               default:
+                       goto err_clear;
+               }
 #if IS_ENABLED(CONFIG_IPV6)
        } else if (level == SOL_IPV6) {
                struct ipv6_pinfo *np = inet6_sk(sk);