Skip to content

Commit 2ba3894

Browse files
committed
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 <[email protected]>
2 parents 2c048e6 + 8496e33 commit 2ba3894

File tree

8 files changed

+68
-239
lines changed

8 files changed

+68
-239
lines changed

drivers/net/ethernet/intel/igb/igb_main.c

Lines changed: 1 addition & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -6768,113 +6768,6 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring,
67686768
return true;
67696769
}
67706770

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-
**/
6782-
static 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-
68786771
/**
68796772
* igb_pull_tail - igb specific version of skb_pull_tail
68806773
* @rx_ring: rx descriptor ring packet is being transacted on
@@ -6919,7 +6812,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
69196812
/* we need the header to contain the greater of either ETH_HLEN or
69206813
* 60 bytes if the skb->len is less than 60 for skb_pad.
69216814
*/
6922-
pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
6815+
pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN);
69236816

69246817
/* align pull length to size of long to optimize memcpy performance */
69256818
skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 1 addition & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,120 +1521,6 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 cleaned_count)
15211521
ixgbe_release_rx_desc(rx_ring, i);
15221522
}
15231523

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-
**/
1535-
static 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-
16381524
static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
16391525
struct sk_buff *skb)
16401526
{
@@ -1793,7 +1679,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
17931679
* we need the header to contain the greater of either ETH_HLEN or
17941680
* 60 bytes if the skb->len is less than 60 for skb_pad.
17951681
*/
1796-
pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
1682+
pull_len = eth_get_headlen(va, IXGBE_RX_HDR_SIZE);
17971683

17981684
/* align pull length to size of long to optimize memcpy performance */
17991685
skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));

include/linux/etherdevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <asm/bitsperlong.h>
3030

3131
#ifdef __KERNEL__
32+
u32 eth_get_headlen(void *data, unsigned int max_len);
3233
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
3334
extern const struct header_ops eth_header_ops;
3435

include/linux/skbuff.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3218,7 +3218,9 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
32183218

32193219
int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
32203220

3221-
u32 __skb_get_poff(const struct sk_buff *skb);
3221+
u32 skb_get_poff(const struct sk_buff *skb);
3222+
u32 __skb_get_poff(const struct sk_buff *skb, void *data,
3223+
const struct flow_keys *keys, int hlen);
32223224

32233225
/**
32243226
* skb_head_is_locked - Determine if the skb->head is locked down

include/net/flow_keys.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8
4040
return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
4141
}
4242
u32 flow_hash_from_keys(struct flow_keys *keys);
43+
unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len,
44+
__be16 protocol);
4345
#endif

net/core/filter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ static unsigned int pkt_type_offset(void)
113113

114114
static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
115115
{
116-
return __skb_get_poff((struct sk_buff *)(unsigned long) ctx);
116+
return skb_get_poff((struct sk_buff *)(unsigned long) ctx);
117117
}
118118

119119
static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)

net/core/flow_dissector.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/if_pppox.h>
1414
#include <linux/ppp_defs.h>
1515
#include <net/flow_keys.h>
16+
#include <scsi/fc/fc_fcoe.h>
1617

1718
/* copy saddr & daddr, possibly using 64bit load/store
1819
* Equivalent to : flow->src = iph->saddr;
@@ -117,6 +118,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
117118
flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
118119
nhoff += sizeof(struct ipv6hdr);
119120

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+
120128
flow_label = ip6_flowlabel(iph);
121129
if (flow_label) {
122130
/* Awesome, IPv6 packet has a flow label so we can
@@ -165,6 +173,9 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
165173
return false;
166174
}
167175
}
176+
case htons(ETH_P_FCOE):
177+
flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
178+
/* fall through */
168179
default:
169180
return false;
170181
}
@@ -316,26 +327,18 @@ u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb,
316327
}
317328
EXPORT_SYMBOL(__skb_tx_hash);
318329

319-
/* __skb_get_poff() returns the offset to the payload as far as it could
320-
* be dissected. The main user is currently BPF, so that we can dynamically
321-
* truncate packets without needing to push actual payload to the user
322-
* space and can analyze headers only, instead.
323-
*/
324-
u32 __skb_get_poff(const struct sk_buff *skb)
330+
u32 __skb_get_poff(const struct sk_buff *skb, void *data,
331+
const struct flow_keys *keys, int hlen)
325332
{
326-
struct flow_keys keys;
327-
u32 poff = 0;
333+
u32 poff = keys->thoff;
328334

329-
if (!skb_flow_dissect(skb, &keys))
330-
return 0;
331-
332-
poff += keys.thoff;
333-
switch (keys.ip_proto) {
335+
switch (keys->ip_proto) {
334336
case IPPROTO_TCP: {
335337
const struct tcphdr *tcph;
336338
struct tcphdr _tcph;
337339

338-
tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph);
340+
tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
341+
data, hlen, &_tcph);
339342
if (!tcph)
340343
return poff;
341344

@@ -369,6 +372,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
369372
return poff;
370373
}
371374

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+
*/
380+
u32 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+
372390
static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
373391
{
374392
#ifdef CONFIG_XPS

0 commit comments

Comments
 (0)