diff options
author | Vlad Yasevich <vyasevic@redhat.com> | 2012-11-15 03:49:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-15 17:36:16 -0500 |
commit | 62532da9d5f47a7ced3b965aa73ffd5b1afbeb79 (patch) | |
tree | 520e8ca8c90116fb4f92db0c356474abed905c79 | |
parent | efad0c14b720ec3791c95e0658c3990fbc124366 (diff) |
net: Add generic packet offload infrastructure.
Create a new data structure to contain the GRO/GSO callbacks and add
a new registration mechanism.
Singed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netdevice.h | 14 | ||||
-rw-r--r-- | net/core/dev.c | 80 |
2 files changed, 94 insertions, 0 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7bf867c97043..d45a58db4ba3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1521,6 +1521,17 @@ struct packet_type { | |||
1521 | struct list_head list; | 1521 | struct list_head list; |
1522 | }; | 1522 | }; |
1523 | 1523 | ||
1524 | struct packet_offload { | ||
1525 | __be16 type; /* This is really htons(ether_type). */ | ||
1526 | struct sk_buff *(*gso_segment)(struct sk_buff *skb, | ||
1527 | netdev_features_t features); | ||
1528 | int (*gso_send_check)(struct sk_buff *skb); | ||
1529 | struct sk_buff **(*gro_receive)(struct sk_buff **head, | ||
1530 | struct sk_buff *skb); | ||
1531 | int (*gro_complete)(struct sk_buff *skb); | ||
1532 | struct list_head list; | ||
1533 | }; | ||
1534 | |||
1524 | #include <linux/notifier.h> | 1535 | #include <linux/notifier.h> |
1525 | 1536 | ||
1526 | /* netdevice notifier chain. Please remember to update the rtnetlink | 1537 | /* netdevice notifier chain. Please remember to update the rtnetlink |
@@ -1615,6 +1626,9 @@ extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short | |||
1615 | extern void dev_add_pack(struct packet_type *pt); | 1626 | extern void dev_add_pack(struct packet_type *pt); |
1616 | extern void dev_remove_pack(struct packet_type *pt); | 1627 | extern void dev_remove_pack(struct packet_type *pt); |
1617 | extern void __dev_remove_pack(struct packet_type *pt); | 1628 | extern void __dev_remove_pack(struct packet_type *pt); |
1629 | extern void dev_add_offload(struct packet_offload *po); | ||
1630 | extern void dev_remove_offload(struct packet_offload *po); | ||
1631 | extern void __dev_remove_offload(struct packet_offload *po); | ||
1618 | 1632 | ||
1619 | extern struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags, | 1633 | extern struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags, |
1620 | unsigned short mask); | 1634 | unsigned short mask); |
diff --git a/net/core/dev.c b/net/core/dev.c index 83232a1be1e7..6884f8783bdd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -176,8 +176,10 @@ | |||
176 | #define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1) | 176 | #define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1) |
177 | 177 | ||
178 | static DEFINE_SPINLOCK(ptype_lock); | 178 | static DEFINE_SPINLOCK(ptype_lock); |
179 | static DEFINE_SPINLOCK(offload_lock); | ||
179 | static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; | 180 | static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; |
180 | static struct list_head ptype_all __read_mostly; /* Taps */ | 181 | static struct list_head ptype_all __read_mostly; /* Taps */ |
182 | static struct list_head offload_base __read_mostly; | ||
181 | 183 | ||
182 | /* | 184 | /* |
183 | * The @dev_base_head list is protected by @dev_base_lock and the rtnl | 185 | * The @dev_base_head list is protected by @dev_base_lock and the rtnl |
@@ -470,6 +472,82 @@ void dev_remove_pack(struct packet_type *pt) | |||
470 | } | 472 | } |
471 | EXPORT_SYMBOL(dev_remove_pack); | 473 | EXPORT_SYMBOL(dev_remove_pack); |
472 | 474 | ||
475 | |||
476 | /** | ||
477 | * dev_add_offload - register offload handlers | ||
478 | * @po: protocol offload declaration | ||
479 | * | ||
480 | * Add protocol offload handlers to the networking stack. The passed | ||
481 | * &proto_offload is linked into kernel lists and may not be freed until | ||
482 | * it has been removed from the kernel lists. | ||
483 | * | ||
484 | * This call does not sleep therefore it can not | ||
485 | * guarantee all CPU's that are in middle of receiving packets | ||
486 | * will see the new offload handlers (until the next received packet). | ||
487 | */ | ||
488 | void dev_add_offload(struct packet_offload *po) | ||
489 | { | ||
490 | struct list_head *head = &offload_base; | ||
491 | |||
492 | spin_lock(&offload_lock); | ||
493 | list_add_rcu(&po->list, head); | ||
494 | spin_unlock(&offload_lock); | ||
495 | } | ||
496 | EXPORT_SYMBOL(dev_add_offload); | ||
497 | |||
498 | /** | ||
499 | * __dev_remove_offload - remove offload handler | ||
500 | * @po: packet offload declaration | ||
501 | * | ||
502 | * Remove a protocol offload handler that was previously added to the | ||
503 | * kernel offload handlers by dev_add_offload(). The passed &offload_type | ||
504 | * is removed from the kernel lists and can be freed or reused once this | ||
505 | * function returns. | ||
506 | * | ||
507 | * The packet type might still be in use by receivers | ||
508 | * and must not be freed until after all the CPU's have gone | ||
509 | * through a quiescent state. | ||
510 | */ | ||
511 | void __dev_remove_offload(struct packet_offload *po) | ||
512 | { | ||
513 | struct list_head *head = &offload_base; | ||
514 | struct packet_offload *po1; | ||
515 | |||
516 | spin_lock(&ptype_lock); | ||
517 | |||
518 | list_for_each_entry(po1, head, list) { | ||
519 | if (po == po1) { | ||
520 | list_del_rcu(&po->list); | ||
521 | goto out; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | pr_warn("dev_remove_offload: %p not found\n", po); | ||
526 | out: | ||
527 | spin_unlock(&ptype_lock); | ||
528 | } | ||
529 | EXPORT_SYMBOL(__dev_remove_offload); | ||
530 | |||
531 | /** | ||
532 | * dev_remove_offload - remove packet offload handler | ||
533 | * @po: packet offload declaration | ||
534 | * | ||
535 | * Remove a packet offload handler that was previously added to the kernel | ||
536 | * offload handlers by dev_add_offload(). The passed &offload_type is | ||
537 | * removed from the kernel lists and can be freed or reused once this | ||
538 | * function returns. | ||
539 | * | ||
540 | * This call sleeps to guarantee that no CPU is looking at the packet | ||
541 | * type after return. | ||
542 | */ | ||
543 | void dev_remove_offload(struct packet_offload *po) | ||
544 | { | ||
545 | __dev_remove_offload(po); | ||
546 | |||
547 | synchronize_net(); | ||
548 | } | ||
549 | EXPORT_SYMBOL(dev_remove_offload); | ||
550 | |||
473 | /****************************************************************************** | 551 | /****************************************************************************** |
474 | 552 | ||
475 | Device Boot-time Settings Routines | 553 | Device Boot-time Settings Routines |
@@ -6661,6 +6739,8 @@ static int __init net_dev_init(void) | |||
6661 | for (i = 0; i < PTYPE_HASH_SIZE; i++) | 6739 | for (i = 0; i < PTYPE_HASH_SIZE; i++) |
6662 | INIT_LIST_HEAD(&ptype_base[i]); | 6740 | INIT_LIST_HEAD(&ptype_base[i]); |
6663 | 6741 | ||
6742 | INIT_LIST_HEAD(&offload_base); | ||
6743 | |||
6664 | if (register_pernet_subsys(&netdev_net_ops)) | 6744 | if (register_pernet_subsys(&netdev_net_ops)) |
6665 | goto out; | 6745 | goto out; |
6666 | 6746 | ||