Skip to content

Commit 76620aa

Browse files
herbertxdavem330
authored andcommitted
gro: New frags interface to avoid copying shinfo
It turns out that copying a 16-byte area at ~800k times a second can be really expensive :) This patch redesigns the frags GRO interface to avoid copying that area twice. The two disciples of the frags interface have been converted. Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 861ab44 commit 76620aa

File tree

7 files changed

+101
-93
lines changed

7 files changed

+101
-93
lines changed

drivers/net/cxgb3/adapter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ struct sge_qset { /* an SGE queue set */
195195
struct sge_rspq rspq;
196196
struct sge_fl fl[SGE_RXQ_PER_SET];
197197
struct sge_txq txq[SGE_TXQ_PER_SET];
198-
struct napi_gro_fraginfo lro_frag_tbl;
198+
int nomem;
199199
int lro_enabled;
200200
void *lro_va;
201201
struct net_device *netdev;

drivers/net/cxgb3/sge.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,8 @@ static void t3_reset_qset(struct sge_qset *q)
654654
q->txq_stopped = 0;
655655
q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */
656656
q->rx_reclaim_timer.function = NULL;
657-
q->lro_frag_tbl.nr_frags = q->lro_frag_tbl.len = 0;
657+
q->nomem = 0;
658+
napi_free_frags(&q->napi);
658659
}
659660

660661

@@ -2074,20 +2075,19 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
20742075
struct sge_fl *fl, int len, int complete)
20752076
{
20762077
struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
2078+
struct sk_buff *skb = NULL;
20772079
struct cpl_rx_pkt *cpl;
2078-
struct skb_frag_struct *rx_frag = qs->lro_frag_tbl.frags;
2079-
int nr_frags = qs->lro_frag_tbl.nr_frags;
2080-
int frag_len = qs->lro_frag_tbl.len;
2080+
struct skb_frag_struct *rx_frag;
2081+
int nr_frags;
20812082
int offset = 0;
20822083

2083-
if (!nr_frags) {
2084-
offset = 2 + sizeof(struct cpl_rx_pkt);
2085-
qs->lro_va = cpl = sd->pg_chunk.va + 2;
2084+
if (!qs->nomem) {
2085+
skb = napi_get_frags(&qs->napi);
2086+
qs->nomem = !skb;
20862087
}
20872088

20882089
fl->credits--;
20892090

2090-
len -= offset;
20912091
pci_dma_sync_single_for_cpu(adap->pdev,
20922092
pci_unmap_addr(sd, dma_addr),
20932093
fl->buf_size - SGE_PG_RSVD,
@@ -2100,21 +2100,38 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
21002100
fl->alloc_size,
21012101
PCI_DMA_FROMDEVICE);
21022102

2103+
if (!skb) {
2104+
put_page(sd->pg_chunk.page);
2105+
if (complete)
2106+
qs->nomem = 0;
2107+
return;
2108+
}
2109+
2110+
rx_frag = skb_shinfo(skb)->frags;
2111+
nr_frags = skb_shinfo(skb)->nr_frags;
2112+
2113+
if (!nr_frags) {
2114+
offset = 2 + sizeof(struct cpl_rx_pkt);
2115+
qs->lro_va = sd->pg_chunk.va + 2;
2116+
}
2117+
len -= offset;
2118+
21032119
prefetch(qs->lro_va);
21042120

21052121
rx_frag += nr_frags;
21062122
rx_frag->page = sd->pg_chunk.page;
21072123
rx_frag->page_offset = sd->pg_chunk.offset + offset;
21082124
rx_frag->size = len;
2109-
frag_len += len;
2110-
qs->lro_frag_tbl.nr_frags++;
2111-
qs->lro_frag_tbl.len = frag_len;
21122125

2126+
skb->len += len;
2127+
skb->data_len += len;
2128+
skb->truesize += len;
2129+
skb_shinfo(skb)->nr_frags++;
21132130

21142131
if (!complete)
21152132
return;
21162133

2117-
qs->lro_frag_tbl.ip_summed = CHECKSUM_UNNECESSARY;
2134+
skb->ip_summed = CHECKSUM_UNNECESSARY;
21182135
cpl = qs->lro_va;
21192136

21202137
if (unlikely(cpl->vlan_valid)) {
@@ -2123,15 +2140,11 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
21232140
struct vlan_group *grp = pi->vlan_grp;
21242141

21252142
if (likely(grp != NULL)) {
2126-
vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan),
2127-
&qs->lro_frag_tbl);
2128-
goto out;
2143+
vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan));
2144+
return;
21292145
}
21302146
}
2131-
napi_gro_frags(&qs->napi, &qs->lro_frag_tbl);
2132-
2133-
out:
2134-
qs->lro_frag_tbl.nr_frags = qs->lro_frag_tbl.len = 0;
2147+
napi_gro_frags(&qs->napi);
21352148
}
21362149

21372150
/**
@@ -2300,8 +2313,6 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
23002313
if (fl->use_pages) {
23012314
void *addr = fl->sdesc[fl->cidx].pg_chunk.va;
23022315

2303-
prefetch(&qs->lro_frag_tbl);
2304-
23052316
prefetch(addr);
23062317
#if L1_CACHE_BYTES < 128
23072318
prefetch(addr + L1_CACHE_BYTES);

drivers/net/sfc/rx.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -450,17 +450,27 @@ static void efx_rx_packet_lro(struct efx_channel *channel,
450450

451451
/* Pass the skb/page into the LRO engine */
452452
if (rx_buf->page) {
453-
struct napi_gro_fraginfo info;
453+
struct sk_buff *skb = napi_get_frags(napi);
454454

455-
info.frags[0].page = rx_buf->page;
456-
info.frags[0].page_offset = efx_rx_buf_offset(rx_buf);
457-
info.frags[0].size = rx_buf->len;
458-
info.nr_frags = 1;
459-
info.ip_summed = CHECKSUM_UNNECESSARY;
460-
info.len = rx_buf->len;
455+
if (!skb) {
456+
put_page(rx_buf->page);
457+
goto out;
458+
}
459+
460+
skb_shinfo(skb)->frags[0].page = rx_buf->page;
461+
skb_shinfo(skb)->frags[0].page_offset =
462+
efx_rx_buf_offset(rx_buf);
463+
skb_shinfo(skb)->frags[0].size = rx_buf->len;
464+
skb_shinfo(skb)->nr_frags = 1;
465+
466+
skb->len = rx_buf->len;
467+
skb->data_len = rx_buf->len;
468+
skb->truesize += rx_buf->len;
469+
skb->ip_summed = CHECKSUM_UNNECESSARY;
461470

462-
napi_gro_frags(napi, &info);
471+
napi_gro_frags(napi);
463472

473+
out:
464474
EFX_BUG_ON_PARANOID(rx_buf->skb);
465475
rx_buf->page = NULL;
466476
} else {

include/linux/if_vlan.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ extern int vlan_hwaccel_do_receive(struct sk_buff *skb);
118118
extern int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
119119
unsigned int vlan_tci, struct sk_buff *skb);
120120
extern int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
121-
unsigned int vlan_tci,
122-
struct napi_gro_fraginfo *info);
121+
unsigned int vlan_tci);
123122

124123
#else
125124
static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
@@ -154,8 +153,7 @@ static inline int vlan_gro_receive(struct napi_struct *napi,
154153
}
155154

156155
static inline int vlan_gro_frags(struct napi_struct *napi,
157-
struct vlan_group *grp, unsigned int vlan_tci,
158-
struct napi_gro_fraginfo *info)
156+
struct vlan_group *grp, unsigned int vlan_tci)
159157
{
160158
return NET_RX_DROP;
161159
}

include/linux/netdevice.h

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,14 +1047,6 @@ struct packet_type {
10471047
struct list_head list;
10481048
};
10491049

1050-
struct napi_gro_fraginfo {
1051-
skb_frag_t frags[MAX_SKB_FRAGS];
1052-
unsigned int nr_frags;
1053-
unsigned int ip_summed;
1054-
unsigned int len;
1055-
__wsum csum;
1056-
};
1057-
10581050
#include <linux/interrupt.h>
10591051
#include <linux/notifier.h>
10601052

@@ -1442,12 +1434,18 @@ extern int napi_gro_receive(struct napi_struct *napi,
14421434
struct sk_buff *skb);
14431435
extern void napi_reuse_skb(struct napi_struct *napi,
14441436
struct sk_buff *skb);
1445-
extern struct sk_buff * napi_fraginfo_skb(struct napi_struct *napi,
1446-
struct napi_gro_fraginfo *info);
1437+
extern struct sk_buff * napi_get_frags(struct napi_struct *napi);
14471438
extern int napi_frags_finish(struct napi_struct *napi,
14481439
struct sk_buff *skb, int ret);
1449-
extern int napi_gro_frags(struct napi_struct *napi,
1450-
struct napi_gro_fraginfo *info);
1440+
extern struct sk_buff * napi_frags_skb(struct napi_struct *napi);
1441+
extern int napi_gro_frags(struct napi_struct *napi);
1442+
1443+
static inline void napi_free_frags(struct napi_struct *napi)
1444+
{
1445+
kfree_skb(napi->skb);
1446+
napi->skb = NULL;
1447+
}
1448+
14511449
extern void netif_nit_deliver(struct sk_buff *skb);
14521450
extern int dev_valid_name(const char *name);
14531451
extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *);

net/8021q/vlan_core.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
114114
EXPORT_SYMBOL(vlan_gro_receive);
115115

116116
int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
117-
unsigned int vlan_tci, struct napi_gro_fraginfo *info)
117+
unsigned int vlan_tci)
118118
{
119-
struct sk_buff *skb = napi_fraginfo_skb(napi, info);
119+
struct sk_buff *skb = napi_frags_skb(napi);
120120

121121
if (!skb)
122122
return NET_RX_DROP;

net/core/dev.c

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,64 +2519,25 @@ void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
25192519
}
25202520
EXPORT_SYMBOL(napi_reuse_skb);
25212521

2522-
struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi,
2523-
struct napi_gro_fraginfo *info)
2522+
struct sk_buff *napi_get_frags(struct napi_struct *napi)
25242523
{
25252524
struct net_device *dev = napi->dev;
25262525
struct sk_buff *skb = napi->skb;
2527-
struct ethhdr *eth;
2528-
skb_frag_t *frag;
2529-
int i;
2530-
2531-
napi->skb = NULL;
25322526

25332527
if (!skb) {
25342528
skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN);
25352529
if (!skb)
25362530
goto out;
25372531

25382532
skb_reserve(skb, NET_IP_ALIGN);
2539-
}
2540-
2541-
BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
2542-
frag = &info->frags[info->nr_frags - 1];
25432533

2544-
for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) {
2545-
skb_fill_page_desc(skb, i, frag->page, frag->page_offset,
2546-
frag->size);
2547-
frag++;
2534+
napi->skb = skb;
25482535
}
2549-
skb_shinfo(skb)->nr_frags = info->nr_frags;
2550-
2551-
skb->data_len = info->len;
2552-
skb->len += info->len;
2553-
skb->truesize += info->len;
2554-
2555-
skb_reset_mac_header(skb);
2556-
skb_gro_reset_offset(skb);
2557-
2558-
eth = skb_gro_header(skb, sizeof(*eth));
2559-
if (!eth) {
2560-
napi_reuse_skb(napi, skb);
2561-
skb = NULL;
2562-
goto out;
2563-
}
2564-
2565-
skb_gro_pull(skb, sizeof(*eth));
2566-
2567-
/*
2568-
* This works because the only protocols we care about don't require
2569-
* special handling. We'll fix it up properly at the end.
2570-
*/
2571-
skb->protocol = eth->h_proto;
2572-
2573-
skb->ip_summed = info->ip_summed;
2574-
skb->csum = info->csum;
25752536

25762537
out:
25772538
return skb;
25782539
}
2579-
EXPORT_SYMBOL(napi_fraginfo_skb);
2540+
EXPORT_SYMBOL(napi_get_frags);
25802541

25812542
int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
25822543
{
@@ -2606,9 +2567,39 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
26062567
}
26072568
EXPORT_SYMBOL(napi_frags_finish);
26082569

2609-
int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
2570+
struct sk_buff *napi_frags_skb(struct napi_struct *napi)
2571+
{
2572+
struct sk_buff *skb = napi->skb;
2573+
struct ethhdr *eth;
2574+
2575+
napi->skb = NULL;
2576+
2577+
skb_reset_mac_header(skb);
2578+
skb_gro_reset_offset(skb);
2579+
2580+
eth = skb_gro_header(skb, sizeof(*eth));
2581+
if (!eth) {
2582+
napi_reuse_skb(napi, skb);
2583+
skb = NULL;
2584+
goto out;
2585+
}
2586+
2587+
skb_gro_pull(skb, sizeof(*eth));
2588+
2589+
/*
2590+
* This works because the only protocols we care about don't require
2591+
* special handling. We'll fix it up properly at the end.
2592+
*/
2593+
skb->protocol = eth->h_proto;
2594+
2595+
out:
2596+
return skb;
2597+
}
2598+
EXPORT_SYMBOL(napi_frags_skb);
2599+
2600+
int napi_gro_frags(struct napi_struct *napi)
26102601
{
2611-
struct sk_buff *skb = napi_fraginfo_skb(napi, info);
2602+
struct sk_buff *skb = napi_frags_skb(napi);
26122603

26132604
if (!skb)
26142605
return NET_RX_DROP;
@@ -2712,7 +2703,7 @@ void netif_napi_del(struct napi_struct *napi)
27122703
struct sk_buff *skb, *next;
27132704

27142705
list_del_init(&napi->dev_list);
2715-
kfree_skb(napi->skb);
2706+
napi_free_frags(napi);
27162707

27172708
for (skb = napi->gro_list; skb; skb = next) {
27182709
next = skb->next;

0 commit comments

Comments
 (0)