Fri, Dec 02, 2016 at 09:31:41PM CET, simon.hor...@netronome.com wrote: >Allow dissection of ICMP(V6) type and code. This re-uses transport layer >port dissection code as although ICMP is not a transport protocol and their >type and code are not ports this allows sharing of both code and storage. > >Signed-off-by: Simon Horman <simon.hor...@netronome.com> >--- > drivers/net/bonding/bond_main.c | 6 +++-- > include/linux/skbuff.h | 5 +++++ > include/net/flow_dissector.h | 50 ++++++++++++++++++++++++++++++++++++++--- > net/core/flow_dissector.c | 34 +++++++++++++++++++++++++--- > net/sched/cls_flow.c | 4 ++-- > 5 files changed, 89 insertions(+), 10 deletions(-) > >diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c >index 8029dd4912b6..a6f75cfb2bf7 100644 >--- a/drivers/net/bonding/bond_main.c >+++ b/drivers/net/bonding/bond_main.c >@@ -3181,7 +3181,8 @@ static bool bond_flow_dissect(struct bonding *bond, >struct sk_buff *skb, > } else { > return false; > } >- if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0) >+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && >+ proto >= 0 && !skb_flow_is_icmp_any(skb, proto)) > fk->ports.ports = skb_flow_get_ports(skb, noff, proto); > > return true; >@@ -3209,7 +3210,8 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff >*skb) > return bond_eth_hash(skb); > > if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 || >- bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) >+ bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23 || >+ flow_keys_are_icmp_any(&flow)) > hash = bond_eth_hash(skb); > else > hash = (__force u32)flow.ports.ports; >diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h >index 9c535fbccf2c..44a8f69a9198 100644 >--- a/include/linux/skbuff.h >+++ b/include/linux/skbuff.h >@@ -1094,6 +1094,11 @@ u32 __skb_get_poff(const struct sk_buff *skb, void >*data, > __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, > void *data, int hlen_proto); > >+static inline bool skb_flow_is_icmp_any(const struct sk_buff *skb, u8 >ip_proto) >+{ >+ return flow_protos_are_icmp_any(skb->protocol, ip_proto); >+} >+ > static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, > int thoff, u8 ip_proto) > { >diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h >index c4f31666afd2..5540dfa18872 100644 >--- a/include/net/flow_dissector.h >+++ b/include/net/flow_dissector.h >@@ -2,6 +2,7 @@ > #define _NET_FLOW_DISSECTOR_H > > #include <linux/types.h> >+#include <linux/in.h> > #include <linux/in6.h> > #include <uapi/linux/if_ether.h> > >@@ -89,10 +90,15 @@ struct flow_dissector_key_addrs { > }; > > /** >- * flow_dissector_key_tp_ports: >- * @ports: port numbers of Transport header >+ * flow_dissector_key_ports: >+ * @ports: port numbers of Transport header or >+ * type and code of ICMP header >+ * ports: source (high) and destination (low) port numbers > * src: source port number > * dst: destination port number >+ * icmp: ICMP type (high) and code (low) >+ * type: ICMP type >+ * type: ICMP code > */ > struct flow_dissector_key_ports { > union { >@@ -101,6 +107,11 @@ struct flow_dissector_key_ports { > __be16 src; > __be16 dst; > }; >+ __be16 icmp; >+ struct { >+ u8 type; >+ u8 code; >+ };
Digging into this a bit more. I think it would be much nice not to mix up l4 ports and icmp stuff. How about to have FLOW_DISSECTOR_KEY_ICMP and struct flow_dissector_key_icmp { u8 type; u8 code; }; The you can make this structure and struct flow_dissector_key_ports into an union in struct flow_keys. Looks much cleaner to me. > }; > }; > >@@ -188,9 +199,42 @@ struct flow_keys_digest { > void make_flow_keys_digest(struct flow_keys_digest *digest, > const struct flow_keys *flow); > >+static inline bool flow_protos_are_icmpv4(__be16 n_proto, u8 ip_proto) >+{ >+ return n_proto == htons(ETH_P_IP) && ip_proto == IPPROTO_ICMP; >+} >+ >+static inline bool flow_protos_are_icmpv6(__be16 n_proto, u8 ip_proto) >+{ >+ return n_proto == htons(ETH_P_IPV6) && ip_proto == IPPROTO_ICMPV6; >+} >+ >+static inline bool flow_protos_are_icmp_any(__be16 n_proto, u8 ip_proto) >+{ >+ return flow_protos_are_icmpv4(n_proto, ip_proto) || >+ flow_protos_are_icmpv6(n_proto, ip_proto); >+} >+ >+static inline bool flow_basic_key_is_icmpv4(const struct >flow_dissector_key_basic *basic) >+{ >+ return flow_protos_are_icmpv4(basic->n_proto, basic->ip_proto); >+} >+ >+static inline bool flow_basic_key_is_icmpv6(const struct >flow_dissector_key_basic *basic) >+{ >+ return flow_protos_are_icmpv6(basic->n_proto, basic->ip_proto); >+} >+ >+static inline bool flow_keys_are_icmp_any(const struct flow_keys *keys) >+{ >+ return flow_protos_are_icmp_any(keys->basic.n_proto, >+ keys->basic.ip_proto); >+} >+ > static inline bool flow_keys_have_l4(const struct flow_keys *keys) > { >- return (keys->ports.ports || keys->tags.flow_label); >+ return (!flow_keys_are_icmp_any(keys) && keys->ports.ports) || >+ keys->tags.flow_label; > } > > u32 flow_hash_from_keys(struct flow_keys *keys); >diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c >index 1eb6f949e5b2..0584b4bb4390 100644 >--- a/net/core/flow_dissector.c >+++ b/net/core/flow_dissector.c >@@ -58,6 +58,28 @@ void skb_flow_dissector_init(struct flow_dissector >*flow_dissector, > EXPORT_SYMBOL(skb_flow_dissector_init); > > /** >+ * skb_flow_get_be16 - extract be16 entity >+ * @skb: sk_buff to extract from >+ * @poff: offset to extract at >+ * @data: raw buffer pointer to the packet >+ * @hlen: packet header length >+ * >+ * The function will try to retrieve a be32 entity at >+ * offset poff >+ */ >+__be16 skb_flow_get_be16(const struct sk_buff *skb, int poff, void *data, >+ int hlen) >+{ >+ __be16 *u, _u; >+ >+ u = __skb_header_pointer(skb, poff, sizeof(_u), data, hlen, &_u); >+ if (u) >+ return *u; >+ >+ return 0; >+} >+ >+/** > * __skb_flow_get_ports - extract the upper layer ports and return them > * @skb: sk_buff to extract the ports from > * @thoff: transport header offset >@@ -542,8 +564,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, > key_ports = skb_flow_dissector_target(flow_dissector, > FLOW_DISSECTOR_KEY_PORTS, > target_container); >- key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, >- data, hlen); >+ if (flow_protos_are_icmp_any(proto, ip_proto)) >+ key_ports->icmp = skb_flow_get_be16(skb, nhoff, data, >+ hlen); >+ else >+ key_ports->ports = __skb_flow_get_ports(skb, nhoff, >+ ip_proto, data, >+ hlen); > } > > out_good: >@@ -718,7 +745,8 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, > > data->n_proto = flow->basic.n_proto; > data->ip_proto = flow->basic.ip_proto; >- data->ports = flow->ports.ports; >+ if (flow_keys_have_l4(flow)) >+ data->ports = flow->ports.ports; > data->src = flow->addrs.v4addrs.src; > data->dst = flow->addrs.v4addrs.dst; > } >diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c >index e39672394c7b..a1a7ae71aa62 100644 >--- a/net/sched/cls_flow.c >+++ b/net/sched/cls_flow.c >@@ -96,7 +96,7 @@ static u32 flow_get_proto(const struct sk_buff *skb, > static u32 flow_get_proto_src(const struct sk_buff *skb, > const struct flow_keys *flow) > { >- if (flow->ports.ports) >+ if (!flow_keys_are_icmp_any(flow) && flow->ports.ports) > return ntohs(flow->ports.src); > > return addr_fold(skb->sk); >@@ -105,7 +105,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb, > static u32 flow_get_proto_dst(const struct sk_buff *skb, > const struct flow_keys *flow) > { >- if (flow->ports.ports) >+ if (!flow_keys_are_icmp_any(flow) && flow->ports.ports) > return ntohs(flow->ports.dst); > > return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); >-- >2.7.0.rc3.207.g0ac5344 >