diff options
| author | Jesse Gross <jesse@nicira.com> | 2014-12-30 22:10:15 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-01-02 15:46:41 -0500 |
| commit | 9b174d88c257150562b0101fcc6cb6c3cb74275c (patch) | |
| tree | 345b03321802cb222991d9c3a524064eadbb54ad /net/ethernet | |
| parent | 05930b5ec1d3b2a5c76e1959b54cae15587009c7 (diff) | |
net: Add Transparent Ethernet Bridging GRO support.
Currently the only tunnel protocol that supports GRO with encapsulated
Ethernet is VXLAN. This pulls out the Ethernet code into a proper layer
so that it can be used by other tunnel protocols such as GRE and Geneve.
Signed-off-by: Jesse Gross <jesse@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ethernet')
| -rw-r--r-- | net/ethernet/eth.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 33a140e15834..238f38d21641 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
| @@ -424,3 +424,95 @@ ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) | |||
| 424 | return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr); | 424 | return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr); |
| 425 | } | 425 | } |
| 426 | EXPORT_SYMBOL(sysfs_format_mac); | 426 | EXPORT_SYMBOL(sysfs_format_mac); |
| 427 | |||
| 428 | struct sk_buff **eth_gro_receive(struct sk_buff **head, | ||
| 429 | struct sk_buff *skb) | ||
| 430 | { | ||
| 431 | struct sk_buff *p, **pp = NULL; | ||
| 432 | struct ethhdr *eh, *eh2; | ||
| 433 | unsigned int hlen, off_eth; | ||
| 434 | const struct packet_offload *ptype; | ||
| 435 | __be16 type; | ||
| 436 | int flush = 1; | ||
| 437 | |||
| 438 | off_eth = skb_gro_offset(skb); | ||
| 439 | hlen = off_eth + sizeof(*eh); | ||
| 440 | eh = skb_gro_header_fast(skb, off_eth); | ||
| 441 | if (skb_gro_header_hard(skb, hlen)) { | ||
| 442 | eh = skb_gro_header_slow(skb, hlen, off_eth); | ||
| 443 | if (unlikely(!eh)) | ||
| 444 | goto out; | ||
| 445 | } | ||
| 446 | |||
| 447 | flush = 0; | ||
| 448 | |||
| 449 | for (p = *head; p; p = p->next) { | ||
| 450 | if (!NAPI_GRO_CB(p)->same_flow) | ||
| 451 | continue; | ||
| 452 | |||
| 453 | eh2 = (struct ethhdr *)(p->data + off_eth); | ||
| 454 | if (compare_ether_header(eh, eh2)) { | ||
| 455 | NAPI_GRO_CB(p)->same_flow = 0; | ||
| 456 | continue; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | type = eh->h_proto; | ||
| 461 | |||
| 462 | rcu_read_lock(); | ||
| 463 | ptype = gro_find_receive_by_type(type); | ||
| 464 | if (ptype == NULL) { | ||
| 465 | flush = 1; | ||
| 466 | goto out_unlock; | ||
| 467 | } | ||
| 468 | |||
| 469 | skb_gro_pull(skb, sizeof(*eh)); | ||
| 470 | skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); | ||
| 471 | pp = ptype->callbacks.gro_receive(head, skb); | ||
| 472 | |||
| 473 | out_unlock: | ||
| 474 | rcu_read_unlock(); | ||
| 475 | out: | ||
| 476 | NAPI_GRO_CB(skb)->flush |= flush; | ||
| 477 | |||
| 478 | return pp; | ||
| 479 | } | ||
| 480 | EXPORT_SYMBOL(eth_gro_receive); | ||
| 481 | |||
| 482 | int eth_gro_complete(struct sk_buff *skb, int nhoff) | ||
| 483 | { | ||
| 484 | struct ethhdr *eh = (struct ethhdr *)(skb->data + nhoff); | ||
| 485 | __be16 type = eh->h_proto; | ||
| 486 | struct packet_offload *ptype; | ||
| 487 | int err = -ENOSYS; | ||
| 488 | |||
| 489 | if (skb->encapsulation) | ||
| 490 | skb_set_inner_mac_header(skb, nhoff); | ||
| 491 | |||
| 492 | rcu_read_lock(); | ||
| 493 | ptype = gro_find_complete_by_type(type); | ||
| 494 | if (ptype != NULL) | ||
| 495 | err = ptype->callbacks.gro_complete(skb, nhoff + | ||
| 496 | sizeof(struct ethhdr)); | ||
| 497 | |||
| 498 | rcu_read_unlock(); | ||
| 499 | return err; | ||
| 500 | } | ||
| 501 | EXPORT_SYMBOL(eth_gro_complete); | ||
| 502 | |||
| 503 | static struct packet_offload eth_packet_offload __read_mostly = { | ||
| 504 | .type = cpu_to_be16(ETH_P_TEB), | ||
| 505 | .callbacks = { | ||
| 506 | .gro_receive = eth_gro_receive, | ||
| 507 | .gro_complete = eth_gro_complete, | ||
| 508 | }, | ||
| 509 | }; | ||
| 510 | |||
| 511 | static int __init eth_offload_init(void) | ||
| 512 | { | ||
| 513 | dev_add_offload(ð_packet_offload); | ||
| 514 | |||
| 515 | return 0; | ||
| 516 | } | ||
| 517 | |||
| 518 | fs_initcall(eth_offload_init); | ||
