diff options
| author | Li RongQing <lirongqing@baidu.com> | 2018-07-05 02:34:32 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2018-07-05 06:20:16 -0400 |
| commit | 6312fe77751f57d4fa2b28abeef84c6a95c28136 (patch) | |
| tree | bc8b1e2befbb98f1015785646f48e5f4172caebe /net/core/dev.c | |
| parent | 6fcf9b1d4d6cd38202247de5c0ac7d85c4483abb (diff) | |
net: limit each hash list length to MAX_GRO_SKBS
After commit 07d78363dcff ("net: Convert NAPI gro list into a small hash
table.")' there is 8 hash buckets, which allows more flows to be held for
merging. but MAX_GRO_SKBS, the total held skb for merging, is 8 skb still,
limit the hash table performance.
keep MAX_GRO_SKBS as 8 skb, but limit each hash list length to 8 skb, not
the total 8 skb
Signed-off-by: Li RongQing <lirongqing@baidu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 56 |
1 files changed, 23 insertions, 33 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 7e6a2f66db5c..89825c1eccdc 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -149,7 +149,6 @@ | |||
| 149 | 149 | ||
| 150 | #include "net-sysfs.h" | 150 | #include "net-sysfs.h" |
| 151 | 151 | ||
| 152 | /* Instead of increasing this, you should create a hash table. */ | ||
| 153 | #define MAX_GRO_SKBS 8 | 152 | #define MAX_GRO_SKBS 8 |
| 154 | 153 | ||
| 155 | /* This should be increased if a protocol with a bigger head is added. */ | 154 | /* This should be increased if a protocol with a bigger head is added. */ |
| @@ -5151,9 +5150,10 @@ out: | |||
| 5151 | return netif_receive_skb_internal(skb); | 5150 | return netif_receive_skb_internal(skb); |
| 5152 | } | 5151 | } |
| 5153 | 5152 | ||
| 5154 | static void __napi_gro_flush_chain(struct napi_struct *napi, struct list_head *head, | 5153 | static void __napi_gro_flush_chain(struct napi_struct *napi, u32 index, |
| 5155 | bool flush_old) | 5154 | bool flush_old) |
| 5156 | { | 5155 | { |
| 5156 | struct list_head *head = &napi->gro_hash[index].list; | ||
| 5157 | struct sk_buff *skb, *p; | 5157 | struct sk_buff *skb, *p; |
| 5158 | 5158 | ||
| 5159 | list_for_each_entry_safe_reverse(skb, p, head, list) { | 5159 | list_for_each_entry_safe_reverse(skb, p, head, list) { |
| @@ -5162,22 +5162,20 @@ static void __napi_gro_flush_chain(struct napi_struct *napi, struct list_head *h | |||
| 5162 | list_del_init(&skb->list); | 5162 | list_del_init(&skb->list); |
| 5163 | napi_gro_complete(skb); | 5163 | napi_gro_complete(skb); |
| 5164 | napi->gro_count--; | 5164 | napi->gro_count--; |
| 5165 | napi->gro_hash[index].count--; | ||
| 5165 | } | 5166 | } |
| 5166 | } | 5167 | } |
| 5167 | 5168 | ||
| 5168 | /* napi->gro_hash contains packets ordered by age. | 5169 | /* napi->gro_hash[].list contains packets ordered by age. |
| 5169 | * youngest packets at the head of it. | 5170 | * youngest packets at the head of it. |
| 5170 | * Complete skbs in reverse order to reduce latencies. | 5171 | * Complete skbs in reverse order to reduce latencies. |
| 5171 | */ | 5172 | */ |
| 5172 | void napi_gro_flush(struct napi_struct *napi, bool flush_old) | 5173 | void napi_gro_flush(struct napi_struct *napi, bool flush_old) |
| 5173 | { | 5174 | { |
| 5174 | int i; | 5175 | u32 i; |
| 5175 | |||
| 5176 | for (i = 0; i < GRO_HASH_BUCKETS; i++) { | ||
| 5177 | struct list_head *head = &napi->gro_hash[i]; | ||
| 5178 | 5176 | ||
| 5179 | __napi_gro_flush_chain(napi, head, flush_old); | 5177 | for (i = 0; i < GRO_HASH_BUCKETS; i++) |
| 5180 | } | 5178 | __napi_gro_flush_chain(napi, i, flush_old); |
| 5181 | } | 5179 | } |
| 5182 | EXPORT_SYMBOL(napi_gro_flush); | 5180 | EXPORT_SYMBOL(napi_gro_flush); |
| 5183 | 5181 | ||
| @@ -5189,7 +5187,7 @@ static struct list_head *gro_list_prepare(struct napi_struct *napi, | |||
| 5189 | struct list_head *head; | 5187 | struct list_head *head; |
| 5190 | struct sk_buff *p; | 5188 | struct sk_buff *p; |
| 5191 | 5189 | ||
| 5192 | head = &napi->gro_hash[hash & (GRO_HASH_BUCKETS - 1)]; | 5190 | head = &napi->gro_hash[hash & (GRO_HASH_BUCKETS - 1)].list; |
| 5193 | list_for_each_entry(p, head, list) { | 5191 | list_for_each_entry(p, head, list) { |
| 5194 | unsigned long diffs; | 5192 | unsigned long diffs; |
| 5195 | 5193 | ||
| @@ -5257,27 +5255,13 @@ static void gro_pull_from_frag0(struct sk_buff *skb, int grow) | |||
| 5257 | } | 5255 | } |
| 5258 | } | 5256 | } |
| 5259 | 5257 | ||
| 5260 | static void gro_flush_oldest(struct napi_struct *napi) | 5258 | static void gro_flush_oldest(struct list_head *head) |
| 5261 | { | 5259 | { |
| 5262 | struct sk_buff *oldest = NULL; | 5260 | struct sk_buff *oldest; |
| 5263 | unsigned long age = jiffies; | ||
| 5264 | int i; | ||
| 5265 | |||
| 5266 | for (i = 0; i < GRO_HASH_BUCKETS; i++) { | ||
| 5267 | struct list_head *head = &napi->gro_hash[i]; | ||
| 5268 | struct sk_buff *skb; | ||
| 5269 | |||
| 5270 | if (list_empty(head)) | ||
| 5271 | continue; | ||
| 5272 | 5261 | ||
| 5273 | skb = list_last_entry(head, struct sk_buff, list); | 5262 | oldest = list_last_entry(head, struct sk_buff, list); |
| 5274 | if (!oldest || time_before(NAPI_GRO_CB(skb)->age, age)) { | ||
| 5275 | oldest = skb; | ||
| 5276 | age = NAPI_GRO_CB(skb)->age; | ||
| 5277 | } | ||
| 5278 | } | ||
| 5279 | 5263 | ||
| 5280 | /* We are called with napi->gro_count >= MAX_GRO_SKBS, so this is | 5264 | /* We are called with head length >= MAX_GRO_SKBS, so this is |
| 5281 | * impossible. | 5265 | * impossible. |
| 5282 | */ | 5266 | */ |
| 5283 | if (WARN_ON_ONCE(!oldest)) | 5267 | if (WARN_ON_ONCE(!oldest)) |
| @@ -5292,6 +5276,7 @@ static void gro_flush_oldest(struct napi_struct *napi) | |||
| 5292 | 5276 | ||
| 5293 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 5277 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
| 5294 | { | 5278 | { |
| 5279 | u32 hash = skb_get_hash_raw(skb) & (GRO_HASH_BUCKETS - 1); | ||
| 5295 | struct list_head *head = &offload_base; | 5280 | struct list_head *head = &offload_base; |
| 5296 | struct packet_offload *ptype; | 5281 | struct packet_offload *ptype; |
| 5297 | __be16 type = skb->protocol; | 5282 | __be16 type = skb->protocol; |
| @@ -5358,6 +5343,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
| 5358 | list_del_init(&pp->list); | 5343 | list_del_init(&pp->list); |
| 5359 | napi_gro_complete(pp); | 5344 | napi_gro_complete(pp); |
| 5360 | napi->gro_count--; | 5345 | napi->gro_count--; |
| 5346 | napi->gro_hash[hash].count--; | ||
| 5361 | } | 5347 | } |
| 5362 | 5348 | ||
| 5363 | if (same_flow) | 5349 | if (same_flow) |
| @@ -5366,10 +5352,11 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
| 5366 | if (NAPI_GRO_CB(skb)->flush) | 5352 | if (NAPI_GRO_CB(skb)->flush) |
| 5367 | goto normal; | 5353 | goto normal; |
| 5368 | 5354 | ||
| 5369 | if (unlikely(napi->gro_count >= MAX_GRO_SKBS)) { | 5355 | if (unlikely(napi->gro_hash[hash].count >= MAX_GRO_SKBS)) { |
| 5370 | gro_flush_oldest(napi); | 5356 | gro_flush_oldest(gro_head); |
| 5371 | } else { | 5357 | } else { |
| 5372 | napi->gro_count++; | 5358 | napi->gro_count++; |
| 5359 | napi->gro_hash[hash].count++; | ||
| 5373 | } | 5360 | } |
| 5374 | NAPI_GRO_CB(skb)->count = 1; | 5361 | NAPI_GRO_CB(skb)->count = 1; |
| 5375 | NAPI_GRO_CB(skb)->age = jiffies; | 5362 | NAPI_GRO_CB(skb)->age = jiffies; |
| @@ -6006,8 +5993,10 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi, | |||
| 6006 | hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); | 5993 | hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); |
| 6007 | napi->timer.function = napi_watchdog; | 5994 | napi->timer.function = napi_watchdog; |
| 6008 | napi->gro_count = 0; | 5995 | napi->gro_count = 0; |
| 6009 | for (i = 0; i < GRO_HASH_BUCKETS; i++) | 5996 | for (i = 0; i < GRO_HASH_BUCKETS; i++) { |
| 6010 | INIT_LIST_HEAD(&napi->gro_hash[i]); | 5997 | INIT_LIST_HEAD(&napi->gro_hash[i].list); |
| 5998 | napi->gro_hash[i].count = 0; | ||
| 5999 | } | ||
| 6011 | napi->skb = NULL; | 6000 | napi->skb = NULL; |
| 6012 | napi->poll = poll; | 6001 | napi->poll = poll; |
| 6013 | if (weight > NAPI_POLL_WEIGHT) | 6002 | if (weight > NAPI_POLL_WEIGHT) |
| @@ -6047,8 +6036,9 @@ static void flush_gro_hash(struct napi_struct *napi) | |||
| 6047 | for (i = 0; i < GRO_HASH_BUCKETS; i++) { | 6036 | for (i = 0; i < GRO_HASH_BUCKETS; i++) { |
| 6048 | struct sk_buff *skb, *n; | 6037 | struct sk_buff *skb, *n; |
| 6049 | 6038 | ||
| 6050 | list_for_each_entry_safe(skb, n, &napi->gro_hash[i], list) | 6039 | list_for_each_entry_safe(skb, n, &napi->gro_hash[i].list, list) |
| 6051 | kfree_skb(skb); | 6040 | kfree_skb(skb); |
| 6041 | napi->gro_hash[i].count = 0; | ||
| 6052 | } | 6042 | } |
| 6053 | } | 6043 | } |
| 6054 | 6044 | ||
