* [PATCH net-next v4 01/13] ipv6: Add udp6_lib_lookup to IPv6 stubs
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 02/13] flow_dissector: Parse ETH_P_TEB and move out of GRE Tom Herbert
` (11 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Want to do a UDP socket lookup from flow dissector so create a
stub for udp6_lib_lookup
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
include/net/ipv6_stubs.h | 5 +++++
net/ipv6/af_inet6.c | 1 +
2 files changed, 6 insertions(+)
diff --git a/include/net/ipv6_stubs.h b/include/net/ipv6_stubs.h
index 8a3465c8c2c5..fc6111fe820a 100644
--- a/include/net/ipv6_stubs.h
+++ b/include/net/ipv6_stubs.h
@@ -75,6 +75,11 @@ struct ipv6_stub {
struct net_device *dev);
int (*ip6_xmit)(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
__u32 mark, struct ipv6_txoptions *opt, int tclass, u32 priority);
+ struct sock *(*udp6_lib_lookup)(const struct net *net,
+ const struct in6_addr *saddr, __be16 sport,
+ const struct in6_addr *daddr, __be16 dport,
+ int dif, int sdif, struct udp_table *tbl,
+ struct sk_buff *skb);
};
extern const struct ipv6_stub *ipv6_stub __read_mostly;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 90d2c7e3f5e9..699f1e3efb91 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -1061,6 +1061,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
.ipv6_fragment = ip6_fragment,
.ipv6_dev_find = ipv6_dev_find,
.ip6_xmit = ip6_xmit,
+ .udp6_lib_lookup = __udp6_lib_lookup,
};
static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 02/13] flow_dissector: Parse ETH_P_TEB and move out of GRE
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 01/13] ipv6: Add udp6_lib_lookup to IPv6 stubs Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 03/13] udp_encaps: Add new UDP_ENCAP constants Tom Herbert
` (10 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert, Willem de Bruijn
ETH_P_TEB (Trans Ether Bridging) is the EtherType to carry
a plain Etherent frame. Add case in skb_flow_dissect to parse
packets of this type
If the GRE protocol is ETH_P_TEB then just process that as any
another EtherType since it's now supported in the main loop
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 71 +++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 26 deletions(-)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 0e638a37aa09..5170676a224c 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -654,7 +654,7 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
struct flow_dissector_key_control *key_control,
struct flow_dissector *flow_dissector,
void *target_container, const void *data,
- __be16 *p_proto, int *p_nhoff, int *p_hlen,
+ __be16 *p_proto, int *p_nhoff, int hlen,
unsigned int flags)
{
struct flow_dissector_key_keyid *key_keyid;
@@ -663,7 +663,7 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
u16 gre_ver;
hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr),
- data, *p_hlen, &_hdr);
+ data, hlen, &_hdr);
if (!hdr)
return FLOW_DISSECT_RET_OUT_BAD;
@@ -695,7 +695,7 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
keyid = __skb_header_pointer(skb, *p_nhoff + offset,
sizeof(_keyid),
- data, *p_hlen, &_keyid);
+ data, hlen, &_keyid);
if (!keyid)
return FLOW_DISSECT_RET_OUT_BAD;
@@ -715,27 +715,11 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
if (hdr->flags & GRE_SEQ)
offset += sizeof_field(struct pptp_gre_header, seq);
- if (gre_ver == 0) {
- if (*p_proto == htons(ETH_P_TEB)) {
- const struct ethhdr *eth;
- struct ethhdr _eth;
-
- eth = __skb_header_pointer(skb, *p_nhoff + offset,
- sizeof(_eth),
- data, *p_hlen, &_eth);
- if (!eth)
- return FLOW_DISSECT_RET_OUT_BAD;
- *p_proto = eth->h_proto;
- offset += sizeof(*eth);
-
- /* Cap headers that we access via pointers at the
- * end of the Ethernet header as our maximum alignment
- * at that point is only 2 bytes.
- */
- if (NET_IP_ALIGN)
- *p_hlen = *p_nhoff + offset;
- }
- } else { /* version 1, must be PPTP */
+ /* For GRE version 0 p_proto is already correctly set (including if
+ * it is ETH_P_TEB)
+ */
+
+ if (gre_ver == 1) { /* Version 1 is PPP */
u8 _ppp_hdr[PPP_HDRLEN];
u8 *ppp_hdr;
@@ -744,7 +728,7 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
ppp_hdr = __skb_header_pointer(skb, *p_nhoff + offset,
sizeof(_ppp_hdr),
- data, *p_hlen, _ppp_hdr);
+ data, hlen, _ppp_hdr);
if (!ppp_hdr)
return FLOW_DISSECT_RET_OUT_BAD;
@@ -1284,6 +1268,41 @@ bool __skb_flow_dissect(const struct net *net,
break;
}
+ case htons(ETH_P_TEB): {
+ const struct ethhdr *eth;
+ struct ethhdr _eth;
+
+ eth = __skb_header_pointer(skb, nhoff, sizeof(_eth),
+ data, hlen, &_eth);
+ if (!eth)
+ goto out_bad;
+
+ proto = eth->h_proto;
+ nhoff += sizeof(*eth);
+
+ /* Cap headers that we access via pointers at the end of the
+ * Ethernet header as our maximum alignment at that point is
+ * only 2 bytes.
+ *
+ * For the real Ethernet header the receive skbuf is offset by
+ * two so that device places the packet such that the Ethernet
+ * payload, i.e. IP header, is aligned to four bytes (14+2=16
+ * which will be offset of IP header). When a packet contains
+ * an encapsulated Ethernet header, the offset of the header is
+ * aligned to four bytes which means the payload of that
+ * Ethernet header, i.e. an encapsulated IP header, is not four
+ * byte aligned and neither are any subsequent headers (TCP,
+ * UDP, etc.). On some architectures, performing unaligned
+ * loads is expensive compared to aligned loads, so hlen is
+ * being capped here to avoid having flow dissector do unaligned
+ * loads on unaligned headers after the Ethernet header.
+ */
+ if (NET_IP_ALIGN)
+ hlen = nhoff;
+
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
+ break;
+ }
case htons(ETH_P_8021AD):
case htons(ETH_P_8021Q): {
const struct vlan_hdr *vlan = NULL;
@@ -1531,7 +1550,7 @@ bool __skb_flow_dissect(const struct net *net,
fdret = __skb_flow_dissect_gre(skb, key_control, flow_dissector,
target_container, data,
- &proto, &nhoff, &hlen, flags);
+ &proto, &nhoff, hlen, flags);
break;
case NEXTHDR_HOP:
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 03/13] udp_encaps: Add new UDP_ENCAP constants
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 01/13] ipv6: Add udp6_lib_lookup to IPv6 stubs Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 02/13] flow_dissector: Parse ETH_P_TEB and move out of GRE Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 04/13] udp_encaps: Set proper UDP_ENCAP types in tunnel setup Tom Herbert
` (9 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert, Willem de Bruijn
Add constants for various UDP encapsulations that are supported
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
include/uapi/linux/udp.h | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
index 1a0fe8b151fb..bf15c4ded3e8 100644
--- a/include/uapi/linux/udp.h
+++ b/include/uapi/linux/udp.h
@@ -35,7 +35,12 @@ struct udphdr {
#define UDP_SEGMENT 103 /* Set GSO segmentation size */
#define UDP_GRO 104 /* This socket can receive UDP GRO packets */
-/* UDP encapsulation types */
+/* UDP encapsulation types
+ *
+ * Note that these are defined in UAPI since we may need to use them externally,
+ * for instance by eBPF
+ */
+#define UDP_ENCAP_NONE 0
#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* unused draft-ietf-ipsec-nat-t-ike-00/01 */
#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */
#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */
@@ -43,5 +48,17 @@ struct udphdr {
#define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */
#define UDP_ENCAP_RXRPC 6
#define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */
+#define UDP_ENCAP_TIPC 8
+#define UDP_ENCAP_FOU 9
+#define UDP_ENCAP_GUE 10
+#define UDP_ENCAP_SCTP 11
+#define UDP_ENCAP_RXE 12
+#define UDP_ENCAP_PFCP 13
+#define UDP_ENCAP_WIREGUARD 14
+#define UDP_ENCAP_BAREUDP 15
+#define UDP_ENCAP_VXLAN 16
+#define UDP_ENCAP_VXLAN_GPE 17
+#define UDP_ENCAP_GENEVE 18
+#define UDP_ENCAP_AMT 19
#endif /* _UAPI_LINUX_UDP_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 04/13] udp_encaps: Set proper UDP_ENCAP types in tunnel setup
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (2 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 03/13] udp_encaps: Add new UDP_ENCAP constants Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 05/13] flow_dissector: UDP encap infrastructure Tom Herbert
` (8 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert, Willem de Bruijn
Instead of just setting UDP tunnel config encap_type to 1,
use the appropriate constat for the tunnel type. This value
can be used to determine the encapsulated protocol in UDP
by looking at the socket
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
drivers/infiniband/sw/rxe/rxe_net.c | 2 +-
drivers/net/amt.c | 2 +-
drivers/net/bareudp.c | 2 +-
drivers/net/geneve.c | 2 +-
drivers/net/pfcp.c | 2 +-
drivers/net/vxlan/vxlan_core.c | 3 ++-
drivers/net/wireguard/socket.c | 2 +-
net/ipv4/fou_core.c | 3 ++-
net/sctp/protocol.c | 2 +-
net/tipc/udp_media.c | 2 +-
10 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
index 75d1407db52d..1c2bb88132c5 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -193,7 +193,7 @@ static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port,
if (err < 0)
return ERR_PTR(err);
- tnl_cfg.encap_type = 1;
+ tnl_cfg.encap_type = UDP_ENCAP_RXE;
tnl_cfg.encap_rcv = rxe_udp_encap_recv;
/* Setup UDP tunnel */
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 6d15ab3bfbbc..fc421cf2c032 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -2970,7 +2970,7 @@ static int amt_socket_create(struct amt_dev *amt)
/* Mark socket as an encapsulation socket */
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
tunnel_cfg.sk_user_data = amt;
- tunnel_cfg.encap_type = 1;
+ tunnel_cfg.encap_type = UDP_ENCAP_AMT;
tunnel_cfg.encap_rcv = amt_rcv;
tunnel_cfg.encap_err_lookup = amt_err_lookup;
tunnel_cfg.encap_destroy = NULL;
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index d5c56ca91b77..007fb8c5168b 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -248,7 +248,7 @@ static int bareudp_socket_create(struct bareudp_dev *bareudp, __be16 port)
/* Mark socket as an encapsulation socket */
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
tunnel_cfg.sk_user_data = bareudp;
- tunnel_cfg.encap_type = 1;
+ tunnel_cfg.encap_type = UDP_ENCAP_BAREUDP;
tunnel_cfg.encap_rcv = bareudp_udp_encap_recv;
tunnel_cfg.encap_err_lookup = bareudp_err_lookup;
tunnel_cfg.encap_destroy = NULL;
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 838e85ddec67..923c573b6e5c 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -611,7 +611,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
/* Mark socket as an encapsulation socket */
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
tunnel_cfg.sk_user_data = gs;
- tunnel_cfg.encap_type = 1;
+ tunnel_cfg.encap_type = UDP_ENCAP_GENEVE;
tunnel_cfg.gro_receive = geneve_gro_receive;
tunnel_cfg.gro_complete = geneve_gro_complete;
tunnel_cfg.encap_rcv = geneve_udp_encap_recv;
diff --git a/drivers/net/pfcp.c b/drivers/net/pfcp.c
index 69434fd13f96..c7e4fa606b16 100644
--- a/drivers/net/pfcp.c
+++ b/drivers/net/pfcp.c
@@ -170,7 +170,7 @@ static struct socket *pfcp_create_sock(struct pfcp_dev *pfcp)
tuncfg.sk_user_data = pfcp;
tuncfg.encap_rcv = pfcp_encap_recv;
- tuncfg.encap_type = 1;
+ tuncfg.encap_type = UDP_ENCAP_PFCP;
setup_udp_tunnel_sock(net, sock, &tuncfg);
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 8983e75e9881..e02cbc018b8c 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -3572,7 +3572,8 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
/* Mark socket as an encapsulation socket. */
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
tunnel_cfg.sk_user_data = vs;
- tunnel_cfg.encap_type = 1;
+ tunnel_cfg.encap_type = vs->flags & VXLAN_F_GPE ?
+ UDP_ENCAP_VXLAN_GPE : UDP_ENCAP_VXLAN;
tunnel_cfg.encap_rcv = vxlan_rcv;
tunnel_cfg.encap_err_lookup = vxlan_err_lookup;
tunnel_cfg.encap_destroy = NULL;
diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c
index 0414d7a6ce74..f4b5bd14fd56 100644
--- a/drivers/net/wireguard/socket.c
+++ b/drivers/net/wireguard/socket.c
@@ -352,7 +352,7 @@ int wg_socket_init(struct wg_device *wg, u16 port)
int ret;
struct udp_tunnel_sock_cfg cfg = {
.sk_user_data = wg,
- .encap_type = 1,
+ .encap_type = UDP_ENCAP_WIREGUARD,
.encap_rcv = wg_receive
};
struct socket *new4 = NULL, *new6 = NULL;
diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c
index 0abbc413e0fe..8241f762e45b 100644
--- a/net/ipv4/fou_core.c
+++ b/net/ipv4/fou_core.c
@@ -578,19 +578,20 @@ static int fou_create(struct net *net, struct fou_cfg *cfg,
fou->sock = sock;
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
- tunnel_cfg.encap_type = 1;
tunnel_cfg.sk_user_data = fou;
tunnel_cfg.encap_destroy = NULL;
/* Initial for fou type */
switch (cfg->type) {
case FOU_ENCAP_DIRECT:
+ tunnel_cfg.encap_type = UDP_ENCAP_FOU;
tunnel_cfg.encap_rcv = fou_udp_recv;
tunnel_cfg.gro_receive = fou_gro_receive;
tunnel_cfg.gro_complete = fou_gro_complete;
fou->protocol = cfg->protocol;
break;
case FOU_ENCAP_GUE:
+ tunnel_cfg.encap_type = UDP_ENCAP_GUE;
tunnel_cfg.encap_rcv = gue_udp_recv;
tunnel_cfg.gro_receive = gue_gro_receive;
tunnel_cfg.gro_complete = gue_gro_complete;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 5a7436a13b74..290ebcf17a48 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -876,7 +876,7 @@ int sctp_udp_sock_start(struct net *net)
return err;
}
- tuncfg.encap_type = 1;
+ tuncfg.encap_type = UDP_ENCAP_SCTP;
tuncfg.encap_rcv = sctp_udp_rcv;
tuncfg.encap_err_lookup = sctp_udp_v4_err;
setup_udp_tunnel_sock(net, sock, &tuncfg);
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 439f75539977..3c081b7b9d67 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -771,7 +771,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
if (err)
goto err;
tuncfg.sk_user_data = ub;
- tuncfg.encap_type = 1;
+ tuncfg.encap_type = UDP_ENCAP_TIPC;
tuncfg.encap_rcv = tipc_udp_recv;
tuncfg.encap_destroy = NULL;
setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 05/13] flow_dissector: UDP encap infrastructure
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (3 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 04/13] udp_encaps: Set proper UDP_ENCAP types in tunnel setup Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-24 19:18 ` Simon Horman
2024-08-23 20:15 ` [PATCH net-next v4 06/13] flow_dissector: Parse vxlan in UDP Tom Herbert
` (7 subsequent siblings)
12 siblings, 1 reply; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Add infrastructure for parsing into UDP encapsulations
Add function __skb_flow_dissect_udp that is called for IPPROTO_UDP.
The flag FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS enables parsing of UDP
encapsulations. If the flag is set when parsing a UDP packet then
a socket lookup is performed. The offset of the base network header,
either an IPv4 or IPv6 header, is tracked and passed to
__skb_flow_dissect_udp so that it can perform the socket lookup
If a socket is found and it's for a UDP encapsulation (encap_type is
set in the UDP socket) then a switch is performed on the encap_type
value (cases are UDP_ENCAP_* values)
An encapsulated packet in UDP can either be indicated by an
EtherType or IP protocol. The processing for dissecting a UDP encap
protocol returns a flow dissector return code. If
FLOW_DISSECT_RET_PROTO_AGAIN or FLOW_DISSECT_RET_IPPROTO_AGAIN is
returned then the corresponding encapsulated protocol is dissected.
The nhoff is set to point to the header to process. In the case
FLOW_DISSECT_RET_PROTO_AGAIN the EtherType protocol is returned and
the IP protocol is set to zero. In the case of
FLOW_DISSECT_RET_IPPROTO_AGAIN, the IP protocol is returned and
the EtherType protocol is returned unchanged
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
include/net/flow_dissector.h | 1 +
net/core/flow_dissector.c | 138 +++++++++++++++++++++++++++++++++++
2 files changed, 139 insertions(+)
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index ced79dc8e856..8a868a88a6f1 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -384,6 +384,7 @@ enum flow_dissector_key_id {
#define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(1)
#define FLOW_DISSECTOR_F_STOP_AT_ENCAP BIT(2)
#define FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP BIT(3)
+#define FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS BIT(4)
struct flow_dissector_key {
enum flow_dissector_key_id key_id;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 5170676a224c..f3134804a1db 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -13,6 +13,7 @@
#include <net/gre.h>
#include <net/pptp.h>
#include <net/tipc.h>
+#include <net/udp.h>
#include <linux/igmp.h>
#include <linux/icmp.h>
#include <linux/sctp.h>
@@ -806,6 +807,134 @@ __skb_flow_dissect_batadv(const struct sk_buff *skb,
return FLOW_DISSECT_RET_PROTO_AGAIN;
}
+static enum flow_dissect_ret
+__skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
+ struct flow_dissector *flow_dissector,
+ void *target_container, const void *data,
+ int *p_nhoff, int hlen, __be16 *p_proto,
+ u8 *p_ip_proto, int base_nhoff, unsigned int flags,
+ unsigned int num_hdrs)
+{
+ enum flow_dissect_ret ret;
+ struct udphdr _udph;
+ int nhoff;
+
+ if (!(flags & FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS))
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ /* Check that the netns for the skb device is the same as the caller's,
+ * and only dissect UDP if we haven't yet encountered any encapsulation.
+ * The goal is to ensure that the socket lookup is being done in the
+ * right netns. Encapsulations may push packets into different name
+ * spaces, so this scheme is restricting UDP dissection to cases where
+ * they are in the same name spaces or at least the original name space.
+ * This should capture the majority of use cases for UDP encaps, and
+ * if we do encounter a UDP encapsulation within a different namespace
+ * then the only effect is we don't attempt UDP dissection
+ */
+ if (dev_net(skb->dev) != net || num_hdrs > 0)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ switch (*p_proto) {
+#ifdef CONFIG_INET
+ case htons(ETH_P_IP): {
+ const struct udphdr *udph;
+ const struct iphdr *iph;
+ struct iphdr _iph;
+ struct sock *sk;
+
+ iph = __skb_header_pointer(skb, base_nhoff, sizeof(_iph), data,
+ hlen, &_iph);
+ if (!iph)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ udph = __skb_header_pointer(skb, *p_nhoff, sizeof(_udph), data,
+ hlen, &_udph);
+ if (!udph)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ rcu_read_lock();
+ /* Look up the UDPv4 socket and get the encap_type */
+ sk = __udp4_lib_lookup(net, iph->saddr, udph->source,
+ iph->daddr, udph->dest,
+ inet_iif(skb), inet_sdif(skb),
+ net->ipv4.udp_table, NULL);
+ if (!sk || !udp_sk(sk)->encap_type) {
+ rcu_read_unlock();
+ return FLOW_DISSECT_RET_OUT_GOOD;
+ }
+
+ encap_type = udp_sk(sk)->encap_type;
+ rcu_read_unlock();
+
+ break;
+ }
+#if IS_ENABLED(CONFIG_IPV6)
+ case htons(ETH_P_IPV6): {
+ const struct ipv6hdr *iph;
+ const struct udphdr *udph;
+ struct ipv6hdr _iph;
+ struct sock *sk;
+
+ if (!likely(ipv6_stub))
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ iph = __skb_header_pointer(skb, base_nhoff, sizeof(_iph), data,
+ hlen, &_iph);
+ if (!iph)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ udph = __skb_header_pointer(skb, *p_nhoff, sizeof(_udph), data,
+ hlen, &_udph);
+ if (!udph)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ rcu_read_lock();
+ /* Look up the UDPv6 socket and get the encap_type */
+ sk = ipv6_stub->udp6_lib_lookup(net,
+ &iph->saddr, udph->source,
+ &iph->daddr, udph->dest,
+ inet_iif(skb), inet_sdif(skb),
+ net->ipv4.udp_table, NULL);
+
+ if (!sk || !udp_sk(sk)->encap_type) {
+ rcu_read_unlock();
+ return FLOW_DISSECT_RET_OUT_GOOD;
+ }
+
+ encap_type = udp_sk(sk)->encap_type;
+ rcu_read_unlock();
+
+ break;
+ }
+#endif /* CONFIG_IPV6 */
+#endif /* CONFIG_INET */
+ default:
+ return FLOW_DISSECT_RET_OUT_GOOD;
+ }
+
+ nhoff = *p_nhoff + sizeof(_udph);
+ ret = FLOW_DISSECT_RET_OUT_GOOD;
+
+ switch (encap_type) {
+ default:
+ break;
+ }
+
+ switch (ret) {
+ case FLOW_DISSECT_RET_PROTO_AGAIN:
+ *p_ip_proto = 0;
+ fallthrough;
+ case FLOW_DISSECT_RET_IPPROTO_AGAIN:
+ *p_nhoff = nhoff;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
static void
__skb_flow_dissect_tcp(const struct sk_buff *skb,
struct flow_dissector *flow_dissector,
@@ -1046,6 +1175,7 @@ bool __skb_flow_dissect(const struct net *net,
int mpls_lse = 0;
int num_hdrs = 0;
u8 ip_proto = 0;
+ int base_nhoff;
bool ret;
if (!data) {
@@ -1168,6 +1298,7 @@ bool __skb_flow_dissect(const struct net *net,
proto_again:
fdret = FLOW_DISSECT_RET_CONTINUE;
+ base_nhoff = nhoff;
switch (proto) {
case htons(ETH_P_IP): {
@@ -1649,6 +1780,13 @@ bool __skb_flow_dissect(const struct net *net,
data, nhoff, hlen);
break;
+ case IPPROTO_UDP:
+ fdret = __skb_flow_dissect_udp(skb, net, flow_dissector,
+ target_container, data, &nhoff,
+ hlen, &proto, &ip_proto,
+ base_nhoff, flags, num_hdrs);
+ break;
+
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
__skb_flow_dissect_icmp(skb, flow_dissector, target_container,
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH net-next v4 05/13] flow_dissector: UDP encap infrastructure
2024-08-23 20:15 ` [PATCH net-next v4 05/13] flow_dissector: UDP encap infrastructure Tom Herbert
@ 2024-08-24 19:18 ` Simon Horman
0 siblings, 0 replies; 15+ messages in thread
From: Simon Horman @ 2024-08-24 19:18 UTC (permalink / raw)
To: Tom Herbert
Cc: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
On Fri, Aug 23, 2024 at 01:15:49PM -0700, Tom Herbert wrote:
> Add infrastructure for parsing into UDP encapsulations
>
> Add function __skb_flow_dissect_udp that is called for IPPROTO_UDP.
> The flag FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS enables parsing of UDP
> encapsulations. If the flag is set when parsing a UDP packet then
> a socket lookup is performed. The offset of the base network header,
> either an IPv4 or IPv6 header, is tracked and passed to
> __skb_flow_dissect_udp so that it can perform the socket lookup
>
> If a socket is found and it's for a UDP encapsulation (encap_type is
> set in the UDP socket) then a switch is performed on the encap_type
> value (cases are UDP_ENCAP_* values)
>
> An encapsulated packet in UDP can either be indicated by an
> EtherType or IP protocol. The processing for dissecting a UDP encap
> protocol returns a flow dissector return code. If
> FLOW_DISSECT_RET_PROTO_AGAIN or FLOW_DISSECT_RET_IPPROTO_AGAIN is
> returned then the corresponding encapsulated protocol is dissected.
> The nhoff is set to point to the header to process. In the case
> FLOW_DISSECT_RET_PROTO_AGAIN the EtherType protocol is returned and
> the IP protocol is set to zero. In the case of
> FLOW_DISSECT_RET_IPPROTO_AGAIN, the IP protocol is returned and
> the EtherType protocol is returned unchanged
>
> Signed-off-by: Tom Herbert <tom@herbertland.com>
...
> diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
...
> @@ -806,6 +807,134 @@ __skb_flow_dissect_batadv(const struct sk_buff *skb,
> return FLOW_DISSECT_RET_PROTO_AGAIN;
> }
>
> +static enum flow_dissect_ret
> +__skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
> + struct flow_dissector *flow_dissector,
> + void *target_container, const void *data,
> + int *p_nhoff, int hlen, __be16 *p_proto,
> + u8 *p_ip_proto, int base_nhoff, unsigned int flags,
> + unsigned int num_hdrs)
> +{
> + enum flow_dissect_ret ret;
> + struct udphdr _udph;
> + int nhoff;
> +
> + if (!(flags & FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS))
> + return FLOW_DISSECT_RET_OUT_GOOD;
> +
> + /* Check that the netns for the skb device is the same as the caller's,
> + * and only dissect UDP if we haven't yet encountered any encapsulation.
> + * The goal is to ensure that the socket lookup is being done in the
> + * right netns. Encapsulations may push packets into different name
> + * spaces, so this scheme is restricting UDP dissection to cases where
> + * they are in the same name spaces or at least the original name space.
> + * This should capture the majority of use cases for UDP encaps, and
> + * if we do encounter a UDP encapsulation within a different namespace
> + * then the only effect is we don't attempt UDP dissection
> + */
> + if (dev_net(skb->dev) != net || num_hdrs > 0)
> + return FLOW_DISSECT_RET_OUT_GOOD;
> +
> + switch (*p_proto) {
> +#ifdef CONFIG_INET
> + case htons(ETH_P_IP): {
> + const struct udphdr *udph;
> + const struct iphdr *iph;
> + struct iphdr _iph;
> + struct sock *sk;
> +
> + iph = __skb_header_pointer(skb, base_nhoff, sizeof(_iph), data,
> + hlen, &_iph);
> + if (!iph)
> + return FLOW_DISSECT_RET_OUT_BAD;
> +
> + udph = __skb_header_pointer(skb, *p_nhoff, sizeof(_udph), data,
> + hlen, &_udph);
> + if (!udph)
> + return FLOW_DISSECT_RET_OUT_BAD;
> +
> + rcu_read_lock();
> + /* Look up the UDPv4 socket and get the encap_type */
> + sk = __udp4_lib_lookup(net, iph->saddr, udph->source,
> + iph->daddr, udph->dest,
> + inet_iif(skb), inet_sdif(skb),
> + net->ipv4.udp_table, NULL);
> + if (!sk || !udp_sk(sk)->encap_type) {
> + rcu_read_unlock();
> + return FLOW_DISSECT_RET_OUT_GOOD;
> + }
> +
> + encap_type = udp_sk(sk)->encap_type;
Hi Tom,
I guess a local change went astray, or something like that,
because encap_type isn't declared in this scope.
> + rcu_read_unlock();
> +
> + break;
> + }
...
--
pw-bot: cr
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH net-next v4 06/13] flow_dissector: Parse vxlan in UDP
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (4 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 05/13] flow_dissector: UDP encap infrastructure Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 07/13] flow_dissector: Parse foo-over-udp (FOU) Tom Herbert
` (6 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Parse vxlan in a UDP encapsulation
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 47 +++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index f3134804a1db..49feea3fec56 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -13,7 +13,9 @@
#include <net/gre.h>
#include <net/pptp.h>
#include <net/tipc.h>
+#include <net/tun_proto.h>
#include <net/udp.h>
+#include <net/vxlan.h>
#include <linux/igmp.h>
#include <linux/icmp.h>
#include <linux/sctp.h>
@@ -756,6 +758,44 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
return FLOW_DISSECT_RET_PROTO_AGAIN;
}
+static enum flow_dissect_ret
+__skb_flow_dissect_vxlan(const struct sk_buff *skb,
+ struct flow_dissector *flow_dissector,
+ void *target_container, const void *data,
+ __be16 *p_proto, int *p_nhoff, int hlen,
+ unsigned int flags, bool is_gpe)
+{
+ struct vxlanhdr *hdr, _hdr;
+ __be16 protocol;
+
+ hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
+ &_hdr);
+ if (!hdr)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ /* VNI flag always required to be set */
+ if (!(hdr->vx_flags & VXLAN_HF_VNI))
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ if (is_gpe) {
+ struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)hdr;
+
+ if (!gpe->np_applied || gpe->version != 0 || gpe->oam_flag)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ protocol = tun_p_to_eth_p(gpe->next_protocol);
+ if (!protocol)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+ } else {
+ protocol = htons(ETH_P_TEB);
+ }
+
+ *p_nhoff += sizeof(struct vxlanhdr);
+ *p_proto = protocol;
+
+ return FLOW_DISSECT_RET_PROTO_AGAIN;
+}
+
/**
* __skb_flow_dissect_batadv() - dissect batman-adv header
* @skb: sk_buff to with the batman-adv header
@@ -917,6 +957,13 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
ret = FLOW_DISSECT_RET_OUT_GOOD;
switch (encap_type) {
+ case UDP_ENCAP_VXLAN:
+ case UDP_ENCAP_VXLAN_GPE:
+ ret = __skb_flow_dissect_vxlan(skb, flow_dissector,
+ target_container, data,
+ p_proto, &nhoff, hlen, flags,
+ encap_type == UDP_ENCAP_VXLAN_GPE);
+ break;
default:
break;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 07/13] flow_dissector: Parse foo-over-udp (FOU)
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (5 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 06/13] flow_dissector: Parse vxlan in UDP Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 08/13] flow_dissector: Parse ESP, L2TP, and SCTP in UDP Tom Herbert
` (5 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert, Willem de Bruijn
Parse FOU by getting the FOU protocol from the matching socket.
This includes moving "struct fou" and "fou_from_sock" to fou.h
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
include/net/fou.h | 16 ++++++++++++++++
net/core/flow_dissector.c | 12 ++++++++++++
net/ipv4/fou_core.c | 16 ----------------
3 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/include/net/fou.h b/include/net/fou.h
index 824eb4b231fd..8574767b91b6 100644
--- a/include/net/fou.h
+++ b/include/net/fou.h
@@ -17,6 +17,22 @@ int __fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
int __gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
u8 *protocol, __be16 *sport, int type);
+struct fou {
+ struct socket *sock;
+ u8 protocol;
+ u8 flags;
+ __be16 port;
+ u8 family;
+ u16 type;
+ struct list_head list;
+ struct rcu_head rcu;
+};
+
+static inline struct fou *fou_from_sock(struct sock *sk)
+{
+ return sk->sk_user_data;
+}
+
int register_fou_bpf(void);
#endif
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 49feea3fec56..e8760c1182b1 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -8,6 +8,7 @@
#include <linux/filter.h>
#include <net/dsa.h>
#include <net/dst_metadata.h>
+#include <net/fou.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/gre.h>
@@ -855,6 +856,7 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
u8 *p_ip_proto, int base_nhoff, unsigned int flags,
unsigned int num_hdrs)
{
+ __u8 encap_type, fou_protocol;
enum flow_dissect_ret ret;
struct udphdr _udph;
int nhoff;
@@ -905,6 +907,9 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
}
encap_type = udp_sk(sk)->encap_type;
+ if (encap_type == UDP_ENCAP_FOU)
+ fou_protocol = fou_from_sock(sk)->protocol;
+
rcu_read_unlock();
break;
@@ -943,6 +948,9 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
}
encap_type = udp_sk(sk)->encap_type;
+ if (encap_type == UDP_ENCAP_FOU)
+ fou_protocol = fou_from_sock(sk)->protocol;
+
rcu_read_unlock();
break;
@@ -957,6 +965,10 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
ret = FLOW_DISSECT_RET_OUT_GOOD;
switch (encap_type) {
+ case UDP_ENCAP_FOU:
+ *p_ip_proto = fou_protocol;
+ ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
+ break;
case UDP_ENCAP_VXLAN:
case UDP_ENCAP_VXLAN_GPE:
ret = __skb_flow_dissect_vxlan(skb, flow_dissector,
diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c
index 8241f762e45b..137eb80c56a2 100644
--- a/net/ipv4/fou_core.c
+++ b/net/ipv4/fou_core.c
@@ -21,17 +21,6 @@
#include "fou_nl.h"
-struct fou {
- struct socket *sock;
- u8 protocol;
- u8 flags;
- __be16 port;
- u8 family;
- u16 type;
- struct list_head list;
- struct rcu_head rcu;
-};
-
#define FOU_F_REMCSUM_NOPARTIAL BIT(0)
struct fou_cfg {
@@ -48,11 +37,6 @@ struct fou_net {
struct mutex fou_lock;
};
-static inline struct fou *fou_from_sock(struct sock *sk)
-{
- return sk->sk_user_data;
-}
-
static int fou_recv_pull(struct sk_buff *skb, struct fou *fou, size_t len)
{
/* Remove 'len' bytes from the packet (UDP header and
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 08/13] flow_dissector: Parse ESP, L2TP, and SCTP in UDP
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (6 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 07/13] flow_dissector: Parse foo-over-udp (FOU) Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 09/13] flow_dissector: Parse Geneve " Tom Herbert
` (4 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
These don't have an encapsulation header so it's fairly easy to
support them
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index e8760c1182b1..dd126e72f880 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -965,10 +965,23 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
ret = FLOW_DISSECT_RET_OUT_GOOD;
switch (encap_type) {
+ case UDP_ENCAP_ESPINUDP_NON_IKE:
+ case UDP_ENCAP_ESPINUDP:
+ *p_ip_proto = IPPROTO_ESP;
+ ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
+ break;
+ case UDP_ENCAP_L2TPINUDP:
+ *p_ip_proto = IPPROTO_L2TP;
+ ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
+ break;
case UDP_ENCAP_FOU:
*p_ip_proto = fou_protocol;
ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
break;
+ case UDP_ENCAP_SCTP:
+ *p_ip_proto = IPPROTO_SCTP;
+ ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
+ break;
case UDP_ENCAP_VXLAN:
case UDP_ENCAP_VXLAN_GPE:
ret = __skb_flow_dissect_vxlan(skb, flow_dissector,
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 09/13] flow_dissector: Parse Geneve in UDP
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (7 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 08/13] flow_dissector: Parse ESP, L2TP, and SCTP in UDP Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 10/13] flow_dissector: Parse GUE " Tom Herbert
` (3 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Parse Geneve in a UDP encapsulation
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index dd126e72f880..1deb9c3a75aa 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -11,6 +11,7 @@
#include <net/fou.h>
#include <net/ip.h>
#include <net/ipv6.h>
+#include <net/geneve.h>
#include <net/gre.h>
#include <net/pptp.h>
#include <net/tipc.h>
@@ -797,6 +798,29 @@ __skb_flow_dissect_vxlan(const struct sk_buff *skb,
return FLOW_DISSECT_RET_PROTO_AGAIN;
}
+static enum flow_dissect_ret
+__skb_flow_dissect_geneve(const struct sk_buff *skb,
+ struct flow_dissector *flow_dissector,
+ void *target_container, const void *data,
+ __be16 *p_proto, int *p_nhoff, int hlen,
+ unsigned int flags)
+{
+ struct genevehdr *hdr, _hdr;
+
+ hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
+ &_hdr);
+ if (!hdr)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ if (hdr->ver != 0)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ *p_proto = hdr->proto_type;
+ *p_nhoff += sizeof(struct genevehdr) + (hdr->opt_len * 4);
+
+ return FLOW_DISSECT_RET_PROTO_AGAIN;
+}
+
/**
* __skb_flow_dissect_batadv() - dissect batman-adv header
* @skb: sk_buff to with the batman-adv header
@@ -989,6 +1013,11 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
p_proto, &nhoff, hlen, flags,
encap_type == UDP_ENCAP_VXLAN_GPE);
break;
+ case UDP_ENCAP_GENEVE:
+ ret = __skb_flow_dissect_geneve(skb, flow_dissector,
+ target_container, data,
+ p_proto, &nhoff, hlen, flags);
+ break;
default:
break;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 10/13] flow_dissector: Parse GUE in UDP
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (8 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 09/13] flow_dissector: Parse Geneve " Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 11/13] gtp: Move gtp_parse_exthdrs into net/gtp.h Tom Herbert
` (2 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Parse both version 0 and 1 of GUE encapsulated in UDP. Add helper
function __skb_direct_ip_dissect to convert an IP header to
IPPROTO_IPIP or IPPROTO_IPV6 (by looking just at the version
number)
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 60 +++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 1deb9c3a75aa..b59a9e896a31 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -821,6 +821,61 @@ __skb_flow_dissect_geneve(const struct sk_buff *skb,
return FLOW_DISSECT_RET_PROTO_AGAIN;
}
+static __u8
+__skb_direct_ip_dissect(void *hdr)
+{
+ /* Direct encapsulation of IPv4 or IPv6 */
+
+ switch (((struct iphdr *)hdr)->version) {
+ case 4:
+ return IPPROTO_IPIP;
+ case 6:
+ return IPPROTO_IPV6;
+ default:
+ return 0;
+ }
+}
+
+static enum flow_dissect_ret
+__skb_flow_dissect_gue(const struct sk_buff *skb,
+ struct flow_dissector *flow_dissector,
+ void *target_container, const void *data,
+ __u8 *p_ip_proto, int *p_nhoff,
+ int hlen, unsigned int flags)
+{
+ struct guehdr *hdr, _hdr;
+ __u8 proto;
+
+ hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
+ &_hdr);
+ if (!hdr)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ switch (hdr->version) {
+ case 0:
+ if (unlikely(hdr->control))
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ *p_nhoff += sizeof(struct guehdr) + (hdr->hlen << 2);
+ *p_ip_proto = hdr->proto_ctype;
+
+ break;
+ case 1:
+ /* Direct encapsulation of IPv4 or IPv6 */
+
+ proto = __skb_direct_ip_dissect(hdr);
+ if (proto) {
+ *p_ip_proto = proto;
+ break;
+ }
+ fallthrough;
+ default:
+ return FLOW_DISSECT_RET_OUT_GOOD;
+ }
+
+ return FLOW_DISSECT_RET_IPPROTO_AGAIN;
+}
+
/**
* __skb_flow_dissect_batadv() - dissect batman-adv header
* @skb: sk_buff to with the batman-adv header
@@ -1002,6 +1057,11 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
*p_ip_proto = fou_protocol;
ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
break;
+ case UDP_ENCAP_GUE:
+ ret = __skb_flow_dissect_gue(skb, flow_dissector,
+ target_container, data,
+ p_ip_proto, p_nhoff, hlen, flags);
+ break;
case UDP_ENCAP_SCTP:
*p_ip_proto = IPPROTO_SCTP;
ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 11/13] gtp: Move gtp_parse_exthdrs into net/gtp.h
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (9 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 10/13] flow_dissector: Parse GUE " Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 12/13] flow_dissector: Parse gtp in UDP Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 13/13] flow_dissector: Add case in ipproto switch for NEXTHDR_NONE Tom Herbert
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
gtp_parse_exthdrs is a generic function, move into a header file
so we can call it outside of the GTP driver (specifically, we can
call it from flow dissector)
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
drivers/net/gtp.c | 37 -------------------------------------
include/net/gtp.h | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 37 deletions(-)
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 0696faf60013..259c7043d20c 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -742,43 +742,6 @@ static int gtp1u_handle_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
msg, 0, GTP_GENL_MCGRP, GFP_ATOMIC);
}
-static int gtp_parse_exthdrs(struct sk_buff *skb, unsigned int *hdrlen)
-{
- struct gtp_ext_hdr *gtp_exthdr, _gtp_exthdr;
- unsigned int offset = *hdrlen;
- __u8 *next_type, _next_type;
-
- /* From 29.060: "The Extension Header Length field specifies the length
- * of the particular Extension header in 4 octets units."
- *
- * This length field includes length field size itself (1 byte),
- * payload (variable length) and next type (1 byte). The extension
- * header is aligned to to 4 bytes.
- */
-
- do {
- gtp_exthdr = skb_header_pointer(skb, offset, sizeof(*gtp_exthdr),
- &_gtp_exthdr);
- if (!gtp_exthdr || !gtp_exthdr->len)
- return -1;
-
- offset += gtp_exthdr->len * 4;
-
- /* From 29.060: "If no such Header follows, then the value of
- * the Next Extension Header Type shall be 0."
- */
- next_type = skb_header_pointer(skb, offset - 1,
- sizeof(_next_type), &_next_type);
- if (!next_type)
- return -1;
-
- } while (*next_type != 0);
-
- *hdrlen = offset;
-
- return 0;
-}
-
static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
{
unsigned int hdrlen = sizeof(struct udphdr) +
diff --git a/include/net/gtp.h b/include/net/gtp.h
index c0253c8702d0..a513aa1c7394 100644
--- a/include/net/gtp.h
+++ b/include/net/gtp.h
@@ -83,4 +83,42 @@ struct gtp_ext_hdr {
__u8 data[];
};
+static inline int gtp_parse_exthdrs(const struct sk_buff *skb,
+ unsigned int *hdrlen)
+{
+ struct gtp_ext_hdr *gtp_exthdr, _gtp_exthdr;
+ unsigned int offset = *hdrlen;
+ __u8 *next_type, _next_type;
+
+ /* From 29.060: "The Extension Header Length field specifies the length
+ * of the particular Extension header in 4 octets units."
+ *
+ * This length field includes length field size itself (1 byte),
+ * payload (variable length) and next type (1 byte). The extension
+ * header is aligned to 4 bytes.
+ */
+
+ do {
+ gtp_exthdr = skb_header_pointer(skb, offset, sizeof(*gtp_exthdr),
+ &_gtp_exthdr);
+ if (!gtp_exthdr || !gtp_exthdr->len)
+ return -1;
+
+ offset += gtp_exthdr->len * 4;
+
+ /* From 29.060: "If no such Header follows, then the value of
+ * the Next Extension Header Type shall be 0."
+ */
+ next_type = skb_header_pointer(skb, offset - 1,
+ sizeof(_next_type), &_next_type);
+ if (!next_type)
+ return -1;
+
+ } while (*next_type != 0);
+
+ *hdrlen = offset;
+
+ return 0;
+}
+
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 12/13] flow_dissector: Parse gtp in UDP
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (10 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 11/13] gtp: Move gtp_parse_exthdrs into net/gtp.h Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
2024-08-23 20:15 ` [PATCH net-next v4 13/13] flow_dissector: Add case in ipproto switch for NEXTHDR_NONE Tom Herbert
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Parse both version 0 and 1. Call __skb_direct_ip_dissect to determine
IP version of the encapsulated packet
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 97 +++++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index b59a9e896a31..ae56de7d420a 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -9,6 +9,7 @@
#include <net/dsa.h>
#include <net/dst_metadata.h>
#include <net/fou.h>
+#include <net/gtp.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/geneve.h>
@@ -35,6 +36,7 @@
#include <net/pkt_cls.h>
#include <scsi/fc/fc_fcoe.h>
#include <uapi/linux/batadv_packet.h>
+#include <uapi/linux/gtp.h>
#include <linux/bpf.h>
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <net/netfilter/nf_conntrack_core.h>
@@ -876,6 +878,91 @@ __skb_flow_dissect_gue(const struct sk_buff *skb,
return FLOW_DISSECT_RET_IPPROTO_AGAIN;
}
+static enum flow_dissect_ret
+__skb_flow_dissect_gtp0(const struct sk_buff *skb,
+ struct flow_dissector *flow_dissector,
+ void *target_container, const void *data,
+ __u8 *p_ip_proto, int *p_nhoff, int hlen,
+ unsigned int flags)
+{
+ __u8 *ip_version, _ip_version, proto;
+ struct gtp0_header *hdr, _hdr;
+
+ hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
+ &_hdr);
+ if (!hdr)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ if ((hdr->flags >> 5) != GTP_V0)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ ip_version = skb_header_pointer(skb, *p_nhoff + sizeof(_hdr),
+ sizeof(*ip_version),
+ &_ip_version);
+ if (!ip_version)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ proto = __skb_direct_ip_dissect(ip_version);
+ if (!proto)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ *p_ip_proto = proto;
+ *p_nhoff += sizeof(struct gtp0_header);
+
+ return FLOW_DISSECT_RET_IPPROTO_AGAIN;
+}
+
+static enum flow_dissect_ret
+__skb_flow_dissect_gtp1u(const struct sk_buff *skb,
+ struct flow_dissector *flow_dissector,
+ void *target_container, const void *data,
+ __u8 *p_ip_proto, int *p_nhoff, int hlen,
+ unsigned int flags)
+{
+ __u8 *ip_version, _ip_version, proto;
+ struct gtp1_header *hdr, _hdr;
+ int hdrlen = sizeof(_hdr);
+
+ hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
+ &_hdr);
+ if (!hdr)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ if ((hdr->flags >> 5) != GTP_V1)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ if (hdr->type != GTP_TPDU)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ if (hdr->flags & GTP1_F_MASK)
+ hdrlen += 4;
+
+ /* Skip over GTP extension headers if they are present */
+ if (hdr->flags & GTP1_F_EXTHDR &&
+ gtp_parse_exthdrs(skb, &hdrlen) < 0)
+ return FLOW_DISSECT_RET_OUT_BAD;
+
+ /* Exit if either NPDU or SEQ glags are set */
+ if (hdr->flags & GTP1_F_NPDU ||
+ hdr->flags & GTP1_F_SEQ)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ ip_version = skb_header_pointer(skb, *p_nhoff + hdrlen,
+ sizeof(*ip_version),
+ &_ip_version);
+ if (!ip_version)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ proto = __skb_direct_ip_dissect(ip_version);
+ if (!proto)
+ return FLOW_DISSECT_RET_OUT_GOOD;
+
+ *p_ip_proto = proto;
+ *p_nhoff += hdrlen;
+
+ return FLOW_DISSECT_RET_IPPROTO_AGAIN;
+}
+
/**
* __skb_flow_dissect_batadv() - dissect batman-adv header
* @skb: sk_buff to with the batman-adv header
@@ -1053,6 +1140,16 @@ __skb_flow_dissect_udp(const struct sk_buff *skb, const struct net *net,
*p_ip_proto = IPPROTO_L2TP;
ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
break;
+ case UDP_ENCAP_GTP0:
+ ret = __skb_flow_dissect_gtp0(skb, flow_dissector,
+ target_container, data,
+ p_ip_proto, &nhoff, hlen, flags);
+ break;
+ case UDP_ENCAP_GTP1U:
+ ret = __skb_flow_dissect_gtp1u(skb, flow_dissector,
+ target_container, data,
+ p_ip_proto, &nhoff, hlen, flags);
+ break;
case UDP_ENCAP_FOU:
*p_ip_proto = fou_protocol;
ret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH net-next v4 13/13] flow_dissector: Add case in ipproto switch for NEXTHDR_NONE
2024-08-23 20:15 [PATCH net-next v4 00/13] flow_dissector: Dissect UDP encapsulation protocols Tom Herbert
` (11 preceding siblings ...)
2024-08-23 20:15 ` [PATCH net-next v4 12/13] flow_dissector: Parse gtp in UDP Tom Herbert
@ 2024-08-23 20:15 ` Tom Herbert
12 siblings, 0 replies; 15+ messages in thread
From: Tom Herbert @ 2024-08-23 20:15 UTC (permalink / raw)
To: davem, kuba, edumazet, netdev, felipe, willemdebruijn.kernel,
pablo, laforge, xeb
Cc: Tom Herbert
Protocol number 59 (no-next-header) means nothing follows the
IP header, break out of the flow dissector loop on
FLOW_DISSECT_RET_OUT_GOOD when encountered in a packet
Signed-off-by: Tom Herbert <tom@herbertland.com>
---
net/core/flow_dissector.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index ae56de7d420a..6f50cbb39539 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -1993,6 +1993,9 @@ bool __skb_flow_dissect(const struct net *net,
fdret = FLOW_DISSECT_RET_OUT_GOOD;
break;
}
+ case NEXTHDR_NONE:
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
+ break;
case IPPROTO_IPIP:
if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
fdret = FLOW_DISSECT_RET_OUT_GOOD;
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread