|
@@ -176,8 +176,10 @@
|
|
|
#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1)
|
|
|
|
|
|
static DEFINE_SPINLOCK(ptype_lock);
|
|
|
+static DEFINE_SPINLOCK(offload_lock);
|
|
|
static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
|
|
|
static struct list_head ptype_all __read_mostly; /* Taps */
|
|
|
+static struct list_head offload_base __read_mostly;
|
|
|
|
|
|
/*
|
|
|
* 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)
|
|
|
}
|
|
|
EXPORT_SYMBOL(dev_remove_pack);
|
|
|
|
|
|
+
|
|
|
+/**
|
|
|
+ * dev_add_offload - register offload handlers
|
|
|
+ * @po: protocol offload declaration
|
|
|
+ *
|
|
|
+ * Add protocol offload handlers to the networking stack. The passed
|
|
|
+ * &proto_offload is linked into kernel lists and may not be freed until
|
|
|
+ * it has been removed from the kernel lists.
|
|
|
+ *
|
|
|
+ * This call does not sleep therefore it can not
|
|
|
+ * guarantee all CPU's that are in middle of receiving packets
|
|
|
+ * will see the new offload handlers (until the next received packet).
|
|
|
+ */
|
|
|
+void dev_add_offload(struct packet_offload *po)
|
|
|
+{
|
|
|
+ struct list_head *head = &offload_base;
|
|
|
+
|
|
|
+ spin_lock(&offload_lock);
|
|
|
+ list_add_rcu(&po->list, head);
|
|
|
+ spin_unlock(&offload_lock);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dev_add_offload);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __dev_remove_offload - remove offload handler
|
|
|
+ * @po: packet offload declaration
|
|
|
+ *
|
|
|
+ * Remove a protocol offload handler that was previously added to the
|
|
|
+ * kernel offload handlers by dev_add_offload(). The passed &offload_type
|
|
|
+ * is removed from the kernel lists and can be freed or reused once this
|
|
|
+ * function returns.
|
|
|
+ *
|
|
|
+ * The packet type might still be in use by receivers
|
|
|
+ * and must not be freed until after all the CPU's have gone
|
|
|
+ * through a quiescent state.
|
|
|
+ */
|
|
|
+void __dev_remove_offload(struct packet_offload *po)
|
|
|
+{
|
|
|
+ struct list_head *head = &offload_base;
|
|
|
+ struct packet_offload *po1;
|
|
|
+
|
|
|
+ spin_lock(&ptype_lock);
|
|
|
+
|
|
|
+ list_for_each_entry(po1, head, list) {
|
|
|
+ if (po == po1) {
|
|
|
+ list_del_rcu(&po->list);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_warn("dev_remove_offload: %p not found\n", po);
|
|
|
+out:
|
|
|
+ spin_unlock(&ptype_lock);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(__dev_remove_offload);
|
|
|
+
|
|
|
+/**
|
|
|
+ * dev_remove_offload - remove packet offload handler
|
|
|
+ * @po: packet offload declaration
|
|
|
+ *
|
|
|
+ * Remove a packet offload handler that was previously added to the kernel
|
|
|
+ * offload handlers by dev_add_offload(). The passed &offload_type is
|
|
|
+ * removed from the kernel lists and can be freed or reused once this
|
|
|
+ * function returns.
|
|
|
+ *
|
|
|
+ * This call sleeps to guarantee that no CPU is looking at the packet
|
|
|
+ * type after return.
|
|
|
+ */
|
|
|
+void dev_remove_offload(struct packet_offload *po)
|
|
|
+{
|
|
|
+ __dev_remove_offload(po);
|
|
|
+
|
|
|
+ synchronize_net();
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dev_remove_offload);
|
|
|
+
|
|
|
/******************************************************************************
|
|
|
|
|
|
Device Boot-time Settings Routines
|
|
@@ -6661,6 +6739,8 @@ static int __init net_dev_init(void)
|
|
|
for (i = 0; i < PTYPE_HASH_SIZE; i++)
|
|
|
INIT_LIST_HEAD(&ptype_base[i]);
|
|
|
|
|
|
+ INIT_LIST_HEAD(&offload_base);
|
|
|
+
|
|
|
if (register_pernet_subsys(&netdev_net_ops))
|
|
|
goto out;
|
|
|
|