diff options
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 59 |
1 files changed, 44 insertions, 15 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 1e0a1847c3bb..09cb3f6dc40c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3300,18 +3300,18 @@ ncls: | |||
3300 | && !skb_pfmemalloc_protocol(skb)) | 3300 | && !skb_pfmemalloc_protocol(skb)) |
3301 | goto drop; | 3301 | goto drop; |
3302 | 3302 | ||
3303 | rx_handler = rcu_dereference(skb->dev->rx_handler); | ||
3304 | if (vlan_tx_tag_present(skb)) { | 3303 | if (vlan_tx_tag_present(skb)) { |
3305 | if (pt_prev) { | 3304 | if (pt_prev) { |
3306 | ret = deliver_skb(skb, pt_prev, orig_dev); | 3305 | ret = deliver_skb(skb, pt_prev, orig_dev); |
3307 | pt_prev = NULL; | 3306 | pt_prev = NULL; |
3308 | } | 3307 | } |
3309 | if (vlan_do_receive(&skb, !rx_handler)) | 3308 | if (vlan_do_receive(&skb)) |
3310 | goto another_round; | 3309 | goto another_round; |
3311 | else if (unlikely(!skb)) | 3310 | else if (unlikely(!skb)) |
3312 | goto unlock; | 3311 | goto unlock; |
3313 | } | 3312 | } |
3314 | 3313 | ||
3314 | rx_handler = rcu_dereference(skb->dev->rx_handler); | ||
3315 | if (rx_handler) { | 3315 | if (rx_handler) { |
3316 | if (pt_prev) { | 3316 | if (pt_prev) { |
3317 | ret = deliver_skb(skb, pt_prev, orig_dev); | 3317 | ret = deliver_skb(skb, pt_prev, orig_dev); |
@@ -3331,6 +3331,9 @@ ncls: | |||
3331 | } | 3331 | } |
3332 | } | 3332 | } |
3333 | 3333 | ||
3334 | if (vlan_tx_nonzero_tag_present(skb)) | ||
3335 | skb->pkt_type = PACKET_OTHERHOST; | ||
3336 | |||
3334 | /* deliver only exact match when indicated */ | 3337 | /* deliver only exact match when indicated */ |
3335 | null_or_dev = deliver_exact ? skb->dev : NULL; | 3338 | null_or_dev = deliver_exact ? skb->dev : NULL; |
3336 | 3339 | ||
@@ -3471,17 +3474,31 @@ out: | |||
3471 | return netif_receive_skb(skb); | 3474 | return netif_receive_skb(skb); |
3472 | } | 3475 | } |
3473 | 3476 | ||
3474 | inline void napi_gro_flush(struct napi_struct *napi) | 3477 | /* napi->gro_list contains packets ordered by age. |
3478 | * youngest packets at the head of it. | ||
3479 | * Complete skbs in reverse order to reduce latencies. | ||
3480 | */ | ||
3481 | void napi_gro_flush(struct napi_struct *napi, bool flush_old) | ||
3475 | { | 3482 | { |
3476 | struct sk_buff *skb, *next; | 3483 | struct sk_buff *skb, *prev = NULL; |
3477 | 3484 | ||
3478 | for (skb = napi->gro_list; skb; skb = next) { | 3485 | /* scan list and build reverse chain */ |
3479 | next = skb->next; | 3486 | for (skb = napi->gro_list; skb != NULL; skb = skb->next) { |
3487 | skb->prev = prev; | ||
3488 | prev = skb; | ||
3489 | } | ||
3490 | |||
3491 | for (skb = prev; skb; skb = prev) { | ||
3480 | skb->next = NULL; | 3492 | skb->next = NULL; |
3493 | |||
3494 | if (flush_old && NAPI_GRO_CB(skb)->age == jiffies) | ||
3495 | return; | ||
3496 | |||
3497 | prev = skb->prev; | ||
3481 | napi_gro_complete(skb); | 3498 | napi_gro_complete(skb); |
3499 | napi->gro_count--; | ||
3482 | } | 3500 | } |
3483 | 3501 | ||
3484 | napi->gro_count = 0; | ||
3485 | napi->gro_list = NULL; | 3502 | napi->gro_list = NULL; |
3486 | } | 3503 | } |
3487 | EXPORT_SYMBOL(napi_gro_flush); | 3504 | EXPORT_SYMBOL(napi_gro_flush); |
@@ -3542,6 +3559,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | |||
3542 | 3559 | ||
3543 | napi->gro_count++; | 3560 | napi->gro_count++; |
3544 | NAPI_GRO_CB(skb)->count = 1; | 3561 | NAPI_GRO_CB(skb)->count = 1; |
3562 | NAPI_GRO_CB(skb)->age = jiffies; | ||
3545 | skb_shinfo(skb)->gso_size = skb_gro_len(skb); | 3563 | skb_shinfo(skb)->gso_size = skb_gro_len(skb); |
3546 | skb->next = napi->gro_list; | 3564 | skb->next = napi->gro_list; |
3547 | napi->gro_list = skb; | 3565 | napi->gro_list = skb; |
@@ -3631,20 +3649,22 @@ gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) | |||
3631 | } | 3649 | } |
3632 | EXPORT_SYMBOL(napi_skb_finish); | 3650 | EXPORT_SYMBOL(napi_skb_finish); |
3633 | 3651 | ||
3634 | void skb_gro_reset_offset(struct sk_buff *skb) | 3652 | static void skb_gro_reset_offset(struct sk_buff *skb) |
3635 | { | 3653 | { |
3654 | const struct skb_shared_info *pinfo = skb_shinfo(skb); | ||
3655 | const skb_frag_t *frag0 = &pinfo->frags[0]; | ||
3656 | |||
3636 | NAPI_GRO_CB(skb)->data_offset = 0; | 3657 | NAPI_GRO_CB(skb)->data_offset = 0; |
3637 | NAPI_GRO_CB(skb)->frag0 = NULL; | 3658 | NAPI_GRO_CB(skb)->frag0 = NULL; |
3638 | NAPI_GRO_CB(skb)->frag0_len = 0; | 3659 | NAPI_GRO_CB(skb)->frag0_len = 0; |
3639 | 3660 | ||
3640 | if (skb->mac_header == skb->tail && | 3661 | if (skb->mac_header == skb->tail && |
3641 | !PageHighMem(skb_frag_page(&skb_shinfo(skb)->frags[0]))) { | 3662 | pinfo->nr_frags && |
3642 | NAPI_GRO_CB(skb)->frag0 = | 3663 | !PageHighMem(skb_frag_page(frag0))) { |
3643 | skb_frag_address(&skb_shinfo(skb)->frags[0]); | 3664 | NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); |
3644 | NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(&skb_shinfo(skb)->frags[0]); | 3665 | NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0); |
3645 | } | 3666 | } |
3646 | } | 3667 | } |
3647 | EXPORT_SYMBOL(skb_gro_reset_offset); | ||
3648 | 3668 | ||
3649 | gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 3669 | gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
3650 | { | 3670 | { |
@@ -3876,7 +3896,7 @@ void napi_complete(struct napi_struct *n) | |||
3876 | if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) | 3896 | if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) |
3877 | return; | 3897 | return; |
3878 | 3898 | ||
3879 | napi_gro_flush(n); | 3899 | napi_gro_flush(n, false); |
3880 | local_irq_save(flags); | 3900 | local_irq_save(flags); |
3881 | __napi_complete(n); | 3901 | __napi_complete(n); |
3882 | local_irq_restore(flags); | 3902 | local_irq_restore(flags); |
@@ -3981,8 +4001,17 @@ static void net_rx_action(struct softirq_action *h) | |||
3981 | local_irq_enable(); | 4001 | local_irq_enable(); |
3982 | napi_complete(n); | 4002 | napi_complete(n); |
3983 | local_irq_disable(); | 4003 | local_irq_disable(); |
3984 | } else | 4004 | } else { |
4005 | if (n->gro_list) { | ||
4006 | /* flush too old packets | ||
4007 | * If HZ < 1000, flush all packets. | ||
4008 | */ | ||
4009 | local_irq_enable(); | ||
4010 | napi_gro_flush(n, HZ >= 1000); | ||
4011 | local_irq_disable(); | ||
4012 | } | ||
3985 | list_move_tail(&n->poll_list, &sd->poll_list); | 4013 | list_move_tail(&n->poll_list, &sd->poll_list); |
4014 | } | ||
3986 | } | 4015 | } |
3987 | 4016 | ||
3988 | netpoll_poll_unlock(have); | 4017 | netpoll_poll_unlock(have); |