[SRU][F:linux-bluefield][PATCH 19/21] UBUNTU: SAUCE: bpf: Add a helper to query TCP conntrack information in XDP

Bodong Wang bodong at nvidia.com
Mon Jul 5 15:39:57 UTC 2021


From: Maxim Mikityanskiy <maximmi at nvidia.com>

BugLink: https://bugs.launchpad.net/bugs/1934499

The new bpf_ct_lookup_tcp helper allows to query connection tracking
information of a TCP connection based on source and destination IP
address and port. The helper returns the status flags of the conntrack
entry if found.

Signed-off-by: Maxim Mikityanskiy <maximmi at nvidia.com>
Reviewed-by: Tariq Toukan <tariqt at nvidia.com>
Signed-off-by: Bodong Wang <bodong at nvidia.com>
---
 include/uapi/linux/bpf.h                  | 20 ++++++++-
 net/core/filter.c                         | 71 +++++++++++++++++++++++++++++++
 tools/include/uapi/linux/bpf.h            | 20 ++++++++-
 tools/testing/selftests/bpf/bpf_helpers.h |  3 ++
 4 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f182bd7..9128511 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -2750,6 +2750,23 @@ struct bpf_stack_build_id {
  *		**-EOPNOTSUPP** kernel configuration does not enable SYN cookies
  *
  *		**-EPROTONOSUPPORT** IP packet version is not 4 or 6
+ *
+ * long bpf_ct_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
+ *	Description
+ *		Look for conntrack info for a TCP connection matching *tuple*,
+ *		optionally in a child network namespace *netns*.
+ *
+ *		This helper is available only if the kernel was compiled with
+ *		**CONFIG_NF_CONNTRACK** configuration option as built-in.
+ *	Return
+ *		On success, connection tracking status (see **enum
+ *		ip_conntrack_status**).
+ *
+ *		On failure, the returned value is one of the following:
+ *
+ *		**-EINVAL** input arguments are invalid.
+ *
+ *		**-ENOENT** the connection is not known to conntrack.
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -2862,7 +2879,8 @@ struct bpf_stack_build_id {
 	FN(sk_storage_get),		\
 	FN(sk_storage_delete),		\
 	FN(send_signal),		\
-	FN(tcp_gen_syncookie),
+	FN(tcp_gen_syncookie),		\
+	FN(ct_lookup_tcp),		\
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index 609fe9f..7df5971 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -73,6 +73,8 @@
 #include <net/lwtunnel.h>
 #include <net/ipv6_stubs.h>
 #include <net/bpf_sk_storage.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
 
 /**
  *	sk_filter_trim_cap - run a packet through a socket filter
@@ -5950,6 +5952,71 @@ u32 bpf_xdp_sock_convert_ctx_access(enum bpf_access_type type,
 	.arg5_type	= ARG_CONST_SIZE,
 };
 
+#if IS_BUILTIN(CONFIG_NF_CONNTRACK)
+BPF_CALL_5(bpf_xdp_ct_lookup_tcp, struct xdp_buff *, ctx,
+	   struct bpf_sock_tuple *, bpf_tuple, u32, len,
+	   u64, netns_id, u64, flags)
+{
+	struct nf_conntrack_tuple_hash *found;
+	const struct nf_conntrack_zone *zone;
+	struct nf_conntrack_tuple tuple = {};
+	unsigned long status;
+	struct nf_conn *ct;
+	struct net *net;
+
+	if (len == sizeof(bpf_tuple->ipv4)) {
+		tuple.src.l3num = AF_INET;
+		tuple.src.u3.ip = bpf_tuple->ipv4.saddr;
+		tuple.src.u.tcp.port = bpf_tuple->ipv4.sport;
+		tuple.dst.u3.ip = bpf_tuple->ipv4.daddr;
+		tuple.dst.u.tcp.port = bpf_tuple->ipv4.dport;
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (len == sizeof(bpf_tuple->ipv6)) {
+		tuple.src.l3num = AF_INET6;
+		memcpy(tuple.src.u3.ip6, bpf_tuple->ipv6.saddr, sizeof(bpf_tuple->ipv6.saddr));
+		tuple.src.u.tcp.port = bpf_tuple->ipv6.sport;
+		memcpy(tuple.dst.u3.ip6, bpf_tuple->ipv6.daddr, sizeof(bpf_tuple->ipv6.daddr));
+		tuple.dst.u.tcp.port = bpf_tuple->ipv6.dport;
+#endif
+	} else {
+		return -EINVAL;
+	}
+
+	net = dev_net(ctx->rxq->dev);
+	if ((s32)netns_id >= 0) {
+		if (unlikely(netns_id) > S32_MAX)
+			return -EINVAL;
+		net = get_net_ns_by_id(net, netns_id);
+	}
+
+	zone = &nf_ct_zone_dflt;
+
+	tuple.dst.protonum = IPPROTO_TCP;
+	tuple.dst.dir = IP_CT_DIR_ORIGINAL;
+
+	found = nf_conntrack_find_get(net, zone, &tuple);
+	if (!found)
+		return -ENOENT;
+	ct = nf_ct_tuplehash_to_ctrack(found);
+	status = ct->status;
+	nf_ct_put(ct);
+
+	return status;
+}
+
+static const struct bpf_func_proto bpf_xdp_ct_lookup_tcp_proto = {
+	.func		= bpf_xdp_ct_lookup_tcp,
+	.gpl_only	= true, /* nf_conntrack_find_get is GPL */
+	.pkt_access	= true,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_PTR_TO_CTX,
+	.arg2_type	= ARG_PTR_TO_MEM,
+	.arg3_type	= ARG_CONST_SIZE,
+	.arg4_type	= ARG_ANYTHING,
+	.arg5_type	= ARG_ANYTHING,
+};
+#endif
+
 #endif /* CONFIG_INET */
 
 bool bpf_helper_changes_pkt_data(void *func)
@@ -6284,6 +6351,10 @@ bool bpf_helper_changes_pkt_data(void *func)
 		return &bpf_tcp_check_syncookie_proto;
 	case BPF_FUNC_tcp_gen_syncookie:
 		return &bpf_tcp_gen_syncookie_proto;
+#if IS_BUILTIN(CONFIG_NF_CONNTRACK)
+	case BPF_FUNC_ct_lookup_tcp:
+		return &bpf_xdp_ct_lookup_tcp_proto;
+#endif
 #endif
 	default:
 		return bpf_base_func_proto(func_id);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 8649422..14ffd42 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -2750,6 +2750,23 @@ struct bpf_stack_build_id {
  *		**-EOPNOTSUPP** kernel configuration does not enable SYN cookies
  *
  *		**-EPROTONOSUPPORT** IP packet version is not 4 or 6
+ *
+ * long bpf_ct_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
+ *	Description
+ *		Look for conntrack info for a TCP connection matching *tuple*,
+ *		optionally in a child network namespace *netns*.
+ *
+ *		This helper is available only if the kernel was compiled with
+ *		**CONFIG_NF_CONNTRACK** configuration option as built-in.
+ *	Return
+ *		On success, connection tracking status (see **enum
+ *		ip_conntrack_status**).
+ *
+ *		On failure, the returned value is one of the following:
+ *
+ *		**-EINVAL** input arguments are invalid.
+ *
+ *		**-ENOENT** the connection is not known to conntrack.
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -2862,7 +2879,8 @@ struct bpf_stack_build_id {
 	FN(sk_storage_get),		\
 	FN(sk_storage_delete),		\
 	FN(send_signal),		\
-	FN(tcp_gen_syncookie),
+	FN(tcp_gen_syncookie),		\
+	FN(ct_lookup_tcp),		\
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h
index 9f77cba..9f1e2ac 100644
--- a/tools/testing/selftests/bpf/bpf_helpers.h
+++ b/tools/testing/selftests/bpf/bpf_helpers.h
@@ -233,6 +233,9 @@ static int (*bpf_sk_storage_delete)(void *map, struct bpf_sock *sk) =
 static long long (*bpf_tcp_gen_syncookie)(struct bpf_sock *sk, void *ip,
 					  int ip_len, void *tcp, int tcp_len) =
 	(void *) BPF_FUNC_tcp_gen_syncookie;
+static long (*bpf_ct_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple,
+				 __u32 tuple_size, __u64 netns, __u64 flags) =
+	(void *) BPF_FUNC_ct_lookup_tcp;
 
 /* llvm builtin functions that eBPF C program may use to
  * emit BPF_LD_ABS and BPF_LD_IND instructions
-- 
1.8.3.1




More information about the kernel-team mailing list