diff options
author | Paolo Abeni <pabeni@redhat.com> | 2018-12-14 05:51:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-12-15 16:23:02 -0500 |
commit | aaa5d90b395a72faff797b00d815165ee0e664c0 (patch) | |
tree | 1200ce4b331921a7ae77964b525c4a3502b726a0 /net/core/dev.c | |
parent | 283c16a2dfd332bf5610c874f7b9f9c8b601ce53 (diff) |
net: use indirect call wrappers at GRO network layer
This avoids an indirect calls for L3 GRO receive path, both
for ipv4 and ipv6, if the latter is not compiled as a module.
Note that when IPv6 is compiled as builtin, it will be checked first,
so we have a single additional compare for the more common path.
v1 -> v2:
- adapted to INDIRECT_CALL_ changes
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index ed9aa4a91f1f..1b5a4410be0e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -145,6 +145,7 @@ | |||
145 | #include <linux/sctp.h> | 145 | #include <linux/sctp.h> |
146 | #include <net/udp_tunnel.h> | 146 | #include <net/udp_tunnel.h> |
147 | #include <linux/net_namespace.h> | 147 | #include <linux/net_namespace.h> |
148 | #include <linux/indirect_call_wrapper.h> | ||
148 | 149 | ||
149 | #include "net-sysfs.h" | 150 | #include "net-sysfs.h" |
150 | 151 | ||
@@ -5338,6 +5339,8 @@ static void flush_all_backlogs(void) | |||
5338 | put_online_cpus(); | 5339 | put_online_cpus(); |
5339 | } | 5340 | } |
5340 | 5341 | ||
5342 | INDIRECT_CALLABLE_DECLARE(int inet_gro_complete(struct sk_buff *, int)); | ||
5343 | INDIRECT_CALLABLE_DECLARE(int ipv6_gro_complete(struct sk_buff *, int)); | ||
5341 | static int napi_gro_complete(struct sk_buff *skb) | 5344 | static int napi_gro_complete(struct sk_buff *skb) |
5342 | { | 5345 | { |
5343 | struct packet_offload *ptype; | 5346 | struct packet_offload *ptype; |
@@ -5357,7 +5360,9 @@ static int napi_gro_complete(struct sk_buff *skb) | |||
5357 | if (ptype->type != type || !ptype->callbacks.gro_complete) | 5360 | if (ptype->type != type || !ptype->callbacks.gro_complete) |
5358 | continue; | 5361 | continue; |
5359 | 5362 | ||
5360 | err = ptype->callbacks.gro_complete(skb, 0); | 5363 | err = INDIRECT_CALL_INET(ptype->callbacks.gro_complete, |
5364 | ipv6_gro_complete, inet_gro_complete, | ||
5365 | skb, 0); | ||
5361 | break; | 5366 | break; |
5362 | } | 5367 | } |
5363 | rcu_read_unlock(); | 5368 | rcu_read_unlock(); |
@@ -5504,6 +5509,10 @@ static void gro_flush_oldest(struct list_head *head) | |||
5504 | napi_gro_complete(oldest); | 5509 | napi_gro_complete(oldest); |
5505 | } | 5510 | } |
5506 | 5511 | ||
5512 | INDIRECT_CALLABLE_DECLARE(struct sk_buff *inet_gro_receive(struct list_head *, | ||
5513 | struct sk_buff *)); | ||
5514 | INDIRECT_CALLABLE_DECLARE(struct sk_buff *ipv6_gro_receive(struct list_head *, | ||
5515 | struct sk_buff *)); | ||
5507 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 5516 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
5508 | { | 5517 | { |
5509 | u32 hash = skb_get_hash_raw(skb) & (GRO_HASH_BUCKETS - 1); | 5518 | u32 hash = skb_get_hash_raw(skb) & (GRO_HASH_BUCKETS - 1); |
@@ -5553,7 +5562,9 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
5553 | NAPI_GRO_CB(skb)->csum_valid = 0; | 5562 | NAPI_GRO_CB(skb)->csum_valid = 0; |
5554 | } | 5563 | } |
5555 | 5564 | ||
5556 | pp = ptype->callbacks.gro_receive(gro_head, skb); | 5565 | pp = INDIRECT_CALL_INET(ptype->callbacks.gro_receive, |
5566 | ipv6_gro_receive, inet_gro_receive, | ||
5567 | gro_head, skb); | ||
5557 | break; | 5568 | break; |
5558 | } | 5569 | } |
5559 | rcu_read_unlock(); | 5570 | rcu_read_unlock(); |