--- /dev/null
+/*
+ * generic net pointers
+ */
+
+#ifndef __NET_GENERIC_H__
+#define __NET_GENERIC_H__
+
+#include <linux/rcupdate.h>
+
+/*
+ * Generic net pointers are to be used by modules to put some private
+ * stuff on the struct net without explicit struct net modification
+ *
+ * The rules are simple:
+ * 1. register the ops with register_pernet_gen_device to get the id
+ *    of your private pointer;
+ * 2. call net_assign_generic() to put the private data on the struct
+ *    net (most preferably this should be done in the ->init callback
+ *    of the ops registered);
+ * 3. do not change this pointer while the net is alive;
+ * 4. do not try to have any private reference on the net_generic object.
+ *
+ * After accomplishing all of the above, the private pointer can be
+ * accessed with the net_generic() call.
+ */
+
+struct net_generic {
+       unsigned int len;
+       struct rcu_head rcu;
+
+       void *ptr[0];
+};
+
+static inline void *net_generic(struct net *net, int id)
+{
+       struct net_generic *ng;
+       void *ptr;
+
+       rcu_read_lock();
+       ng = rcu_dereference(net->gen);
+       BUG_ON(id == 0 || id > ng->len);
+       ptr = ng->ptr[id - 1];
+       rcu_read_unlock();
+
+       return ptr;
+}
+
+extern int net_assign_generic(struct net *net, int id, void *data);
+#endif
 
 #include <linux/sched.h>
 #include <linux/idr.h>
 #include <net/net_namespace.h>
+#include <net/netns/generic.h>
 
 /*
  *     Our network namespace constructor/destructor lists
 struct net init_net;
 EXPORT_SYMBOL(init_net);
 
+#define INITIAL_NET_GEN_PTRS   13 /* +1 for len +2 for rcu_head */
+
 /*
  * setup_net runs the initializers for the network namespace object.
  */
        /* Must be called with net_mutex held */
        struct pernet_operations *ops;
        int error;
+       struct net_generic *ng;
 
        atomic_set(&net->count, 1);
        atomic_set(&net->use_count, 0);
 
+       error = -ENOMEM;
+       ng = kzalloc(sizeof(struct net_generic) +
+                       INITIAL_NET_GEN_PTRS * sizeof(void *), GFP_KERNEL);
+       if (ng == NULL)
+               goto out;
+
+       ng->len = INITIAL_NET_GEN_PTRS;
+       INIT_RCU_HEAD(&ng->rcu);
+       rcu_assign_pointer(net->gen, ng);
+
        error = 0;
        list_for_each_entry(ops, &pernet_list, list) {
                if (ops->init) {
        }
 
        rcu_barrier();
+       kfree(ng);
        goto out;
 }
 
        mutex_unlock(&net_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_gen_device);
+
+static void net_generic_release(struct rcu_head *rcu)
+{
+       struct net_generic *ng;
+
+       ng = container_of(rcu, struct net_generic, rcu);
+       kfree(ng);
+}
+
+int net_assign_generic(struct net *net, int id, void *data)
+{
+       struct net_generic *ng, *old_ng;
+
+       BUG_ON(!mutex_is_locked(&net_mutex));
+       BUG_ON(id == 0);
+
+       ng = old_ng = net->gen;
+       if (old_ng->len >= id)
+               goto assign;
+
+       ng = kzalloc(sizeof(struct net_generic) +
+                       id * sizeof(void *), GFP_KERNEL);
+       if (ng == NULL)
+               return -ENOMEM;
+
+       /*
+        * Some synchronisation notes:
+        *
+        * The net_generic explores the net->gen array inside rcu
+        * read section. Besides once set the net->gen->ptr[x]
+        * pointer never changes (see rules in netns/generic.h).
+        *
+        * That said, we simply duplicate this array and schedule
+        * the old copy for kfree after a grace period.
+        */
+
+       ng->len = id;
+       INIT_RCU_HEAD(&ng->rcu);
+       memcpy(&ng->ptr, &old_ng->ptr, old_ng->len);
+
+       rcu_assign_pointer(net->gen, ng);
+       call_rcu(&old_ng->rcu, net_generic_release);
+assign:
+       ng->ptr[id - 1] = data;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(net_assign_generic);