netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] Drop get_headlen functions in favor of generic function
@ 2014-09-04 23:13 Alexander Duyck
  2014-09-04 23:13 ` [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames Alexander Duyck
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Alexander Duyck @ 2014-09-04 23:13 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet

This series replaced igb_get_headlen and ixgbe_get_headlen with a generic
function named eth_get_headlen.

This is a first pass at this and has been compile tested only.  I'm mainly
looking for feedback on any issues with the approach I have taken or any
complains about the eth_get_headlen function or the changes to __skb_get_poff
in the first patch.

I'll try running this through some stress/performance testing tomorrow to
see how it compares to the original functions.

---

Alexander Duyck (3):
      net: Add function for parsing the header length out of linear ethernet frames
      igb: use new eth_get_headlen interface
      ixgbe: use new eth_get_headlen interface


 drivers/net/ethernet/intel/igb/igb_main.c     |  109 -----------------------
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  116 -------------------------
 include/linux/etherdevice.h                   |    1 
 include/linux/skbuff.h                        |    2 
 include/net/flow_keys.h                       |    2 
 net/core/flow_dissector.c                     |   41 ++++++---
 net/ethernet/eth.c                            |   27 ++++++
 7 files changed, 60 insertions(+), 238 deletions(-)

-- 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames
  2014-09-04 23:13 [RFC PATCH 0/3] Drop get_headlen functions in favor of generic function Alexander Duyck
@ 2014-09-04 23:13 ` Alexander Duyck
  2014-09-04 23:36   ` Eric Dumazet
  2014-09-04 23:13 ` [RFC PATCH 2/3] igb: use new eth_get_headlen interface Alexander Duyck
  2014-09-04 23:13 ` [RFC PATCH 3/3] ixgbe: " Alexander Duyck
  2 siblings, 1 reply; 6+ messages in thread
From: Alexander Duyck @ 2014-09-04 23:13 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet

This patch updates some of the flow_dissector api so that it can be used to
parse the length of ethernet buffers stored in fragments.  Most of the
changes needed were to __skb_get_poff as it needed to be updated to support
sending a linear buffer instead of a skb.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---
 include/linux/etherdevice.h |    1 +
 include/linux/skbuff.h      |    2 ++
 include/net/flow_keys.h     |    2 ++
 net/core/flow_dissector.c   |   41 ++++++++++++++++++++++++++---------------
 net/ethernet/eth.c          |   27 +++++++++++++++++++++++++++
 5 files changed, 58 insertions(+), 15 deletions(-)

diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 9c5529d..733980f 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -29,6 +29,7 @@
 #include <asm/bitsperlong.h>
 
 #ifdef __KERNEL__
+u32 eth_get_headlen(void *data, unsigned int max_len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern const struct header_ops eth_header_ops;
 
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 02529fc..77d4d6f 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3217,6 +3217,8 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
 
 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);
 
 /**
  * skb_head_is_locked - Determine if the skb->head is locked down
diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h
index 9a03f73..7ee2df0 100644
--- a/include/net/flow_keys.h
+++ b/include/net/flow_keys.h
@@ -40,4 +40,6 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8
 	return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
 }
 u32 flow_hash_from_keys(struct flow_keys *keys);
+unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len,
+			   __be16 protocol);
 #endif
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 12f48ca..f55667e 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -13,6 +13,7 @@
 #include <linux/if_pppox.h>
 #include <linux/ppp_defs.h>
 #include <net/flow_keys.h>
+#include <scsi/fc/fc_fcoe.h>
 
 /* copy saddr & daddr, possibly using 64bit load/store
  * Equivalent to :	flow->src = iph->saddr;
@@ -118,7 +119,7 @@ ipv6:
 		nhoff += sizeof(struct ipv6hdr);
 
 		flow_label = ip6_flowlabel(iph);
-		if (flow_label) {
+		if (flow_label && skb) {
 			/* Awesome, IPv6 packet has a flow label so we can
 			 * use that to represent the ports without any
 			 * further dissection.
@@ -165,6 +166,9 @@ ipv6:
 			return false;
 		}
 	}
+	case htons(ETH_P_FCOE):
+		flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
+		/* fall through */
 	default:
 		return false;
 	}
@@ -316,26 +320,18 @@ u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb,
 }
 EXPORT_SYMBOL(__skb_tx_hash);
 
-/* __skb_get_poff() returns the offset to the payload as far as it could
- * be dissected. The main user is currently BPF, so that we can dynamically
- * truncate packets without needing to push actual payload to the user
- * space and can analyze headers only, instead.
- */
-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)
 {
-	struct flow_keys keys;
-	u32 poff = 0;
-
-	if (!skb_flow_dissect(skb, &keys))
-		return 0;
+	u32 poff = keys->thoff;
 
-	poff += keys.thoff;
-	switch (keys.ip_proto) {
+	switch (keys->ip_proto) {
 	case IPPROTO_TCP: {
 		const struct tcphdr *tcph;
 		struct tcphdr _tcph;
 
-		tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph);
+		tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
+					    data, hlen, &_tcph);
 		if (!tcph)
 			return poff;
 
@@ -369,6 +365,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
 	return poff;
 }
 
+/* __skb_get_poff() returns the offset to the payload as far as it could
+ * be dissected. The main user is currently BPF, so that we can dynamically
+ * truncate packets without needing to push actual payload to the user
+ * space and can analyze headers only, instead.
+ */
+u32 __skb_get_poff(const struct sk_buff *skb)
+{
+	struct flow_keys keys;
+
+	if (!skb_flow_dissect(skb, &keys))
+		return 0;
+
+	return ___skb_get_poff(skb, skb->data, &keys, skb->len);
+}
+
 static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_XPS
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 5cebca1..f0299ac 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -146,6 +146,33 @@ int eth_rebuild_header(struct sk_buff *skb)
 EXPORT_SYMBOL(eth_rebuild_header);
 
 /**
+ * eth_get_headlen - determine the the length of header for an ethernet frame
+ * @data: pointer to start of frame
+ * @len: total length of frame
+ *
+ * Make a best effort attempt to pull the length for all of the headers for
+ * a given frame in a linear buffer.
+ */
+u32 eth_get_headlen(void *data, unsigned int len)
+{
+	const struct ethhdr *eth = (const struct ethhdr *)data;
+	struct flow_keys keys;
+
+	/* this should never happen, but better safe than sorry */
+	if (len < sizeof(*eth))
+		return len;
+
+	/* parse any remaining L2/L3 headers, check for L4 */
+	if (!__skb_flow_dissect(NULL, &keys, data,
+				eth->h_proto, sizeof(*eth), len))
+		return max_t(u32, keys.thoff, sizeof(*eth));
+
+	/* parse for any L4 headers */
+	return min_t(u32, ___skb_get_poff(NULL, data, &keys, len), len);
+}
+EXPORT_SYMBOL(eth_get_headlen);
+
+/**
  * eth_type_trans - determine the packet's protocol ID.
  * @skb: received socket data
  * @dev: receiving network device

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH 2/3] igb: use new eth_get_headlen interface
  2014-09-04 23:13 [RFC PATCH 0/3] Drop get_headlen functions in favor of generic function Alexander Duyck
  2014-09-04 23:13 ` [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames Alexander Duyck
@ 2014-09-04 23:13 ` Alexander Duyck
  2014-09-04 23:13 ` [RFC PATCH 3/3] ixgbe: " Alexander Duyck
  2 siblings, 0 replies; 6+ messages in thread
From: Alexander Duyck @ 2014-09-04 23:13 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet

Update igb to drop the igb_get_headlen function in favor of eth_get_headlen.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---
 drivers/net/ethernet/intel/igb/igb_main.c |  109 -----------------------------
 1 file changed, 1 insertion(+), 108 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 89de7fe..4c023f0 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -6769,113 +6769,6 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring,
 }
 
 /**
- *  igb_get_headlen - determine size of header for LRO/GRO
- *  @data: pointer to the start of the headers
- *  @max_len: total length of section to find headers in
- *
- *  This function is meant to determine the length of headers that will
- *  be recognized by hardware for LRO, and GRO offloads.  The main
- *  motivation of doing this is to only perform one pull for IPv4 TCP
- *  packets so that we can do basic things like calculating the gso_size
- *  based on the average data per packet.
- **/
-static unsigned int igb_get_headlen(unsigned char *data,
-				    unsigned int max_len)
-{
-	union {
-		unsigned char *network;
-		/* l2 headers */
-		struct ethhdr *eth;
-		struct vlan_hdr *vlan;
-		/* l3 headers */
-		struct iphdr *ipv4;
-		struct ipv6hdr *ipv6;
-	} hdr;
-	__be16 protocol;
-	u8 nexthdr = 0;	/* default to not TCP */
-	u8 hlen;
-
-	/* this should never happen, but better safe than sorry */
-	if (max_len < ETH_HLEN)
-		return max_len;
-
-	/* initialize network frame pointer */
-	hdr.network = data;
-
-	/* set first protocol and move network header forward */
-	protocol = hdr.eth->h_proto;
-	hdr.network += ETH_HLEN;
-
-	/* handle any vlan tag if present */
-	if (protocol == htons(ETH_P_8021Q)) {
-		if ((hdr.network - data) > (max_len - VLAN_HLEN))
-			return max_len;
-
-		protocol = hdr.vlan->h_vlan_encapsulated_proto;
-		hdr.network += VLAN_HLEN;
-	}
-
-	/* handle L3 protocols */
-	if (protocol == htons(ETH_P_IP)) {
-		if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-			return max_len;
-
-		/* access ihl as a u8 to avoid unaligned access on ia64 */
-		hlen = (hdr.network[0] & 0x0F) << 2;
-
-		/* verify hlen meets minimum size requirements */
-		if (hlen < sizeof(struct iphdr))
-			return hdr.network - data;
-
-		/* record next protocol if header is present */
-		if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-			nexthdr = hdr.ipv4->protocol;
-	} else if (protocol == htons(ETH_P_IPV6)) {
-		if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-			return max_len;
-
-		/* record next protocol */
-		nexthdr = hdr.ipv6->nexthdr;
-		hlen = sizeof(struct ipv6hdr);
-	} else {
-		return hdr.network - data;
-	}
-
-	/* relocate pointer to start of L4 header */
-	hdr.network += hlen;
-
-	/* finally sort out TCP */
-	if (nexthdr == IPPROTO_TCP) {
-		if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-			return max_len;
-
-		/* access doff as a u8 to avoid unaligned access on ia64 */
-		hlen = (hdr.network[12] & 0xF0) >> 2;
-
-		/* verify hlen meets minimum size requirements */
-		if (hlen < sizeof(struct tcphdr))
-			return hdr.network - data;
-
-		hdr.network += hlen;
-	} else if (nexthdr == IPPROTO_UDP) {
-		if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-			return max_len;
-
-		hdr.network += sizeof(struct udphdr);
-	}
-
-	/* If everything has gone correctly hdr.network should be the
-	 * data section of the packet and will be the end of the header.
-	 * If not then it probably represents the end of the last recognized
-	 * header.
-	 */
-	if ((hdr.network - data) < max_len)
-		return hdr.network - data;
-	else
-		return max_len;
-}
-
-/**
  *  igb_pull_tail - igb specific version of skb_pull_tail
  *  @rx_ring: rx descriptor ring packet is being transacted on
  *  @rx_desc: pointer to the EOP Rx descriptor
@@ -6919,7 +6812,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
 	/* we need the header to contain the greater of either ETH_HLEN or
 	 * 60 bytes if the skb->len is less than 60 for skb_pad.
 	 */
-	pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
+	pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN);
 
 	/* align pull length to size of long to optimize memcpy performance */
 	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH 3/3] ixgbe: use new eth_get_headlen interface
  2014-09-04 23:13 [RFC PATCH 0/3] Drop get_headlen functions in favor of generic function Alexander Duyck
  2014-09-04 23:13 ` [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames Alexander Duyck
  2014-09-04 23:13 ` [RFC PATCH 2/3] igb: use new eth_get_headlen interface Alexander Duyck
@ 2014-09-04 23:13 ` Alexander Duyck
  2 siblings, 0 replies; 6+ messages in thread
From: Alexander Duyck @ 2014-09-04 23:13 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet

Update ixgbe to drop the ixgbe_get_headlen function in favor of eth_get_headlen.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  116 -------------------------
 1 file changed, 1 insertion(+), 115 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 53fbf06..09c3746 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1521,120 +1521,6 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 cleaned_count)
 		ixgbe_release_rx_desc(rx_ring, i);
 }
 
-/**
- * ixgbe_get_headlen - determine size of header for RSC/LRO/GRO/FCOE
- * @data: pointer to the start of the headers
- * @max_len: total length of section to find headers in
- *
- * This function is meant to determine the length of headers that will
- * be recognized by hardware for LRO, GRO, and RSC offloads.  The main
- * motivation of doing this is to only perform one pull for IPv4 TCP
- * packets so that we can do basic things like calculating the gso_size
- * based on the average data per packet.
- **/
-static unsigned int ixgbe_get_headlen(unsigned char *data,
-				      unsigned int max_len)
-{
-	union {
-		unsigned char *network;
-		/* l2 headers */
-		struct ethhdr *eth;
-		struct vlan_hdr *vlan;
-		/* l3 headers */
-		struct iphdr *ipv4;
-		struct ipv6hdr *ipv6;
-	} hdr;
-	__be16 protocol;
-	u8 nexthdr = 0;	/* default to not TCP */
-	u8 hlen;
-
-	/* this should never happen, but better safe than sorry */
-	if (max_len < ETH_HLEN)
-		return max_len;
-
-	/* initialize network frame pointer */
-	hdr.network = data;
-
-	/* set first protocol and move network header forward */
-	protocol = hdr.eth->h_proto;
-	hdr.network += ETH_HLEN;
-
-	/* handle any vlan tag if present */
-	if (protocol == htons(ETH_P_8021Q)) {
-		if ((hdr.network - data) > (max_len - VLAN_HLEN))
-			return max_len;
-
-		protocol = hdr.vlan->h_vlan_encapsulated_proto;
-		hdr.network += VLAN_HLEN;
-	}
-
-	/* handle L3 protocols */
-	if (protocol == htons(ETH_P_IP)) {
-		if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-			return max_len;
-
-		/* access ihl as a u8 to avoid unaligned access on ia64 */
-		hlen = (hdr.network[0] & 0x0F) << 2;
-
-		/* verify hlen meets minimum size requirements */
-		if (hlen < sizeof(struct iphdr))
-			return hdr.network - data;
-
-		/* record next protocol if header is present */
-		if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-			nexthdr = hdr.ipv4->protocol;
-	} else if (protocol == htons(ETH_P_IPV6)) {
-		if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-			return max_len;
-
-		/* record next protocol */
-		nexthdr = hdr.ipv6->nexthdr;
-		hlen = sizeof(struct ipv6hdr);
-#ifdef IXGBE_FCOE
-	} else if (protocol == htons(ETH_P_FCOE)) {
-		if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
-			return max_len;
-		hlen = FCOE_HEADER_LEN;
-#endif
-	} else {
-		return hdr.network - data;
-	}
-
-	/* relocate pointer to start of L4 header */
-	hdr.network += hlen;
-
-	/* finally sort out TCP/UDP */
-	if (nexthdr == IPPROTO_TCP) {
-		if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-			return max_len;
-
-		/* access doff as a u8 to avoid unaligned access on ia64 */
-		hlen = (hdr.network[12] & 0xF0) >> 2;
-
-		/* verify hlen meets minimum size requirements */
-		if (hlen < sizeof(struct tcphdr))
-			return hdr.network - data;
-
-		hdr.network += hlen;
-	} else if (nexthdr == IPPROTO_UDP) {
-		if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-			return max_len;
-
-		hdr.network += sizeof(struct udphdr);
-	}
-
-	/*
-	 * If everything has gone correctly hdr.network should be the
-	 * data section of the packet and will be the end of the header.
-	 * If not then it probably represents the end of the last recognized
-	 * header.
-	 */
-	if ((hdr.network - data) < max_len)
-		return hdr.network - data;
-	else
-		return max_len;
-}
-
 static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
 				   struct sk_buff *skb)
 {
@@ -1793,7 +1679,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
 	 * we need the header to contain the greater of either ETH_HLEN or
 	 * 60 bytes if the skb->len is less than 60 for skb_pad.
 	 */
-	pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
+	pull_len = eth_get_headlen(va, IXGBE_RX_HDR_SIZE);
 
 	/* align pull length to size of long to optimize memcpy performance */
 	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames
  2014-09-04 23:13 ` [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames Alexander Duyck
@ 2014-09-04 23:36   ` Eric Dumazet
  2014-09-05  1:00     ` Alexander Duyck
  0 siblings, 1 reply; 6+ messages in thread
From: Eric Dumazet @ 2014-09-04 23:36 UTC (permalink / raw)
  To: Alexander Duyck; +Cc: netdev, davem

On Thu, 2014-09-04 at 19:13 -0400, Alexander Duyck wrote:
> This patch updates some of the flow_dissector api so that it can be used to
> parse the length of ethernet buffers stored in fragments.  Most of the
> changes needed were to __skb_get_poff as it needed to be updated to support
> sending a linear buffer instead of a skb.
> 
> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
> ---
>  include/linux/etherdevice.h |    1 +
>  include/linux/skbuff.h      |    2 ++
>  include/net/flow_keys.h     |    2 ++
>  net/core/flow_dissector.c   |   41 ++++++++++++++++++++++++++---------------
>  net/ethernet/eth.c          |   27 +++++++++++++++++++++++++++
>  5 files changed, 58 insertions(+), 15 deletions(-)
> 
> diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
> index 9c5529d..733980f 100644
> --- a/include/linux/etherdevice.h
> +++ b/include/linux/etherdevice.h
> @@ -29,6 +29,7 @@
>  #include <asm/bitsperlong.h>
>  
>  #ifdef __KERNEL__
> +u32 eth_get_headlen(void *data, unsigned int max_len);
>  __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
>  extern const struct header_ops eth_header_ops;
>  
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 02529fc..77d4d6f 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -3217,6 +3217,8 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
>  int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
>  
>  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);
>  
>  /**
>   * skb_head_is_locked - Determine if the skb->head is locked down
> diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h
> index 9a03f73..7ee2df0 100644
> --- a/include/net/flow_keys.h
> +++ b/include/net/flow_keys.h
> @@ -40,4 +40,6 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8
>  	return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
>  }
>  u32 flow_hash_from_keys(struct flow_keys *keys);
> +unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len,
> +			   __be16 protocol);
>  #endif
> diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
> index 12f48ca..f55667e 100644
> --- a/net/core/flow_dissector.c
> +++ b/net/core/flow_dissector.c
> @@ -13,6 +13,7 @@
>  #include <linux/if_pppox.h>
>  #include <linux/ppp_defs.h>
>  #include <net/flow_keys.h>
> +#include <scsi/fc/fc_fcoe.h>
>  
>  /* copy saddr & daddr, possibly using 64bit load/store
>   * Equivalent to :	flow->src = iph->saddr;
> @@ -118,7 +119,7 @@ ipv6:
>  		nhoff += sizeof(struct ipv6hdr);
>  
>  		flow_label = ip6_flowlabel(iph);
> -		if (flow_label) {
> +		if (flow_label && skb) {

Hmpff... undocumented bit here....

>  			/* Awesome, IPv6 packet has a flow label so we can
>  			 * use that to represent the ports without any
>  			 * further dissection.
> @@ -165,6 +166,9 @@ ipv6:
>  			return false;
>  		}
>  	}
> +	case htons(ETH_P_FCOE):
> +		flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
> +		/* fall through */
>  	default:
>  		return false;
>  	}
> @@ -316,26 +320,18 @@ u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb,
>  }
>  EXPORT_SYMBOL(__skb_tx_hash);
>  
> -/* __skb_get_poff() returns the offset to the payload as far as it could
> - * be dissected. The main user is currently BPF, so that we can dynamically
> - * truncate packets without needing to push actual payload to the user
> - * space and can analyze headers only, instead.
> - */
> -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)
>  {
> -	struct flow_keys keys;
> -	u32 poff = 0;
> -
> -	if (!skb_flow_dissect(skb, &keys))
> -		return 0;
> +	u32 poff = keys->thoff;
>  
> -	poff += keys.thoff;
> -	switch (keys.ip_proto) {
> +	switch (keys->ip_proto) {
>  	case IPPROTO_TCP: {
>  		const struct tcphdr *tcph;
>  		struct tcphdr _tcph;
>  
> -		tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph);
> +		tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
> +					    data, hlen, &_tcph);
>  		if (!tcph)
>  			return poff;
>  
> @@ -369,6 +365,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
>  	return poff;
>  }
>  
> +/* __skb_get_poff() returns the offset to the payload as far as it could
> + * be dissected. The main user is currently BPF, so that we can dynamically
> + * truncate packets without needing to push actual payload to the user
> + * space and can analyze headers only, instead.
> + */
> +u32 __skb_get_poff(const struct sk_buff *skb)
> +{
> +	struct flow_keys keys;
> +
> +	if (!skb_flow_dissect(skb, &keys))
> +		return 0;
> +
> +	return ___skb_get_poff(skb, skb->data, &keys, skb->len);

hlen is not skb->len, but skb_headlen(skb)

> +}
> +
>  static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
>  {
>  #ifdef CONFIG_XPS
> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
> index 5cebca1..f0299ac 100644
> --- a/net/ethernet/eth.c
> +++ b/net/ethernet/eth.c
> @@ -146,6 +146,33 @@ int eth_rebuild_header(struct sk_buff *skb)
>  EXPORT_SYMBOL(eth_rebuild_header);
>  
>  /**
> + * eth_get_headlen - determine the the length of header for an ethernet frame
> + * @data: pointer to start of frame
> + * @len: total length of frame
> + *
> + * Make a best effort attempt to pull the length for all of the headers for
> + * a given frame in a linear buffer.
> + */
> +u32 eth_get_headlen(void *data, unsigned int len)
> +{
> +	const struct ethhdr *eth = (const struct ethhdr *)data;
> +	struct flow_keys keys;
> +
> +	/* this should never happen, but better safe than sorry */
> +	if (len < sizeof(*eth))
> +		return len;
> +
> +	/* parse any remaining L2/L3 headers, check for L4 */
> +	if (!__skb_flow_dissect(NULL, &keys, data,
> +				eth->h_proto, sizeof(*eth), len))
> +		return max_t(u32, keys.thoff, sizeof(*eth));

Not sure keys.thoff is valid at this point ?

> +
> +	/* parse for any L4 headers */
> +	return min_t(u32, ___skb_get_poff(NULL, data, &keys, len), len);
> +}
> +EXPORT_SYMBOL(eth_get_headlen);
> +
> +/**
>   * eth_type_trans - determine the packet's protocol ID.
>   * @skb: received socket data
>   * @dev: receiving network device
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames
  2014-09-04 23:36   ` Eric Dumazet
@ 2014-09-05  1:00     ` Alexander Duyck
  0 siblings, 0 replies; 6+ messages in thread
From: Alexander Duyck @ 2014-09-05  1:00 UTC (permalink / raw)
  To: Eric Dumazet, Alexander Duyck; +Cc: netdev, davem

On 09/04/2014 04:36 PM, Eric Dumazet wrote:
> On Thu, 2014-09-04 at 19:13 -0400, Alexander Duyck wrote:
>> This patch updates some of the flow_dissector api so that it can be used to
>> parse the length of ethernet buffers stored in fragments.  Most of the
>> changes needed were to __skb_get_poff as it needed to be updated to support
>> sending a linear buffer instead of a skb.
>>
>> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
>> ---
>>  include/linux/etherdevice.h |    1 +
>>  include/linux/skbuff.h      |    2 ++
>>  include/net/flow_keys.h     |    2 ++
>>  net/core/flow_dissector.c   |   41 ++++++++++++++++++++++++++---------------
>>  net/ethernet/eth.c          |   27 +++++++++++++++++++++++++++
>>  5 files changed, 58 insertions(+), 15 deletions(-)
>>
>> diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
>> index 12f48ca..f55667e 100644
>> --- a/net/core/flow_dissector.c
>> +++ b/net/core/flow_dissector.c
>> @@ -13,6 +13,7 @@
>>  #include <linux/if_pppox.h>
>>  #include <linux/ppp_defs.h>
>>  #include <net/flow_keys.h>
>> +#include <scsi/fc/fc_fcoe.h>
>>  
>>  /* copy saddr & daddr, possibly using 64bit load/store
>>   * Equivalent to :	flow->src = iph->saddr;
>> @@ -118,7 +119,7 @@ ipv6:
>>  		nhoff += sizeof(struct ipv6hdr);
>>  
>>  		flow_label = ip6_flowlabel(iph);
>> -		if (flow_label) {
>> +		if (flow_label && skb) {
> Hmpff... undocumented bit here....

I'll add a comment.  It is basically just forcing it to continue parsing
for the case where skb is NULL which currently only applies to
eth_get_headlen.

>  
> @@ -369,6 +365,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
>  	return poff;
>  }
>  
> +/* __skb_get_poff() returns the offset to the payload as far as it could
> + * be dissected. The main user is currently BPF, so that we can dynamically
> + * truncate packets without needing to push actual payload to the user
> + * space and can analyze headers only, instead.
> + */
> +u32 __skb_get_poff(const struct sk_buff *skb)
> +{
> +	struct flow_keys keys;
> +
> +	if (!skb_flow_dissect(skb, &keys))
> +		return 0;
> +
> +	return ___skb_get_poff(skb, skb->data, &keys, skb->len);
> hlen is not skb->len, but skb_headlen(skb)

My bad.  I will fix that for the next one.

>> +}
>> +
>>  static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
>>  {
>>  #ifdef CONFIG_XPS
>> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
>> index 5cebca1..f0299ac 100644
>> --- a/net/ethernet/eth.c
>> +++ b/net/ethernet/eth.c
>> @@ -146,6 +146,33 @@ int eth_rebuild_header(struct sk_buff *skb)
>>  EXPORT_SYMBOL(eth_rebuild_header);
>>  
>>  /**
>> + * eth_get_headlen - determine the the length of header for an ethernet frame
>> + * @data: pointer to start of frame
>> + * @len: total length of frame
>> + *
>> + * Make a best effort attempt to pull the length for all of the headers for
>> + * a given frame in a linear buffer.
>> + */
>> +u32 eth_get_headlen(void *data, unsigned int len)
>> +{
>> +	const struct ethhdr *eth = (const struct ethhdr *)data;
>> +	struct flow_keys keys;
>> +
>> +	/* this should never happen, but better safe than sorry */
>> +	if (len < sizeof(*eth))
>> +		return len;
>> +
>> +	/* parse any remaining L2/L3 headers, check for L4 */
>> +	if (!__skb_flow_dissect(NULL, &keys, data,
>> +				eth->h_proto, sizeof(*eth), len))
>> +		return max_t(u32, keys.thoff, sizeof(*eth));
> Not sure keys.thoff is valid at this point ?
>

It should be 0 if it didn't find any value.  __skb_flow_dissect starts
by doing a memset 0 on the keys.  So I am using the max_t to force it to
at least include the Ethernet header in the length to pull as otherwise
we will trigger errors on eth_type_trans.

Thanks,

Alex

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-09-05  1:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-04 23:13 [RFC PATCH 0/3] Drop get_headlen functions in favor of generic function Alexander Duyck
2014-09-04 23:13 ` [RFC PATCH 1/3] net: Add function for parsing the header length out of linear ethernet frames Alexander Duyck
2014-09-04 23:36   ` Eric Dumazet
2014-09-05  1:00     ` Alexander Duyck
2014-09-04 23:13 ` [RFC PATCH 2/3] igb: use new eth_get_headlen interface Alexander Duyck
2014-09-04 23:13 ` [RFC PATCH 3/3] ixgbe: " Alexander Duyck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).