Message ID | 20240731172332.683815-7-tom@herbertland.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | flow_dissector: Dissect UDP encapsulation protocols | expand |
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> > --- > include/net/flow_dissector.h | 1 + > net/core/flow_dissector.c | 114 +++++++++++++++++++++++++++++++++++ > 2 files changed, 115 insertions(+) > > +static enum flow_dissect_ret > +__skb_flow_dissect_udp(const struct sk_buff *skb, 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 bpoff, unsigned int flags) > +{ > + enum flow_dissect_ret ret; > + const struct udphdr *udph; > + struct udphdr _udph; > + struct sock *sk; > + __u8 encap_type; > + int nhoff; > + > + if (!(flags & FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS)) > + return FLOW_DISSECT_RET_OUT_GOOD; > + > + switch (*p_proto) { > + case htons(ETH_P_IP): { > + const struct iphdr *iph; > + struct iphdr _iph; > + > + iph = __skb_header_pointer(skb, bpoff, 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; > + } > + case htons(ETH_P_IPV6): { > + const struct ipv6hdr *iph; > + struct ipv6hdr _iph; > + > + iph = __skb_header_pointer(skb, bpoff, 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 = __udp6_lib_lookup(net, &iph->saddr, udph->source, > + &iph->daddr, udph->dest, > + inet_iif(skb), inet_sdif(skb), > + net->ipv4.udp_table, NULL); #if IS_ENABLED(CONFIG_IPV6) similar to net/ipv4/udp_diag.c > + 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; > + } > + default: > + return FLOW_DISSECT_RET_OUT_GOOD; > + } > + > static void > __skb_flow_dissect_tcp(const struct sk_buff *skb, > struct flow_dissector *flow_dissector, > @@ -1046,6 +1151,7 @@ bool __skb_flow_dissect(struct net *net, > int mpls_lse = 0; > int num_hdrs = 0; > u8 ip_proto = 0; > + int bpoff; What does bp mean here? It points to the network header off, but nhoff does not mean network header, but next header. And now points to the udp header. Just not sure what bp is meant to convey.
Hi Tom,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
[also build test ERROR on net/main linus/master v6.11-rc1 next-20240802]
[cannot apply to horms-ipvs/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Tom-Herbert/skbuff-Unconstantify-struct-net-argument-in-flowdis-functions/20240802-084418
base: net-next/main
patch link: https://lore.kernel.org/r/20240731172332.683815-7-tom%40herbertland.com
patch subject: [PATCH 06/12] flow_dissector: UDP encap infrastructure
config: arc-vdk_hs38_defconfig (https://download.01.org/0day-ci/archive/20240802/202408022051.e0Dqh7P1-lkp@intel.com/config)
compiler: arc-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240802/202408022051.e0Dqh7P1-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408022051.e0Dqh7P1-lkp@intel.com/
All errors (new ones prefixed by >>):
arc-elf-ld: net/core/flow_dissector.o: in function `__skb_flow_dissect_udp.isra.0':
flow_dissector.c:(.text+0x81c): undefined reference to `__udp6_lib_lookup'
>> arc-elf-ld: flow_dissector.c:(.text+0x81c): undefined reference to `__udp6_lib_lookup'
Hi Tom, kernel test robot noticed the following build errors: [auto build test ERROR on net-next/main] [also build test ERROR on net/main linus/master v6.11-rc1 next-20240802] [cannot apply to horms-ipvs/master] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Tom-Herbert/skbuff-Unconstantify-struct-net-argument-in-flowdis-functions/20240802-084418 base: net-next/main patch link: https://lore.kernel.org/r/20240731172332.683815-7-tom%40herbertland.com patch subject: [PATCH 06/12] flow_dissector: UDP encap infrastructure config: um-defconfig (https://download.01.org/0day-ci/archive/20240802/202408022046.h8kMQ01e-lkp@intel.com/config) compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 430b90f04533b099d788db2668176038be38c53b) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240802/202408022046.h8kMQ01e-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202408022046.h8kMQ01e-lkp@intel.com/ All errors (new ones prefixed by >>): /usr/bin/ld: warning: .tmp_vmlinux1 has a LOAD segment with RWX permissions /usr/bin/ld: net/core/flow_dissector.o: in function `__skb_flow_dissect': >> net/core/flow_dissector.c:874:(.ltext+0x1ff9): undefined reference to `__udp6_lib_lookup' clang: error: linker command failed with exit code 1 (use -v to see invocation) vim +874 net/core/flow_dissector.c 809 810 static enum flow_dissect_ret 811 __skb_flow_dissect_udp(const struct sk_buff *skb, struct net *net, 812 struct flow_dissector *flow_dissector, 813 void *target_container, const void *data, 814 int *p_nhoff, int hlen, __be16 *p_proto, 815 u8 *p_ip_proto, int bpoff, unsigned int flags) 816 { 817 enum flow_dissect_ret ret; 818 const struct udphdr *udph; 819 struct udphdr _udph; 820 struct sock *sk; 821 __u8 encap_type; 822 int nhoff; 823 824 if (!(flags & FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS)) 825 return FLOW_DISSECT_RET_OUT_GOOD; 826 827 switch (*p_proto) { 828 case htons(ETH_P_IP): { 829 const struct iphdr *iph; 830 struct iphdr _iph; 831 832 iph = __skb_header_pointer(skb, bpoff, sizeof(_iph), data, 833 hlen, &_iph); 834 if (!iph) 835 return FLOW_DISSECT_RET_OUT_BAD; 836 837 udph = __skb_header_pointer(skb, *p_nhoff, sizeof(_udph), data, 838 hlen, &_udph); 839 if (!udph) 840 return FLOW_DISSECT_RET_OUT_BAD; 841 842 rcu_read_lock(); 843 /* Look up the UDPv4 socket and get the encap_type */ 844 sk = __udp4_lib_lookup(net, iph->saddr, udph->source, 845 iph->daddr, udph->dest, 846 inet_iif(skb), inet_sdif(skb), 847 net->ipv4.udp_table, NULL); 848 if (!sk || !udp_sk(sk)->encap_type) { 849 rcu_read_unlock(); 850 return FLOW_DISSECT_RET_OUT_GOOD; 851 } 852 853 encap_type = udp_sk(sk)->encap_type; 854 rcu_read_unlock(); 855 856 break; 857 } 858 case htons(ETH_P_IPV6): { 859 const struct ipv6hdr *iph; 860 struct ipv6hdr _iph; 861 862 iph = __skb_header_pointer(skb, bpoff, sizeof(_iph), data, 863 hlen, &_iph); 864 if (!iph) 865 return FLOW_DISSECT_RET_OUT_BAD; 866 867 udph = __skb_header_pointer(skb, *p_nhoff, sizeof(_udph), data, 868 hlen, &_udph); 869 if (!udph) 870 return FLOW_DISSECT_RET_OUT_BAD; 871 872 rcu_read_lock(); 873 /* Look up the UDPv6 socket and get the encap_type */ > 874 sk = __udp6_lib_lookup(net, &iph->saddr, udph->source, 875 &iph->daddr, udph->dest, 876 inet_iif(skb), inet_sdif(skb), 877 net->ipv4.udp_table, NULL); 878 if (!sk || !udp_sk(sk)->encap_type) { 879 rcu_read_unlock(); 880 return FLOW_DISSECT_RET_OUT_GOOD; 881 } 882 883 encap_type = udp_sk(sk)->encap_type; 884 rcu_read_unlock(); 885 886 break; 887 } 888 default: 889 return FLOW_DISSECT_RET_OUT_GOOD; 890 } 891 892 nhoff = *p_nhoff + sizeof(struct udphdr); 893 ret = FLOW_DISSECT_RET_OUT_GOOD; 894 895 switch (encap_type) { 896 default: 897 break; 898 } 899 900 switch (ret) { 901 case FLOW_DISSECT_RET_PROTO_AGAIN: 902 *p_ip_proto = 0; 903 fallthrough; 904 case FLOW_DISSECT_RET_IPPROTO_AGAIN: 905 *p_nhoff = nhoff; 906 break; 907 default: 908 break; 909 } 910 911 return ret; 912 } 913
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 416f889c623c..006db3b893d0 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,110 @@ __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, 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 bpoff, unsigned int flags) +{ + enum flow_dissect_ret ret; + const struct udphdr *udph; + struct udphdr _udph; + struct sock *sk; + __u8 encap_type; + int nhoff; + + if (!(flags & FLOW_DISSECTOR_F_PARSE_UDP_ENCAPS)) + return FLOW_DISSECT_RET_OUT_GOOD; + + switch (*p_proto) { + case htons(ETH_P_IP): { + const struct iphdr *iph; + struct iphdr _iph; + + iph = __skb_header_pointer(skb, bpoff, 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; + } + case htons(ETH_P_IPV6): { + const struct ipv6hdr *iph; + struct ipv6hdr _iph; + + iph = __skb_header_pointer(skb, bpoff, 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 = __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; + } + default: + return FLOW_DISSECT_RET_OUT_GOOD; + } + + nhoff = *p_nhoff + sizeof(struct udphdr); + 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 +1151,7 @@ bool __skb_flow_dissect(struct net *net, int mpls_lse = 0; int num_hdrs = 0; u8 ip_proto = 0; + int bpoff; bool ret; if (!data) { @@ -1168,6 +1274,7 @@ bool __skb_flow_dissect(struct net *net, proto_again: fdret = FLOW_DISSECT_RET_CONTINUE; + bpoff = nhoff; switch (proto) { case htons(ETH_P_IP): { @@ -1635,6 +1742,13 @@ bool __skb_flow_dissect(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, + bpoff, flags); + break; + case IPPROTO_ICMP: case IPPROTO_ICMPV6: __skb_flow_dissect_icmp(skb, flow_dissector, target_container,
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 | 114 +++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+)