bpf: Add support for reading socket family, type, protocol
authorDavid Ahern <dsa@cumulusnetworks.com>
Thu, 1 Dec 2016 16:48:06 +0000 (08:48 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Dec 2016 18:46:09 +0000 (13:46 -0500)
Add socket family, type and protocol to bpf_sock allowing bpf programs
read-only access.

Add __sk_flags_offset[0] to struct sock before the bitfield to
programmtically determine the offset of the unsigned int containing
protocol and type.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sock.h
include/uapi/linux/bpf.h
net/core/filter.c

index 442cbb118a07e3f9b208215ad2af025636d1a85a..69afda6bea15643f8769c8a0e261aac924f0f225 100644 (file)
@@ -389,6 +389,21 @@ struct sock {
         * Because of non atomicity rules, all
         * changes are protected by socket lock.
         */
+       unsigned int            __sk_flags_offset[0];
+#ifdef __BIG_ENDIAN_BITFIELD
+#define SK_FL_PROTO_SHIFT  16
+#define SK_FL_PROTO_MASK   0x00ff0000
+
+#define SK_FL_TYPE_SHIFT   0
+#define SK_FL_TYPE_MASK    0x0000ffff
+#else
+#define SK_FL_PROTO_SHIFT  8
+#define SK_FL_PROTO_MASK   0x0000ff00
+
+#define SK_FL_TYPE_SHIFT   16
+#define SK_FL_TYPE_MASK    0xffff0000
+#endif
+
        kmemcheck_bitfield_begin(flags);
        unsigned int            sk_padding : 2,
                                sk_no_check_tx : 1,
index bfe5e31a128838fc9d78cbd3f166e2427f58b38a..6123d9b8e828b2ff0d825bd8f4ffe374daac9b4f 100644 (file)
@@ -571,6 +571,9 @@ enum bpf_ret_code {
 
 struct bpf_sock {
        __u32 bound_dev_if;
+       __u32 family;
+       __u32 type;
+       __u32 protocol;
 };
 
 /* User return codes for XDP prog type.
index 0ab252e462aabc110eba96d6e14273ad48dec216..56b43587d2006c400af06df00f221296dd8d1f13 100644 (file)
@@ -3121,6 +3121,27 @@ static u32 sock_filter_convert_ctx_access(enum bpf_access_type type,
                        *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg,
                                      offsetof(struct sock, sk_bound_dev_if));
                break;
+
+       case offsetof(struct bpf_sock, family):
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sock, sk_family) != 2);
+
+               *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg,
+                                     offsetof(struct sock, sk_family));
+               break;
+
+       case offsetof(struct bpf_sock, type):
+               *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg,
+                                     offsetof(struct sock, __sk_flags_offset));
+               *insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, SK_FL_TYPE_MASK);
+               *insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, SK_FL_TYPE_SHIFT);
+               break;
+
+       case offsetof(struct bpf_sock, protocol):
+               *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg,
+                                     offsetof(struct sock, __sk_flags_offset));
+               *insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, SK_FL_PROTO_MASK);
+               *insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, SK_FL_PROTO_SHIFT);
+               break;
        }
 
        return insn - insn_buf;