Skip to content

Commit

Permalink
Merge branch 'Get ingress_ifindex in BPF_SK_LOOKUP prog type'
Browse files Browse the repository at this point in the history
Mark Pashmfouroush says:

====================

BPF_SK_LOOKUP users may want to have access to the ifindex of the skb
which triggered the socket lookup. This may be useful for selectively
applying programmable socket lookup logic to packets that arrive on a
specific interface, or excluding packets from an interface.

v3:
- Rename ifindex field to ingress_ifindex for consistency. (Yonghong)

v2:
- Fix inaccurate comment (Alexei)
- Add more details to commit messages (John)
====================

Revieview-by: Lorenz Bauer <lmb@cloudflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Alexei Starovoitov committed Nov 11, 2021
2 parents 1a8b597 + 8b4fd2b commit 04f8cb6
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 18 deletions.
7 changes: 5 additions & 2 deletions include/linux/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,7 @@ struct bpf_sk_lookup_kern {
const struct in6_addr *daddr;
} v6;
struct sock *selected_sk;
u32 ingress_ifindex;
bool no_reuseport;
};

Expand Down Expand Up @@ -1436,7 +1437,7 @@ extern struct static_key_false bpf_sk_lookup_enabled;
static inline bool bpf_sk_lookup_run_v4(struct net *net, int protocol,
const __be32 saddr, const __be16 sport,
const __be32 daddr, const u16 dport,
struct sock **psk)
const int ifindex, struct sock **psk)
{
struct bpf_prog_array *run_array;
struct sock *selected_sk = NULL;
Expand All @@ -1452,6 +1453,7 @@ static inline bool bpf_sk_lookup_run_v4(struct net *net, int protocol,
.v4.daddr = daddr,
.sport = sport,
.dport = dport,
.ingress_ifindex = ifindex,
};
u32 act;

Expand All @@ -1474,7 +1476,7 @@ static inline bool bpf_sk_lookup_run_v6(struct net *net, int protocol,
const __be16 sport,
const struct in6_addr *daddr,
const u16 dport,
struct sock **psk)
const int ifindex, struct sock **psk)
{
struct bpf_prog_array *run_array;
struct sock *selected_sk = NULL;
Expand All @@ -1490,6 +1492,7 @@ static inline bool bpf_sk_lookup_run_v6(struct net *net, int protocol,
.v6.daddr = daddr,
.sport = sport,
.dport = dport,
.ingress_ifindex = ifindex,
};
u32 act;

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -6316,6 +6316,7 @@ struct bpf_sk_lookup {
__u32 local_ip4; /* Network byte order */
__u32 local_ip6[4]; /* Network byte order */
__u32 local_port; /* Host byte order */
__u32 ingress_ifindex; /* The arriving interface. Determined by inet_iif. */
};

/*
Expand Down
7 changes: 7 additions & 0 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -10491,6 +10491,7 @@ static bool sk_lookup_is_valid_access(int off, int size,
case bpf_ctx_range_till(struct bpf_sk_lookup, local_ip6[0], local_ip6[3]):
case bpf_ctx_range(struct bpf_sk_lookup, remote_port):
case bpf_ctx_range(struct bpf_sk_lookup, local_port):
case bpf_ctx_range(struct bpf_sk_lookup, ingress_ifindex):
bpf_ctx_record_field_size(info, sizeof(__u32));
return bpf_ctx_narrow_access_ok(off, size, sizeof(__u32));

Expand Down Expand Up @@ -10580,6 +10581,12 @@ static u32 sk_lookup_convert_ctx_access(enum bpf_access_type type,
bpf_target_off(struct bpf_sk_lookup_kern,
dport, 2, target_size));
break;

case offsetof(struct bpf_sk_lookup, ingress_ifindex):
*insn++ = BPF_LDX_MEM(BPF_W, si->dst_reg, si->src_reg,
bpf_target_off(struct bpf_sk_lookup_kern,
ingress_ifindex, 4, target_size));
break;
}

return insn - insn_buf;
Expand Down
8 changes: 4 additions & 4 deletions net/ipv4/inet_hashtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,16 +307,16 @@ static inline struct sock *inet_lookup_run_bpf(struct net *net,
struct inet_hashinfo *hashinfo,
struct sk_buff *skb, int doff,
__be32 saddr, __be16 sport,
__be32 daddr, u16 hnum)
__be32 daddr, u16 hnum, const int dif)
{
struct sock *sk, *reuse_sk;
bool no_reuseport;

if (hashinfo != &tcp_hashinfo)
return NULL; /* only TCP is supported */

no_reuseport = bpf_sk_lookup_run_v4(net, IPPROTO_TCP,
saddr, sport, daddr, hnum, &sk);
no_reuseport = bpf_sk_lookup_run_v4(net, IPPROTO_TCP, saddr, sport,
daddr, hnum, dif, &sk);
if (no_reuseport || IS_ERR_OR_NULL(sk))
return sk;

Expand All @@ -340,7 +340,7 @@ struct sock *__inet_lookup_listener(struct net *net,
/* Lookup redirect from BPF */
if (static_branch_unlikely(&bpf_sk_lookup_enabled)) {
result = inet_lookup_run_bpf(net, hashinfo, skb, doff,
saddr, sport, daddr, hnum);
saddr, sport, daddr, hnum, dif);
if (result)
goto done;
}
Expand Down
8 changes: 4 additions & 4 deletions net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,16 +460,16 @@ static struct sock *udp4_lookup_run_bpf(struct net *net,
struct udp_table *udptable,
struct sk_buff *skb,
__be32 saddr, __be16 sport,
__be32 daddr, u16 hnum)
__be32 daddr, u16 hnum, const int dif)
{
struct sock *sk, *reuse_sk;
bool no_reuseport;

if (udptable != &udp_table)
return NULL; /* only UDP is supported */

no_reuseport = bpf_sk_lookup_run_v4(net, IPPROTO_UDP,
saddr, sport, daddr, hnum, &sk);
no_reuseport = bpf_sk_lookup_run_v4(net, IPPROTO_UDP, saddr, sport,
daddr, hnum, dif, &sk);
if (no_reuseport || IS_ERR_OR_NULL(sk))
return sk;

Expand Down Expand Up @@ -505,7 +505,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
/* Lookup redirect from BPF */
if (static_branch_unlikely(&bpf_sk_lookup_enabled)) {
sk = udp4_lookup_run_bpf(net, udptable, skb,
saddr, sport, daddr, hnum);
saddr, sport, daddr, hnum, dif);
if (sk) {
result = sk;
goto done;
Expand Down
8 changes: 4 additions & 4 deletions net/ipv6/inet6_hashtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,16 @@ static inline struct sock *inet6_lookup_run_bpf(struct net *net,
const struct in6_addr *saddr,
const __be16 sport,
const struct in6_addr *daddr,
const u16 hnum)
const u16 hnum, const int dif)
{
struct sock *sk, *reuse_sk;
bool no_reuseport;

if (hashinfo != &tcp_hashinfo)
return NULL; /* only TCP is supported */

no_reuseport = bpf_sk_lookup_run_v6(net, IPPROTO_TCP,
saddr, sport, daddr, hnum, &sk);
no_reuseport = bpf_sk_lookup_run_v6(net, IPPROTO_TCP, saddr, sport,
daddr, hnum, dif, &sk);
if (no_reuseport || IS_ERR_OR_NULL(sk))
return sk;

Expand All @@ -198,7 +198,7 @@ struct sock *inet6_lookup_listener(struct net *net,
/* Lookup redirect from BPF */
if (static_branch_unlikely(&bpf_sk_lookup_enabled)) {
result = inet6_lookup_run_bpf(net, hashinfo, skb, doff,
saddr, sport, daddr, hnum);
saddr, sport, daddr, hnum, dif);
if (result)
goto done;
}
Expand Down
8 changes: 4 additions & 4 deletions net/ipv6/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,16 @@ static inline struct sock *udp6_lookup_run_bpf(struct net *net,
const struct in6_addr *saddr,
__be16 sport,
const struct in6_addr *daddr,
u16 hnum)
u16 hnum, const int dif)
{
struct sock *sk, *reuse_sk;
bool no_reuseport;

if (udptable != &udp_table)
return NULL; /* only UDP is supported */

no_reuseport = bpf_sk_lookup_run_v6(net, IPPROTO_UDP,
saddr, sport, daddr, hnum, &sk);
no_reuseport = bpf_sk_lookup_run_v6(net, IPPROTO_UDP, saddr, sport,
daddr, hnum, dif, &sk);
if (no_reuseport || IS_ERR_OR_NULL(sk))
return sk;

Expand Down Expand Up @@ -240,7 +240,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
/* Lookup redirect from BPF */
if (static_branch_unlikely(&bpf_sk_lookup_enabled)) {
sk = udp6_lookup_run_bpf(net, udptable, skb,
saddr, sport, daddr, hnum);
saddr, sport, daddr, hnum, dif);
if (sk) {
result = sk;
goto done;
Expand Down
1 change: 1 addition & 0 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -6316,6 +6316,7 @@ struct bpf_sk_lookup {
__u32 local_ip4; /* Network byte order */
__u32 local_ip6[4]; /* Network byte order */
__u32 local_port; /* Host byte order */
__u32 ingress_ifindex; /* The arriving interface. Determined by inet_iif. */
};

/*
Expand Down
31 changes: 31 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/sk_lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,37 @@ static void test_drop_on_lookup(struct test_sk_lookup *skel)
.connect_to = { EXT_IP6, EXT_PORT },
.listen_at = { EXT_IP6, INT_PORT },
},
/* The program will drop on success, meaning that the ifindex
* was 1.
*/
{
.desc = "TCP IPv4 drop on valid ifindex",
.lookup_prog = skel->progs.check_ifindex,
.sotype = SOCK_STREAM,
.connect_to = { EXT_IP4, EXT_PORT },
.listen_at = { EXT_IP4, EXT_PORT },
},
{
.desc = "TCP IPv6 drop on valid ifindex",
.lookup_prog = skel->progs.check_ifindex,
.sotype = SOCK_STREAM,
.connect_to = { EXT_IP6, EXT_PORT },
.listen_at = { EXT_IP6, EXT_PORT },
},
{
.desc = "UDP IPv4 drop on valid ifindex",
.lookup_prog = skel->progs.check_ifindex,
.sotype = SOCK_DGRAM,
.connect_to = { EXT_IP4, EXT_PORT },
.listen_at = { EXT_IP4, EXT_PORT },
},
{
.desc = "UDP IPv6 drop on valid ifindex",
.lookup_prog = skel->progs.check_ifindex,
.sotype = SOCK_DGRAM,
.connect_to = { EXT_IP6, EXT_PORT },
.listen_at = { EXT_IP6, EXT_PORT },
},
};
const struct test *t;

Expand Down
8 changes: 8 additions & 0 deletions tools/testing/selftests/bpf/progs/test_sk_lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ int lookup_drop(struct bpf_sk_lookup *ctx)
return SK_DROP;
}

SEC("sk_lookup")
int check_ifindex(struct bpf_sk_lookup *ctx)
{
if (ctx->ingress_ifindex == 1)
return SK_DROP;
return SK_PASS;
}

SEC("sk_reuseport")
int reuseport_pass(struct sk_reuseport_md *ctx)
{
Expand Down
32 changes: 32 additions & 0 deletions tools/testing/selftests/bpf/verifier/ctx_sk_lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,24 @@
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, local_port)),

/* 1-byte read from ingress_ifindex field */
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex)),
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex) + 1),
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex) + 2),
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex) + 3),
/* 2-byte read from ingress_ifindex field */
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex)),
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex) + 2),
/* 4-byte read from ingress_ifindex field */
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex)),

/* 8-byte read from sk field */
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, sk)),
Expand Down Expand Up @@ -351,6 +369,20 @@
.expected_attach_type = BPF_SK_LOOKUP,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
},
{
"invalid 8-byte read from bpf_sk_lookup ingress_ifindex field",
.insns = {
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
offsetof(struct bpf_sk_lookup, ingress_ifindex)),
BPF_MOV32_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.errstr = "invalid bpf_context access",
.result = REJECT,
.prog_type = BPF_PROG_TYPE_SK_LOOKUP,
.expected_attach_type = BPF_SK_LOOKUP,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
},
/* invalid 1,2,4-byte reads from 8-byte fields in bpf_sk_lookup */
{
"invalid 4-byte read from bpf_sk_lookup sk field",
Expand Down

0 comments on commit 04f8cb6

Please sign in to comment.