aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index de2bad717d56..d44668f63c88 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3471,17 +3471,31 @@ out:
3471 return netif_receive_skb(skb); 3471 return netif_receive_skb(skb);
3472} 3472}
3473 3473
3474inline void napi_gro_flush(struct napi_struct *napi) 3474/* napi->gro_list contains packets ordered by age.
3475 * youngest packets at the head of it.
3476 * Complete skbs in reverse order to reduce latencies.
3477 */
3478void napi_gro_flush(struct napi_struct *napi, bool flush_old)
3475{ 3479{
3476 struct sk_buff *skb, *next; 3480 struct sk_buff *skb, *prev = NULL;
3477 3481
3478 for (skb = napi->gro_list; skb; skb = next) { 3482 /* scan list and build reverse chain */
3479 next = skb->next; 3483 for (skb = napi->gro_list; skb != NULL; skb = skb->next) {
3484 skb->prev = prev;
3485 prev = skb;
3486 }
3487
3488 for (skb = prev; skb; skb = prev) {
3480 skb->next = NULL; 3489 skb->next = NULL;
3490
3491 if (flush_old && NAPI_GRO_CB(skb)->age == jiffies)
3492 return;
3493
3494 prev = skb->prev;
3481 napi_gro_complete(skb); 3495 napi_gro_complete(skb);
3496 napi->gro_count--;
3482 } 3497 }
3483 3498
3484 napi->gro_count = 0;
3485 napi->gro_list = NULL; 3499 napi->gro_list = NULL;
3486} 3500}
3487EXPORT_SYMBOL(napi_gro_flush); 3501EXPORT_SYMBOL(napi_gro_flush);
@@ -3542,6 +3556,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
3542 3556
3543 napi->gro_count++; 3557 napi->gro_count++;
3544 NAPI_GRO_CB(skb)->count = 1; 3558 NAPI_GRO_CB(skb)->count = 1;
3559 NAPI_GRO_CB(skb)->age = jiffies;
3545 skb_shinfo(skb)->gso_size = skb_gro_len(skb); 3560 skb_shinfo(skb)->gso_size = skb_gro_len(skb);
3546 skb->next = napi->gro_list; 3561 skb->next = napi->gro_list;
3547 napi->gro_list = skb; 3562 napi->gro_list = skb;
@@ -3878,7 +3893,7 @@ void napi_complete(struct napi_struct *n)
3878 if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) 3893 if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state)))
3879 return; 3894 return;
3880 3895
3881 napi_gro_flush(n); 3896 napi_gro_flush(n, false);
3882 local_irq_save(flags); 3897 local_irq_save(flags);
3883 __napi_complete(n); 3898 __napi_complete(n);
3884 local_irq_restore(flags); 3899 local_irq_restore(flags);
@@ -3983,8 +3998,17 @@ static void net_rx_action(struct softirq_action *h)
3983 local_irq_enable(); 3998 local_irq_enable();
3984 napi_complete(n); 3999 napi_complete(n);
3985 local_irq_disable(); 4000 local_irq_disable();
3986 } else 4001 } else {
4002 if (n->gro_list) {
4003 /* flush too old packets
4004 * If HZ < 1000, flush all packets.
4005 */
4006 local_irq_enable();
4007 napi_gro_flush(n, HZ >= 1000);
4008 local_irq_disable();
4009 }
3987 list_move_tail(&n->poll_list, &sd->poll_list); 4010 list_move_tail(&n->poll_list, &sd->poll_list);
4011 }
3988 } 4012 }
3989 4013
3990 netpoll_poll_unlock(have); 4014 netpoll_poll_unlock(have);