Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41ecc3d3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'flow-dissector-features'



Tom Herbert says:

====================
flow_dissector: Paramterize dissection and other features

This patch set adds some new capabilities to flow_dissector:

- Add flags to flow dissector functions to control dissection
  - Flag to stop dissection when L3 header is seen (don't
    dissect L4)
  - Flag to stop dissection when encapsulation is detected
  - Flag to parse first fragment of fragmented packet. This
    may provide L4 ports
- Added new reporting in key_control
  - Packet is a fragment
  - Packet is a first fragment
  - Packet has encapsulation

Also:
  - Make __skb_set_sw_hash a general function
  - Create functions to get a flow hash based on flowi4 or flowi6
    structures without an reference to an skbuff
  - Ignore flow dissector return value from ___skb_get_hash. Just
    use whatever key fields are found to make a hash

Tested:

Ran 200 netperf TCP_RR instances for IPv6 and IPv4. Did not see any
regression. Ran UDP_RR with 10000 byte request and response size
for IPv4 and IPv6, no regression observed however I did see better
performance with IPv6 flow labels due to use of flow labels for L4
hash.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d3d11fe0 6db61d79
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3095,7 +3095,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
	int noff, proto = -1;

	if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23)
		return skb_flow_dissect_flow_keys(skb, fk);
		return skb_flow_dissect_flow_keys(skb, fk, 0);

	fk->ports.ports = 0;
	noff = skb_network_offset(skb);
+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
	int res, i;

	enic = netdev_priv(dev);
	res = skb_flow_dissect_flow_keys(skb, &keys);
	res = skb_flow_dissect_flow_keys(skb, &keys, 0);
	if (!res || keys.basic.n_proto != htons(ETH_P_IP) ||
	    (keys.basic.ip_proto != IPPROTO_TCP &&
	     keys.basic.ip_proto != IPPROTO_UDP))
+1 −1
Original line number Diff line number Diff line
@@ -239,7 +239,7 @@ static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
	struct flow_keys flow;
	int data_len;

	if (!skb_flow_dissect_flow_keys(skb, &flow) ||
	if (!skb_flow_dissect_flow_keys(skb, &flow, 0) ||
	    !(flow.basic.n_proto == htons(ETH_P_IP) ||
	      flow.basic.n_proto == htons(ETH_P_IPV6)))
		return false;
+92 −21
Original line number Diff line number Diff line
@@ -937,14 +937,90 @@ enum pkt_hash_types {
	PKT_HASH_TYPE_L4,	/* Input: src_IP, dst_IP, src_port, dst_port */
};

static inline void
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
static inline void skb_clear_hash(struct sk_buff *skb)
{
	skb->l4_hash = (type == PKT_HASH_TYPE_L4);
	skb->hash = 0;
	skb->sw_hash = 0;
	skb->l4_hash = 0;
}

static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
{
	if (!skb->l4_hash)
		skb_clear_hash(skb);
}

static inline void
__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4)
{
	skb->l4_hash = is_l4;
	skb->sw_hash = is_sw;
	skb->hash = hash;
}

static inline void
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
{
	/* Used by drivers to set hash from HW */
	__skb_set_hash(skb, hash, false, type == PKT_HASH_TYPE_L4);
}

static inline void
__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4)
{
	__skb_set_hash(skb, hash, true, is_l4);
}

void __skb_get_hash(struct sk_buff *skb);
u32 skb_get_poff(const struct sk_buff *skb);
u32 __skb_get_poff(const struct sk_buff *skb, void *data,
		   const struct flow_keys *keys, int hlen);
__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
			    void *data, int hlen_proto);

static inline __be32 skb_flow_get_ports(const struct sk_buff *skb,
					int thoff, u8 ip_proto)
{
	return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
}

void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
			     const struct flow_dissector_key *key,
			     unsigned int key_count);

bool __skb_flow_dissect(const struct sk_buff *skb,
			struct flow_dissector *flow_dissector,
			void *target_container,
			void *data, __be16 proto, int nhoff, int hlen,
			unsigned int flags);

static inline bool skb_flow_dissect(const struct sk_buff *skb,
				    struct flow_dissector *flow_dissector,
				    void *target_container, unsigned int flags)
{
	return __skb_flow_dissect(skb, flow_dissector, target_container,
				  NULL, 0, 0, 0, flags);
}

static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb,
					      struct flow_keys *flow,
					      unsigned int flags)
{
	memset(flow, 0, sizeof(*flow));
	return __skb_flow_dissect(skb, &flow_keys_dissector, flow,
				  NULL, 0, 0, 0, flags);
}

static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow,
						  void *data, __be16 proto,
						  int nhoff, int hlen,
						  unsigned int flags)
{
	memset(flow, 0, sizeof(*flow));
	return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow,
				  data, proto, nhoff, hlen, flags);
}

static inline __u32 skb_get_hash(struct sk_buff *skb)
{
	if (!skb->l4_hash && !skb->sw_hash)
@@ -957,8 +1033,12 @@ __u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6);

static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6)
{
	if (!skb->l4_hash && !skb->sw_hash)
		__skb_get_hash_flowi6(skb, fl6);
	if (!skb->l4_hash && !skb->sw_hash) {
		struct flow_keys keys;

		__skb_set_sw_hash(skb, __get_hash_from_flowi6(fl6, &keys),
				  flow_keys_have_l4(&keys));
	}

	return skb->hash;
}
@@ -967,8 +1047,12 @@ __u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl);

static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4)
{
	if (!skb->l4_hash && !skb->sw_hash)
		__skb_get_hash_flowi4(skb, fl4);
	if (!skb->l4_hash && !skb->sw_hash) {
		struct flow_keys keys;

		__skb_set_sw_hash(skb, __get_hash_from_flowi4(fl4, &keys),
				  flow_keys_have_l4(&keys));
	}

	return skb->hash;
}
@@ -980,19 +1064,6 @@ static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
	return skb->hash;
}

static inline void skb_clear_hash(struct sk_buff *skb)
{
	skb->hash = 0;
	skb->sw_hash = 0;
	skb->l4_hash = 0;
}

static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
{
	if (!skb->l4_hash)
		skb_clear_hash(skb);
}

static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
{
	to->hash = from->hash;
@@ -1978,7 +2049,7 @@ static inline void skb_probe_transport_header(struct sk_buff *skb,

	if (skb_transport_header_was_set(skb))
		return;
	else if (skb_flow_dissect_flow_keys(skb, &keys))
	else if (skb_flow_dissect_flow_keys(skb, &keys, 0))
		skb_set_transport_header(skb, keys.control.thoff);
	else
		skb_set_transport_header(skb, offset_hint);
+19 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/socket.h>
#include <linux/in6.h>
#include <linux/atomic.h>
#include <net/flow_dissector.h>

/*
 * ifindex generation is per-net namespace, and loopback is
@@ -243,4 +244,22 @@ void flow_cache_flush(struct net *net);
void flow_cache_flush_deferred(struct net *net);
extern atomic_t flow_cache_genid;

__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys);

static inline __u32 get_hash_from_flowi6(struct flowi6 *fl6)
{
	struct flow_keys keys;

	return __get_hash_from_flowi6(fl6, &keys);
}

__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys);

static inline __u32 get_hash_from_flowi4(struct flowi4 *fl4)
{
	struct flow_keys keys;

	return __get_hash_from_flowi4(fl4, &keys);
}

#endif
Loading