mbox series

[00/12] flow_dissector: Dissect UDP encapsulation protocols

Message ID 20240731172332.683815-1-tom@herbertland.com (mailing list archive)
Headers show
Series flow_dissector: Dissect UDP encapsulation protocols | expand

Message

Tom Herbert July 31, 2024, 5:23 p.m. UTC
Add support in flow_dissector for dissecting into UDP
encapsulations like VXLAN. __skb_flow_dissect_udp 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)

Changes in the patch set:

- Unconstantify struct net argument in flowdis functions so we can call
  UDP socket lookup functions
- Dissect ETH_P_TEB in main flow dissector loop, move ETH_P_TEB check
  out of __skb_flow_dissect_gre and process it in main loop
- Add UDP_ENCAP constants for tipc, fou, gue, sctp, rxe, pfcp,
  wireguard, bareudp, vxlan, vxlan_gpe, geneve, and amt
- For the various UDP encapsulation protocols, Instead of just setting
  UDP tunnel encap type to 1, set it to the corresponding UDP_ENCAP
  constant. This allows identify the encapsulation protocol for a
  UDP socket by the encap_type
- Add function __skb_flow_dissect_udp in flow_dissector and call it for
  UDP packets. If a UDP encapsulation is present then the function
  returns either FLOW_DISSECT_RET_PROTO_AGAIN or
  FLOW_DISSECT_RET_IPPROTO_AGAIN
- Add flag FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS that indicates UDP
  encapsulations should be dissected
- Add __skb_flow_dissect_vxlan which is called when encap_type is
  UDP_ENCAP_VXLAN or UDP_ENCAP_VXLAN_GPE. Dissect VXLAN and return
  a next protocol and offset
- Add __skb_flow_dissect_fou which is called when encap_type is
  UDP_ENCAP_FOU. Dissect FOU and return a next protocol and offset
- Add support for ESP, L2TP, and SCTP in UDP in __skb_flow_dissect_udp.
  All we need to do is return FLOW_DISSECT_RET_IPPROTO_AGAIN and the
  corresponding IP protocol number
- Add __skb_flow_dissect_geneve which is called when encap_type is
  UDP_ENCAP_GENEVE. Dissect geneve and return a next protocol and offset
- Add __skb_flow_dissect_gue which is called when encap_type is
  UDP_ENCAP_GUE. Dissect gue and return a next protocol and offset
- Add __skb_flow_dissect_gtp which is called when encap_type is
  UDP_ENCAP_GTP. Dissect gtp and return a next protocol and offset

Tested: Verified fou, gue, vxlan, and geneve are properly dissected for
IPv4 and IPv6 cases. This includes testing ETH_P_TEB case

Tom Herbert (12):
  skbuff: Unconstantify struct net argument in flowdis functions
  flow_dissector: Parse ETH_P_TEB
  flow_dissector: Move ETH_P_TEB out of GRE
  udp_encaps: Add new UDP_ENCAP constants
  udp_encaps: Set proper UDP_ENCAP types in tunnel setup
  flow_dissector: UDP encap infrastructure
  flow_dissector: Parse vxlan in UDP
  flow_dissector: Parse foo-over-udp (FOU)
  flow_dissector: Parse ESP, L2TP, and SCTP in UDP
  flow_dissector: Parse Geneve in UDP
  flow_dissector: Parse GUE in UDP
  flow_dissector: Parse gtp in UDP

 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 +-
 include/linux/skbuff.h              |  10 +-
 include/net/flow_dissector.h        |   1 +
 include/net/fou.h                   |  16 +
 include/uapi/linux/udp.h            |  13 +
 net/core/flow_dissector.c           | 434 ++++++++++++++++++++++++++--
 net/ipv4/fou_core.c                 |  19 +-
 net/sctp/protocol.c                 |   2 +-
 net/tipc/udp_media.c                |   2 +-
 15 files changed, 452 insertions(+), 60 deletions(-)

Comments

Willem de Bruijn Aug. 1, 2024, 1:20 p.m. UTC | #1
Tom Herbert wrote:
> Add support in flow_dissector for dissecting into UDP
> encapsulations like VXLAN. __skb_flow_dissect_udp 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)

The main concern with the flow dissector is that its execution depends
on untrusted packets.

For this reason we added the BPF dissector for new protocols. What is
the reason to prefer adding more C code?

And somewhat academic, but: would it be different if the BPF would
ship with the kernel and autoload at boot, just like C modules?

A second concern is changing the defaults. I have not looked at this
closely, but if dissection today stops at the outer UDP header for
skb_get_hash, then we don't want to accidentally change this behavior.
Or if not accidental, call it out explicitly.

> 
> Tested: Verified fou, gue, vxlan, and geneve are properly dissected for
> IPv4 and IPv6 cases. This includes testing ETH_P_TEB case

Manually?
Jakub Kicinski Aug. 1, 2024, 4:16 p.m. UTC | #2
On Wed, 31 Jul 2024 10:23:20 -0700 Tom Herbert wrote:
> Add support in flow_dissector for dissecting into UDP
> encapsulations like VXLAN. __skb_flow_dissect_udp 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)

Appears to break build for allmodconfig
Tom Herbert Aug. 14, 2024, 8:28 p.m. UTC | #3
On Thu, Aug 1, 2024 at 6:20 AM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> Tom Herbert wrote:
> > Add support in flow_dissector for dissecting into UDP
> > encapsulations like VXLAN. __skb_flow_dissect_udp 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)
>
> The main concern with the flow dissector is that its execution depends
> on untrusted packets.
>
> For this reason we added the BPF dissector for new protocols. What is
> the reason to prefer adding more C code?
>
> And somewhat academic, but: would it be different if the BPF would
> ship with the kernel and autoload at boot, just like C modules?

Hi Willem,

I agree with that, and believe the ultimate goal is to replace flow
dissector C code with eBPF which I still intend to work on that, but
right now I'm hoping to get support as part of obsoleting protocol
specific checksum offload on receive. We can use flow dissector to
identify the checksum in a packet marked checksum-unnecessary by a
legacy device for doing conversion to checksum-complete. This handles
the case where the device reports a valid L4 checksum in a UDP
encapsulation and the outer UDP checksum is zero.

>
> A second concern is changing the defaults. I have not looked at this
> closely, but if dissection today stops at the outer UDP header for
> skb_get_hash, then we don't want to accidentally change this behavior.
> Or if not accidental, call it out explicitly.

No defaults are being changed. Flow dissector flag
FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS needs to be set in the call to flow
dissector. In this patch set it's not being used, but as I mentioned
it will be used in subsequent patch sets for obsoleting
CHECKSUM_UNNECESSARY.

For other use cases, the flag can be optionally set. TC-flower for
instance could use this for VXLAN and Geneve parsing.

>
> >
> > Tested: Verified fou, gue, vxlan, and geneve are properly dissected for
> > IPv4 and IPv6 cases. This includes testing ETH_P_TEB case
>
> Manually?

Yes for the time being.

Tom
Tom Herbert Aug. 14, 2024, 8:37 p.m. UTC | #4
On Wed, Aug 14, 2024 at 1:28 PM Tom Herbert <tom@herbertland.com> wrote:
>
> On Thu, Aug 1, 2024 at 6:20 AM Willem de Bruijn
> <willemdebruijn.kernel@gmail.com> wrote:
> >
> > Tom Herbert wrote:
> > > Add support in flow_dissector for dissecting into UDP
> > > encapsulations like VXLAN. __skb_flow_dissect_udp 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)
> >
> > The main concern with the flow dissector is that its execution depends
> > on untrusted packets.
> >
> > For this reason we added the BPF dissector for new protocols. What is
> > the reason to prefer adding more C code?
> >
> > And somewhat academic, but: would it be different if the BPF would
> > ship with the kernel and autoload at boot, just like C modules?
>
> Hi Willem,
>
> I agree with that, and believe the ultimate goal is to replace flow
> dissector C code with eBPF which I still intend to work on that, but
> right now I'm hoping to get support as part of obsoleting protocol
> specific checksum offload on receive. We can use flow dissector to
> identify the checksum in a packet marked checksum-unnecessary by a
> legacy device for doing conversion to checksum-complete. This handles
> the case where the device reports a valid L4 checksum in a UDP
> encapsulation and the outer UDP checksum is zero.

Also, there's another wrinkle with doing this in eBPF. UDP
encapsulations are identified by port number, not a protocol number,
so we can't hardcode port numbers into eBPF like we can other protocol
constants. We'd probably need to hook into setup_udp_tunnel_sock
somehow.

Tom

>
> >
> > A second concern is changing the defaults. I have not looked at this
> > closely, but if dissection today stops at the outer UDP header for
> > skb_get_hash, then we don't want to accidentally change this behavior.
> > Or if not accidental, call it out explicitly.
>
> No defaults are being changed. Flow dissector flag
> FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS needs to be set in the call to flow
> dissector. In this patch set it's not being used, but as I mentioned
> it will be used in subsequent patch sets for obsoleting
> CHECKSUM_UNNECESSARY.
>
> For other use cases, the flag can be optionally set. TC-flower for
> instance could use this for VXLAN and Geneve parsing.
>
> >
> > >
> > > Tested: Verified fou, gue, vxlan, and geneve are properly dissected for
> > > IPv4 and IPv6 cases. This includes testing ETH_P_TEB case
> >
> > Manually?
>
> Yes for the time being.
>
> Tom