aboutsummaryrefslogtreecommitdiffstats
path: root/net/ethernet
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2014-12-30 22:10:15 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-02 15:46:41 -0500
commit9b174d88c257150562b0101fcc6cb6c3cb74275c (patch)
tree345b03321802cb222991d9c3a524064eadbb54ad /net/ethernet
parent05930b5ec1d3b2a5c76e1959b54cae15587009c7 (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.c92
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}
426EXPORT_SYMBOL(sysfs_format_mac); 426EXPORT_SYMBOL(sysfs_format_mac);
427
428struct 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
473out_unlock:
474 rcu_read_unlock();
475out:
476 NAPI_GRO_CB(skb)->flush |= flush;
477
478 return pp;
479}
480EXPORT_SYMBOL(eth_gro_receive);
481
482int 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}
501EXPORT_SYMBOL(eth_gro_complete);
502
503static 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
511static int __init eth_offload_init(void)
512{
513 dev_add_offload(&eth_packet_offload);
514
515 return 0;
516}
517
518fs_initcall(eth_offload_init);