diff options
| author | Daniel Borkmann <dborkman@redhat.com> | 2013-07-01 13:24:00 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-07-03 17:37:39 -0400 |
| commit | c50cd357887acf9fd7af3a5d492911bd825555a2 (patch) | |
| tree | 8b2c00e46461e9959b4ecc339d8fcdef1ca69f03 | |
| parent | 419076f59fc5916bd200b45225c83437b37ab189 (diff) | |
net: gre: move GSO functions to gre_offload
Similarly to TCP/UDP offloading, move all related GRE functions to
gre_offload.c to make things more explicit and similar to the rest
of the code.
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/gre.h | 4 | ||||
| -rw-r--r-- | net/ipv4/Makefile | 1 | ||||
| -rw-r--r-- | net/ipv4/gre_demux.c (renamed from net/ipv4/gre.c) | 106 | ||||
| -rw-r--r-- | net/ipv4/gre_offload.c | 127 |
4 files changed, 135 insertions, 103 deletions
diff --git a/include/net/gre.h b/include/net/gre.h index a5a4ddf05300..57e4afdf7879 100644 --- a/include/net/gre.h +++ b/include/net/gre.h | |||
| @@ -32,6 +32,10 @@ struct gre_cisco_protocol { | |||
| 32 | 32 | ||
| 33 | int gre_cisco_register(struct gre_cisco_protocol *proto); | 33 | int gre_cisco_register(struct gre_cisco_protocol *proto); |
| 34 | int gre_cisco_unregister(struct gre_cisco_protocol *proto); | 34 | int gre_cisco_unregister(struct gre_cisco_protocol *proto); |
| 35 | |||
| 36 | int gre_offload_init(void); | ||
| 37 | void gre_offload_exit(void); | ||
| 38 | |||
| 35 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, | 39 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, |
| 36 | int hdr_len); | 40 | int hdr_len); |
| 37 | struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum); | 41 | struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum); |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 86ded0bac9c7..4b81e91c80fe 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
| @@ -19,6 +19,7 @@ obj-$(CONFIG_PROC_FS) += proc.o | |||
| 19 | obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o | 19 | obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o |
| 20 | obj-$(CONFIG_IP_MROUTE) += ipmr.o | 20 | obj-$(CONFIG_IP_MROUTE) += ipmr.o |
| 21 | obj-$(CONFIG_NET_IPIP) += ipip.o | 21 | obj-$(CONFIG_NET_IPIP) += ipip.o |
| 22 | gre-y := gre_demux.o gre_offload.o | ||
| 22 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o | 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o |
| 23 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o | 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o |
| 24 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o | 25 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o |
diff --git a/net/ipv4/gre.c b/net/ipv4/gre_demux.c index ba4803e609b5..736c9fc3ef93 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre_demux.c | |||
| @@ -334,113 +334,12 @@ static void gre_err(struct sk_buff *skb, u32 info) | |||
| 334 | rcu_read_unlock(); | 334 | rcu_read_unlock(); |
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | ||
| 338 | netdev_features_t features) | ||
| 339 | { | ||
| 340 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 341 | netdev_features_t enc_features; | ||
| 342 | int ghl = GRE_HEADER_SECTION; | ||
| 343 | struct gre_base_hdr *greh; | ||
| 344 | int mac_len = skb->mac_len; | ||
| 345 | __be16 protocol = skb->protocol; | ||
| 346 | int tnl_hlen; | ||
| 347 | bool csum; | ||
| 348 | |||
| 349 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
| 350 | ~(SKB_GSO_TCPV4 | | ||
| 351 | SKB_GSO_TCPV6 | | ||
| 352 | SKB_GSO_UDP | | ||
| 353 | SKB_GSO_DODGY | | ||
| 354 | SKB_GSO_TCP_ECN | | ||
| 355 | SKB_GSO_GRE))) | ||
| 356 | goto out; | ||
| 357 | |||
| 358 | if (unlikely(!pskb_may_pull(skb, sizeof(*greh)))) | ||
| 359 | goto out; | ||
| 360 | |||
| 361 | greh = (struct gre_base_hdr *)skb_transport_header(skb); | ||
| 362 | |||
| 363 | if (greh->flags & GRE_KEY) | ||
| 364 | ghl += GRE_HEADER_SECTION; | ||
| 365 | if (greh->flags & GRE_SEQ) | ||
| 366 | ghl += GRE_HEADER_SECTION; | ||
| 367 | if (greh->flags & GRE_CSUM) { | ||
| 368 | ghl += GRE_HEADER_SECTION; | ||
| 369 | csum = true; | ||
| 370 | } else | ||
| 371 | csum = false; | ||
| 372 | |||
| 373 | /* setup inner skb. */ | ||
| 374 | skb->protocol = greh->protocol; | ||
| 375 | skb->encapsulation = 0; | ||
| 376 | |||
| 377 | if (unlikely(!pskb_may_pull(skb, ghl))) | ||
| 378 | goto out; | ||
| 379 | __skb_pull(skb, ghl); | ||
| 380 | skb_reset_mac_header(skb); | ||
| 381 | skb_set_network_header(skb, skb_inner_network_offset(skb)); | ||
| 382 | skb->mac_len = skb_inner_network_offset(skb); | ||
| 383 | |||
| 384 | /* segment inner packet. */ | ||
| 385 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
| 386 | segs = skb_mac_gso_segment(skb, enc_features); | ||
| 387 | if (!segs || IS_ERR(segs)) | ||
| 388 | goto out; | ||
| 389 | |||
| 390 | skb = segs; | ||
| 391 | tnl_hlen = skb_tnl_header_len(skb); | ||
| 392 | do { | ||
| 393 | __skb_push(skb, ghl); | ||
| 394 | if (csum) { | ||
| 395 | __be32 *pcsum; | ||
| 396 | |||
| 397 | if (skb_has_shared_frag(skb)) { | ||
| 398 | int err; | ||
| 399 | |||
| 400 | err = __skb_linearize(skb); | ||
| 401 | if (err) { | ||
| 402 | kfree_skb(segs); | ||
| 403 | segs = ERR_PTR(err); | ||
| 404 | goto out; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 408 | greh = (struct gre_base_hdr *)(skb->data); | ||
| 409 | pcsum = (__be32 *)(greh + 1); | ||
| 410 | *pcsum = 0; | ||
| 411 | *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0)); | ||
| 412 | } | ||
| 413 | __skb_push(skb, tnl_hlen - ghl); | ||
| 414 | |||
| 415 | skb_reset_mac_header(skb); | ||
| 416 | skb_set_network_header(skb, mac_len); | ||
| 417 | skb->mac_len = mac_len; | ||
| 418 | skb->protocol = protocol; | ||
| 419 | } while ((skb = skb->next)); | ||
| 420 | out: | ||
| 421 | return segs; | ||
| 422 | } | ||
| 423 | |||
| 424 | static int gre_gso_send_check(struct sk_buff *skb) | ||
| 425 | { | ||
| 426 | if (!skb->encapsulation) | ||
| 427 | return -EINVAL; | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | static const struct net_protocol net_gre_protocol = { | 337 | static const struct net_protocol net_gre_protocol = { |
| 432 | .handler = gre_rcv, | 338 | .handler = gre_rcv, |
| 433 | .err_handler = gre_err, | 339 | .err_handler = gre_err, |
| 434 | .netns_ok = 1, | 340 | .netns_ok = 1, |
| 435 | }; | 341 | }; |
| 436 | 342 | ||
| 437 | static const struct net_offload gre_offload = { | ||
| 438 | .callbacks = { | ||
| 439 | .gso_send_check = gre_gso_send_check, | ||
| 440 | .gso_segment = gre_gso_segment, | ||
| 441 | }, | ||
| 442 | }; | ||
| 443 | |||
| 444 | static const struct gre_protocol ipgre_protocol = { | 343 | static const struct gre_protocol ipgre_protocol = { |
| 445 | .handler = gre_cisco_rcv, | 344 | .handler = gre_cisco_rcv, |
| 446 | .err_handler = gre_cisco_err, | 345 | .err_handler = gre_cisco_err, |
| @@ -485,7 +384,7 @@ static int __init gre_init(void) | |||
| 485 | goto err_gre; | 384 | goto err_gre; |
| 486 | } | 385 | } |
| 487 | 386 | ||
| 488 | if (inet_add_offload(&gre_offload, IPPROTO_GRE)) { | 387 | if (gre_offload_init()) { |
| 489 | pr_err("can't add protocol offload\n"); | 388 | pr_err("can't add protocol offload\n"); |
| 490 | goto err_gso; | 389 | goto err_gso; |
| 491 | } | 390 | } |
| @@ -501,7 +400,8 @@ err: | |||
| 501 | 400 | ||
| 502 | static void __exit gre_exit(void) | 401 | static void __exit gre_exit(void) |
| 503 | { | 402 | { |
| 504 | inet_del_offload(&gre_offload, IPPROTO_GRE); | 403 | gre_offload_exit(); |
| 404 | |||
| 505 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | 405 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); |
| 506 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 406 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); |
| 507 | } | 407 | } |
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c new file mode 100644 index 000000000000..a9d8cd2bff4b --- /dev/null +++ b/net/ipv4/gre_offload.c | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | /* | ||
| 2 | * IPV4 GSO/GRO offload support | ||
| 3 | * Linux INET implementation | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * GRE GSO support | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/skbuff.h> | ||
| 14 | #include <net/protocol.h> | ||
| 15 | #include <net/gre.h> | ||
| 16 | |||
| 17 | static int gre_gso_send_check(struct sk_buff *skb) | ||
| 18 | { | ||
| 19 | if (!skb->encapsulation) | ||
| 20 | return -EINVAL; | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | ||
| 25 | netdev_features_t features) | ||
| 26 | { | ||
| 27 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
| 28 | netdev_features_t enc_features; | ||
| 29 | int ghl = GRE_HEADER_SECTION; | ||
| 30 | struct gre_base_hdr *greh; | ||
| 31 | int mac_len = skb->mac_len; | ||
| 32 | __be16 protocol = skb->protocol; | ||
| 33 | int tnl_hlen; | ||
| 34 | bool csum; | ||
| 35 | |||
| 36 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
| 37 | ~(SKB_GSO_TCPV4 | | ||
| 38 | SKB_GSO_TCPV6 | | ||
| 39 | SKB_GSO_UDP | | ||
| 40 | SKB_GSO_DODGY | | ||
