diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2009-05-26 14:50:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-27 06:25:55 -0400 |
commit | 78a478d0efd9e86e5345b436e130497b4e5846e8 (patch) | |
tree | 273e7565811add8216267f5893335bdb7928a6b7 | |
parent | 42da6994ca6d20ad1d4e30255dee98047db454e7 (diff) |
gro: Inline skb_gro_header and cache frag0 virtual address
The function skb_gro_header is called four times per packet which
quickly adds up at 10Gb/s. This patch inlines it to allow better
optimisations.
Some architectures perform multiplication for page_address, which
is done by each skb_gro_header invocation. This patch caches that
value in skb->cb to avoid the unnecessary multiplications.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netdevice.h | 22 | ||||
-rw-r--r-- | net/core/dev.c | 27 |
2 files changed, 27 insertions, 22 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 586b71f0358c..61890ed0bcf2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1008,6 +1008,9 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi, | |||
1008 | void netif_napi_del(struct napi_struct *napi); | 1008 | void netif_napi_del(struct napi_struct *napi); |
1009 | 1009 | ||
1010 | struct napi_gro_cb { | 1010 | struct napi_gro_cb { |
1011 | /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ | ||
1012 | void *frag0; | ||
1013 | |||
1011 | /* This indicates where we are processing relative to skb->data. */ | 1014 | /* This indicates where we are processing relative to skb->data. */ |
1012 | int data_offset; | 1015 | int data_offset; |
1013 | 1016 | ||
@@ -1107,9 +1110,9 @@ extern int dev_restart(struct net_device *dev); | |||
1107 | #ifdef CONFIG_NETPOLL_TRAP | 1110 | #ifdef CONFIG_NETPOLL_TRAP |
1108 | extern int netpoll_trap(void); | 1111 | extern int netpoll_trap(void); |
1109 | #endif | 1112 | #endif |
1110 | extern void *skb_gro_header(struct sk_buff *skb, unsigned int hlen); | ||
1111 | extern int skb_gro_receive(struct sk_buff **head, | 1113 | extern int skb_gro_receive(struct sk_buff **head, |
1112 | struct sk_buff *skb); | 1114 | struct sk_buff *skb); |
1115 | extern void skb_gro_reset_offset(struct sk_buff *skb); | ||
1113 | 1116 | ||
1114 | static inline unsigned int skb_gro_offset(const struct sk_buff *skb) | 1117 | static inline unsigned int skb_gro_offset(const struct sk_buff *skb) |
1115 | { | 1118 | { |
@@ -1126,23 +1129,28 @@ static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len) | |||
1126 | NAPI_GRO_CB(skb)->data_offset += len; | 1129 | NAPI_GRO_CB(skb)->data_offset += len; |
1127 | } | 1130 | } |
1128 | 1131 | ||
1129 | static inline void skb_gro_reset_offset(struct sk_buff *skb) | 1132 | static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) |
1130 | { | 1133 | { |
1131 | NAPI_GRO_CB(skb)->data_offset = 0; | 1134 | unsigned int offset = skb_gro_offset(skb); |
1135 | |||
1136 | hlen += offset; | ||
1137 | if (!NAPI_GRO_CB(skb)->frag0 || | ||
1138 | unlikely(skb_shinfo(skb)->frags[0].size + skb_headlen(skb) < hlen)) | ||
1139 | return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; | ||
1140 | |||
1141 | return NAPI_GRO_CB(skb)->frag0 + offset; | ||
1132 | } | 1142 | } |
1133 | 1143 | ||
1134 | static inline void *skb_gro_mac_header(struct sk_buff *skb) | 1144 | static inline void *skb_gro_mac_header(struct sk_buff *skb) |
1135 | { | 1145 | { |
1136 | return skb_headlen(skb) ? skb_mac_header(skb) : | 1146 | return skb_headlen(skb) ? skb_mac_header(skb) : |
1137 | page_address(skb_shinfo(skb)->frags[0].page) + | 1147 | NAPI_GRO_CB(skb)->frag0; |
1138 | skb_shinfo(skb)->frags[0].page_offset; | ||
1139 | } | 1148 | } |
1140 | 1149 | ||
1141 | static inline void *skb_gro_network_header(struct sk_buff *skb) | 1150 | static inline void *skb_gro_network_header(struct sk_buff *skb) |
1142 | { | 1151 | { |
1143 | return skb_headlen(skb) ? skb_network_header(skb) : | 1152 | return skb_headlen(skb) ? skb_network_header(skb) : |
1144 | page_address(skb_shinfo(skb)->frags[0].page) + | 1153 | NAPI_GRO_CB(skb)->frag0 + skb_network_offset(skb); |
1145 | skb_shinfo(skb)->frags[0].page_offset + skb_network_offset(skb); | ||
1146 | } | 1154 | } |
1147 | 1155 | ||
1148 | static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, | 1156 | static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, |
diff --git a/net/core/dev.c b/net/core/dev.c index 5eb3e48ab31d..bdb1a738193d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2390,21 +2390,6 @@ void napi_gro_flush(struct napi_struct *napi) | |||
2390 | } | 2390 | } |
2391 | EXPORT_SYMBOL(napi_gro_flush); | 2391 | EXPORT_SYMBOL(napi_gro_flush); |
2392 | 2392 | ||
2393 | void *skb_gro_header(struct sk_buff *skb, unsigned int hlen) | ||
2394 | { | ||
2395 | unsigned int offset = skb_gro_offset(skb); | ||
2396 | |||
2397 | hlen += offset; | ||
2398 | if (unlikely(skb_headlen(skb) || | ||
2399 | skb_shinfo(skb)->frags[0].size < hlen || | ||
2400 | PageHighMem(skb_shinfo(skb)->frags[0].page))) | ||
2401 | return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL; | ||
2402 | |||
2403 | return page_address(skb_shinfo(skb)->frags[0].page) + | ||
2404 | skb_shinfo(skb)->frags[0].page_offset + offset; | ||
2405 | } | ||
2406 | EXPORT_SYMBOL(skb_gro_header); | ||
2407 | |||
2408 | int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 2393 | int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
2409 | { | 2394 | { |
2410 | struct sk_buff **pp = NULL; | 2395 | struct sk_buff **pp = NULL; |
@@ -2520,6 +2505,18 @@ int napi_skb_finish(int ret, struct sk_buff *skb) | |||
2520 | } | 2505 | } |
2521 | EXPORT_SYMBOL(napi_skb_finish); | 2506 | EXPORT_SYMBOL(napi_skb_finish); |
2522 | 2507 | ||
2508 | void skb_gro_reset_offset(struct sk_buff *skb) | ||
2509 | { | ||
2510 | NAPI_GRO_CB(skb)->data_offset = 0; | ||
2511 | NAPI_GRO_CB(skb)->frag0 = NULL; | ||
2512 | |||
2513 | if (!skb_headlen(skb) && !PageHighMem(skb_shinfo(skb)->frags[0].page)) | ||
2514 | NAPI_GRO_CB(skb)->frag0 = | ||
2515 | page_address(skb_shinfo(skb)->frags[0].page) + | ||
2516 | skb_shinfo(skb)->frags[0].page_offset; | ||
2517 | } | ||
2518 | EXPORT_SYMBOL(skb_gro_reset_offset); | ||
2519 | |||
2523 | int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 2520 | int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
2524 | { | 2521 | { |
2525 | skb_gro_reset_offset(skb); | 2522 | skb_gro_reset_offset(skb); |