aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-09-05 20:47:12 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-05 20:47:12 -0400
commit2ba38943ba190eb6a494262003e23187d1b40fb4 (patch)
treed132fa676dc72a6bb0b9c6ef648f2dc694b6eeda
parent2c048e646212f9880e6f201771a30daa963d7f8b (diff)
parent8496e3382e33ef0b6862e07aaf4025420223232e (diff)
Merge branch 'eth_get_headlen'
Alexander Duyck says: ==================== net: Drop get_headlen functions in favor of generic function This series replaces the igb_get_headlen and ixgbe_get_headlen functions with a generic function named eth_get_headlen. I have done some performance testing on ixgbe with 258 byte frames since the calls are only used on frames larger than 256 bytes and have seen no significant difference in CPU utilization. v2: renamed __skb_get_poff to skb_get_poff renamed ___skb_get_poff to __skb_get_poff ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c109
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c116
-rw-r--r--include/linux/etherdevice.h1
-rw-r--r--include/linux/skbuff.h4
-rw-r--r--include/net/flow_keys.h2
-rw-r--r--net/core/filter.c2
-rw-r--r--net/core/flow_dissector.c46
-rw-r--r--net/ethernet/eth.c27
8 files changed, 68 insertions, 239 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 89de7fee5e94..4c023f0e54e4 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,
6769} 6769}
6770 6770
6771/** 6771/**
6772 * igb_get_headlen - determine size of header for LRO/GRO
6773 * @data: pointer to the start of the headers
6774 * @max_len: total length of section to find headers in
6775 *
6776 * This function is meant to determine the length of headers that will
6777 * be recognized by hardware for LRO, and GRO offloads. The main
6778 * motivation of doing this is to only perform one pull for IPv4 TCP
6779 * packets so that we can do basic things like calculating the gso_size
6780 * based on the average data per packet.
6781 **/
6782static unsigned int igb_get_headlen(unsigned char *data,
6783 unsigned int max_len)
6784{
6785 union {
6786 unsigned char *network;
6787 /* l2 headers */
6788 struct ethhdr *eth;
6789 struct vlan_hdr *vlan;
6790 /* l3 headers */
6791 struct iphdr *ipv4;
6792 struct ipv6hdr *ipv6;
6793 } hdr;
6794 __be16 protocol;
6795 u8 nexthdr = 0; /* default to not TCP */
6796 u8 hlen;
6797
6798 /* this should never happen, but better safe than sorry */
6799 if (max_len < ETH_HLEN)
6800 return max_len;
6801
6802 /* initialize network frame pointer */
6803 hdr.network = data;
6804
6805 /* set first protocol and move network header forward */
6806 protocol = hdr.eth->h_proto;
6807 hdr.network += ETH_HLEN;
6808
6809 /* handle any vlan tag if present */
6810 if (protocol == htons(ETH_P_8021Q)) {
6811 if ((hdr.network - data) > (max_len - VLAN_HLEN))
6812 return max_len;
6813
6814 protocol = hdr.vlan->h_vlan_encapsulated_proto;
6815 hdr.network += VLAN_HLEN;
6816 }
6817
6818 /* handle L3 protocols */
6819 if (protocol == htons(ETH_P_IP)) {
6820 if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
6821 return max_len;
6822
6823 /* access ihl as a u8 to avoid unaligned access on ia64 */
6824 hlen = (hdr.network[0] & 0x0F) << 2;
6825
6826 /* verify hlen meets minimum size requirements */
6827 if (hlen < sizeof(struct iphdr))
6828 return hdr.network - data;
6829
6830 /* record next protocol if header is present */
6831 if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
6832 nexthdr = hdr.ipv4->protocol;
6833 } else if (protocol == htons(ETH_P_IPV6)) {
6834 if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
6835 return max_len;
6836
6837 /* record next protocol */
6838 nexthdr = hdr.ipv6->nexthdr;
6839 hlen = sizeof(struct ipv6hdr);
6840 } else {
6841 return hdr.network - data;
6842 }
6843
6844 /* relocate pointer to start of L4 header */
6845 hdr.network += hlen;
6846
6847 /* finally sort out TCP */
6848 if (nexthdr == IPPROTO_TCP) {
6849 if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
6850 return max_len;
6851
6852 /* access doff as a u8 to avoid unaligned access on ia64 */
6853 hlen = (hdr.network[12] & 0xF0) >> 2;
6854
6855 /* verify hlen meets minimum size requirements */
6856 if (hlen < sizeof(struct tcphdr))
6857 return hdr.network - data;
6858
6859 hdr.network += hlen;
6860 } else if (nexthdr == IPPROTO_UDP) {
6861 if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
6862 return max_len;
6863
6864 hdr.network += sizeof(struct udphdr);
6865 }
6866
6867 /* If everything has gone correctly hdr.network should be the
6868 * data section of the packet and will be the end of the header.
6869 * If not then it probably represents the end of the last recognized
6870 * header.
6871 */
6872 if ((hdr.network - data) < max_len)
6873 return hdr.network - data;
6874 else
6875 return max_len;
6876}
6877
6878/**
6879 * igb_pull_tail - igb specific version of skb_pull_tail 6772 * igb_pull_tail - igb specific version of skb_pull_tail
6880 * @rx_ring: rx descriptor ring packet is being transacted on 6773 * @rx_ring: rx descriptor ring packet is being transacted on
6881 * @rx_desc: pointer to the EOP Rx descriptor 6774 * @rx_desc: pointer to the EOP Rx descriptor
@@ -6919,7 +6812,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
6919 /* we need the header to contain the greater of either ETH_HLEN or 6812 /* we need the header to contain the greater of either ETH_HLEN or
6920 * 60 bytes if the skb->len is less than 60 for skb_pad. 6813 * 60 bytes if the skb->len is less than 60 for skb_pad.
6921 */ 6814 */
6922 pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN); 6815 pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN);
6923 6816
6924 /* align pull length to size of long to optimize memcpy performance */ 6817 /* align pull length to size of long to optimize memcpy performance */
6925 skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long))); 6818 skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 5a3efd9f9de0..166dc0015a5e 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)
1521 ixgbe_release_rx_desc(rx_ring, i); 1521 ixgbe_release_rx_desc(rx_ring, i);
1522} 1522}
1523 1523
1524/**
1525 * ixgbe_get_headlen - determine size of header for RSC/LRO/GRO/FCOE
1526 * @data: pointer to the start of the headers
1527 * @max_len: total length of section to find headers in
1528 *
1529 * This function is meant to determine the length of headers that will
1530 * be recognized by hardware for LRO, GRO, and RSC offloads. The main
1531 * motivation of doing this is to only perform one pull for IPv4 TCP
1532 * packets so that we can do basic things like calculating the gso_size
1533 * based on the average data per packet.
1534 **/
1535static unsigned int ixgbe_get_headlen(unsigned char *data,
1536 unsigned int max_len)
1537{
1538 union {
1539 unsigned char *network;
1540 /* l2 headers */
1541 struct ethhdr *eth;
1542 struct vlan_hdr *vlan;
1543 /* l3 headers */
1544 struct iphdr *ipv4;
1545 struct ipv6hdr *ipv6;
1546 } hdr;
1547 __be16 protocol;
1548 u8 nexthdr = 0; /* default to not TCP */
1549 u8 hlen;
1550
1551 /* this should never happen, but better safe than sorry */
1552 if (max_len < ETH_HLEN)
1553 return max_len;
1554
1555 /* initialize network frame pointer */
1556 hdr.network = data;
1557
1558 /* set first protocol and move network header forward */
1559 protocol = hdr.eth->h_proto;
1560 hdr.network += ETH_HLEN;
1561
1562 /* handle any vlan tag if present */
1563 if (protocol == htons(ETH_P_8021Q)) {
1564 if ((hdr.network - data) > (max_len - VLAN_HLEN))
1565 return max_len;
1566
1567 protocol = hdr.vlan->h_vlan_encapsulated_proto;
1568 hdr.network += VLAN_HLEN;
1569 }
1570
1571 /* handle L3 protocols */
1572 if (protocol == htons(ETH_P_IP)) {
1573 if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
1574 return max_len;
1575
1576 /* access ihl as a u8 to avoid unaligned access on ia64 */
1577 hlen = (hdr.network[0] & 0x0F) << 2;
1578
1579 /* verify hlen meets minimum size requirements */
1580 if (hlen < sizeof(struct iphdr))
1581 return hdr.network - data;
1582
1583 /* record next protocol if header is present */
1584 if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
1585 nexthdr = hdr.ipv4->protocol;
1586 } else if (protocol == htons(ETH_P_IPV6)) {
1587 if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
1588 return max_len;
1589
1590 /* record next protocol */
1591 nexthdr = hdr.ipv6->nexthdr;
1592 hlen = sizeof(struct ipv6hdr);
1593#ifdef IXGBE_FCOE
1594 } else if (protocol == htons(ETH_P_FCOE)) {
1595 if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
1596 return max_len;
1597 hlen = FCOE_HEADER_LEN;
1598#endif
1599 } else {
1600 return hdr.network - data;
1601 }
1602
1603 /* relocate pointer to start of L4 header */
1604 hdr.network += hlen;
1605
1606 /* finally sort out TCP/UDP */
1607 if (nexthdr == IPPROTO_TCP) {
1608 if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
1609 return max_len;
1610
1611 /* access doff as a u8 to avoid unaligned access on ia64 */
1612 hlen = (hdr.network[12] & 0xF0) >> 2;
1613
1614 /* verify hlen meets minimum size requirements */
1615 if (hlen < sizeof(struct tcphdr))
1616 return hdr.network - data;
1617
1618 hdr.network += hlen;
1619 } else if (nexthdr == IPPROTO_UDP) {
1620 if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
1621 return max_len;
1622
1623 hdr.network += sizeof(struct udphdr);
1624 }
1625
1626 /*
1627 * If everything has gone correctly hdr.network should be the
1628 * data section of the packet and will be the end of the header.
1629 * If not then it probably represents the end of the last recognized
1630 * header.
1631 */
1632 if ((hdr.network - data) < max_len)
1633 return hdr.network - data;
1634 else
1635 return max_len;
1636}
1637
1638static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring, 1524static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
1639 struct sk_buff *skb) 1525 struct sk_buff *skb)
1640{ 1526{
@@ -1793,7 +1679,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
1793 * we need the header to contain the greater of either ETH_HLEN or 1679 * we need the header to contain the greater of either ETH_HLEN or
1794 * 60 bytes if the skb->len is less than 60 for skb_pad. 1680 * 60 bytes if the skb->len is less than 60 for skb_pad.
1795 */ 1681 */
1796 pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE); 1682 pull_len = eth_get_headlen(va, IXGBE_RX_HDR_SIZE);
1797 1683
1798 /* align pull length to size of long to optimize memcpy performance */ 1684 /* align pull length to size of long to optimize memcpy performance */
1799 skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long))); 1685 skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 9c5529dc6d07..733980fce8e3 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -29,6 +29,7 @@
29#include <asm/bitsperlong.h> 29#include <asm/bitsperlong.h>
30 30
31#ifdef __KERNEL__ 31#ifdef __KERNEL__
32u32 eth_get_headlen(void *data, unsigned int max_len);
32__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); 33__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
33extern const struct header_ops eth_header_ops; 34extern const struct header_ops eth_header_ops;
34 35
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 1cf0cfaef10a..07c9fdd0c126 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3218,7 +3218,9 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
3218 3218
3219int skb_checksum_setup(struct sk_buff *skb, bool recalculate); 3219int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
3220 3220
3221u32 __skb_get_poff(const struct sk_buff *skb); 3221u32 skb_get_poff(const struct sk_buff *skb);
3222u32 __skb_get_poff(const struct sk_buff *skb, void *data,
3223 const struct flow_keys *keys, int hlen);
3222 3224
3223/** 3225/**
3224 * skb_head_is_locked - Determine if the skb->head is locked down 3226 * 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 9a03f73c4974..7ee2df083542 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
40 return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0); 40 return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
41} 41}
42u32 flow_hash_from_keys(struct flow_keys *keys); 42u32 flow_hash_from_keys(struct flow_keys *keys);
43unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len,
44 __be16 protocol);
43#endif 45#endif
diff --git a/net/core/filter.c b/net/core/filter.c
index 37f8eb06fdee..fa5b7d0f77ac 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -113,7 +113,7 @@ static unsigned int pkt_type_offset(void)
113 113
114static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) 114static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
115{ 115{
116 return __skb_get_poff((struct sk_buff *)(unsigned long) ctx); 116 return skb_get_poff((struct sk_buff *)(unsigned long) ctx);
117} 117}
118 118
119static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) 119static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 12f48ca7a0b0..8560dea58803 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -13,6 +13,7 @@
13#include <linux/if_pppox.h> 13#include <linux/if_pppox.h>
14#include <linux/ppp_defs.h> 14#include <linux/ppp_defs.h>
15#include <net/flow_keys.h> 15#include <net/flow_keys.h>
16#include <scsi/fc/fc_fcoe.h>
16 17
17/* copy saddr & daddr, possibly using 64bit load/store 18/* copy saddr & daddr, possibly using 64bit load/store
18 * Equivalent to : flow->src = iph->saddr; 19 * Equivalent to : flow->src = iph->saddr;
@@ -117,6 +118,13 @@ ipv6:
117 flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); 118 flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
118 nhoff += sizeof(struct ipv6hdr); 119 nhoff += sizeof(struct ipv6hdr);
119 120
121 /* skip the flow label processing if skb is NULL. The
122 * assumption here is that if there is no skb we are not
123 * looking for flow info as much as we are length.
124 */
125 if (!skb)
126 break;
127
120 flow_label = ip6_flowlabel(iph); 128 flow_label = ip6_flowlabel(iph);
121 if (flow_label) { 129 if (flow_label) {
122 /* Awesome, IPv6 packet has a flow label so we can 130 /* Awesome, IPv6 packet has a flow label so we can
@@ -165,6 +173,9 @@ ipv6:
165 return false; 173 return false;
166 } 174 }
167 } 175 }
176 case htons(ETH_P_FCOE):
177 flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
178 /* fall through */
168 default: 179 default:
169 return false; 180 return false;
170 } 181 }
@@ -316,26 +327,18 @@ u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb,
316} 327}
317EXPORT_SYMBOL(__skb_tx_hash); 328EXPORT_SYMBOL(__skb_tx_hash);
318 329
319/* __skb_get_poff() returns the offset to the payload as far as it could 330u32 __skb_get_poff(const struct sk_buff *skb, void *data,
320 * be dissected. The main user is currently BPF, so that we can dynamically 331 const struct flow_keys *keys, int hlen)
321 * truncate packets without needing to push actual payload to the user
322 * space and can analyze headers only, instead.
323 */
324u32 __skb_get_poff(const struct sk_buff *skb)
325{ 332{
326 struct flow_keys keys; 333 u32 poff = keys->thoff;
327 u32 poff = 0;
328 334
329 if (!skb_flow_dissect(skb, &keys)) 335 switch (keys->ip_proto) {
330 return 0;
331
332 poff += keys.thoff;
333 switch (keys.ip_proto) {
334 case IPPROTO_TCP: { 336 case IPPROTO_TCP: {
335 const struct tcphdr *tcph; 337 const struct tcphdr *tcph;
336 struct tcphdr _tcph; 338 struct tcphdr _tcph;
337 339
338 tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph); 340 tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
341 data, hlen, &_tcph);
339 if (!tcph) 342 if (!tcph)
340 return poff; 343 return poff;
341 344
@@ -369,6 +372,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
369 return poff; 372 return poff;
370} 373}
371 374
375/* skb_get_poff() returns the offset to the payload as far as it could
376 * be dissected. The main user is currently BPF, so that we can dynamically
377 * truncate packets without needing to push actual payload to the user
378 * space and can analyze headers only, instead.
379 */
380u32 skb_get_poff(const struct sk_buff *skb)
381{
382 struct flow_keys keys;
383
384 if (!skb_flow_dissect(skb, &keys))
385 return 0;
386
387 return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb));
388}
389
372static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) 390static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
373{ 391{
374#ifdef CONFIG_XPS 392#ifdef CONFIG_XPS
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 5cebca134585..33a140e15834 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -146,6 +146,33 @@ int eth_rebuild_header(struct sk_buff *skb)
146EXPORT_SYMBOL(eth_rebuild_header); 146EXPORT_SYMBOL(eth_rebuild_header);
147 147
148/** 148/**
149 * eth_get_headlen - determine the the length of header for an ethernet frame
150 * @data: pointer to start of frame
151 * @len: total length of frame
152 *
153 * Make a best effort attempt to pull the length for all of the headers for
154 * a given frame in a linear buffer.
155 */
156u32 eth_get_headlen(void *data, unsigned int len)
157{
158 const struct ethhdr *eth = (const struct ethhdr *)data;
159 struct flow_keys keys;
160
161 /* this should never happen, but better safe than sorry */
162 if (len < sizeof(*eth))
163 return len;
164
165 /* parse any remaining L2/L3 headers, check for L4 */
166 if (!__skb_flow_dissect(NULL, &keys, data,
167 eth->h_proto, sizeof(*eth), len))
168 return max_t(u32, keys.thoff, sizeof(*eth));
169
170 /* parse for any L4 headers */
171 return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len);
172}
173EXPORT_SYMBOL(eth_get_headlen);
174
175/**
149 * eth_type_trans - determine the packet's protocol ID. 176 * eth_type_trans - determine the packet's protocol ID.
150 * @skb: received socket data 177 * @skb: received socket data
151 * @dev: receiving network device 178 * @dev: receiving network device