Patchwork [RFC,4/4] net: ppp_generic - introduce net-namespace functionality

login
register
mail settings
Submitter Cyrill Gorcunov
Date Jan. 10, 2009, 9:28 a.m.
Message ID <20090110092830.GB7622@localhost>
Download mbox | patch
Permalink /patch/17728/
State RFC
Delegated to: David Miller
Headers show

Comments

Cyrill Gorcunov - Jan. 10, 2009, 9:28 a.m.
[Cyrill Gorcunov - Sat, Jan 10, 2009 at 12:22:58PM +0300]
| [Cyrill Gorcunov - Fri, Jan 09, 2009 at 10:51:58PM +0300]
| | - Each namespace contain ppp channels and units separately
| |   with appropriate locks
| | 
| | CC: Paul Mackerras <paulus@samba.org>
| | Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
| ...
| 
| Please ignore this one -- I forgot to update
| ppp_init while was porting the patch. Will
| fix.
| 
| 		- Cyrill -

ok, here is an updated version

		- Cyrill -
---
From: Cyrill Gorcunov <gorcunov@gmail.com>
Subecjt: [RFC] net: ppp_generic - introduce net-namespace functionality

- Each namespace contain ppp channels and units separately
  with appropriate locks

CC: Paul Mackerras <paulus@samba.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
---
 drivers/net/ppp_generic.c |  279 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 199 insertions(+), 80 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paul Mackerras - Jan. 11, 2009, 12:33 a.m.
Cyrill Gorcunov writes:

> From: Cyrill Gorcunov <gorcunov@gmail.com>
> Subecjt: [RFC] net: ppp_generic - introduce net-namespace functionality
> 
> - Each namespace contain ppp channels and units separately
>   with appropriate locks

This looks like a lot of uglification to me.  Why exactly do
individual network drivers need to know or care about namespaces?

Paul.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller - Jan. 11, 2009, 7:39 a.m.
From: Paul Mackerras <paulus@samba.org>
Date: Sun, 11 Jan 2009 11:33:21 +1100

> Cyrill Gorcunov writes:
> 
> > From: Cyrill Gorcunov <gorcunov@gmail.com>
> > Subecjt: [RFC] net: ppp_generic - introduce net-namespace functionality
> > 
> > - Each namespace contain ppp channels and units separately
> >   with appropriate locks
> 
> This looks like a lot of uglification to me.  Why exactly do
> individual network drivers need to know or care about namespaces?

They need to know if there is a lookup involved and the device
type internally has it's own realm of keys that identify such
devices.

PPP fits that particular case.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Cyrill Gorcunov - Jan. 11, 2009, 7:46 a.m.
[Paul Mackerras - Sun, Jan 11, 2009 at 11:33:21AM +1100]
| Cyrill Gorcunov writes:
| 
| > From: Cyrill Gorcunov <gorcunov@gmail.com>
| > Subecjt: [RFC] net: ppp_generic - introduce net-namespace functionality
| > 
| > - Each namespace contain ppp channels and units separately
| >   with appropriate locks
| 
| This looks like a lot of uglification to me.  Why exactly do
| individual network drivers need to know or care about namespaces?
| 
| Paul.
| 

Unfortunately in the whole series ppp has been change more
then others and it's looks ugly indeed that is why it was RFC.
Namespaces imply isolation of data right? Including private
data being 'user related' -- ie units passed to user in one
namespace should not interfere with units passed to user in
another namespace. So if I will not 'bind' units pool to
namespaces it would be possible to steal unit from one namespace
proposed for another namespace. Right?

		- Cyrill -
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Cyrill Gorcunov - Jan. 11, 2009, 8:25 a.m.
[Cyrill Gorcunov - Sun, Jan 11, 2009 at 10:46:52AM +0300]
| [Paul Mackerras - Sun, Jan 11, 2009 at 11:33:21AM +1100]
| | Cyrill Gorcunov writes:
| | 
| | > From: Cyrill Gorcunov <gorcunov@gmail.com>
| | > Subecjt: [RFC] net: ppp_generic - introduce net-namespace functionality
| | > 
| | > - Each namespace contain ppp channels and units separately
| | >   with appropriate locks
| | 
| | This looks like a lot of uglification to me.  Why exactly do
| | individual network drivers need to know or care about namespaces?
| | 
| | Paul.
| | 
| 
| Unfortunately in the whole series ppp has been change more
| then others and it's looks ugly indeed that is why it was RFC.
| Namespaces imply isolation of data right? Including private
| data being 'user related' -- ie units passed to user in one
| namespace should not interfere with units passed to user in
| another namespace. So if I will not 'bind' units pool to
| namespaces it would be possible to steal unit from one namespace
| proposed for another namespace. Right?
| 
| 		- Cyrill -

Anyway, thanks for review -- I'll check if I could make this
series less 'ugly'. I just wanna hear what people think about
this series 'in general' (or maybe even test it [James, thanks!] :) --
since the series is RFC and not to include in any kind of tree.

		- Cyrill -
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

Index: linux-2.6.git/drivers/net/ppp_generic.c
===================================================================
--- linux-2.6.git.orig/drivers/net/ppp_generic.c
+++ linux-2.6.git/drivers/net/ppp_generic.c
@@ -49,6 +49,10 @@ 
 #include <net/slhc_vj.h>
 #include <asm/atomic.h>
 
+#include <linux/nsproxy.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
 #define PPP_VERSION	"2.4.2"
 
 /*
@@ -89,6 +93,8 @@  struct ppp_file {
 #define PF_TO_PPP(pf)		PF_TO_X(pf, struct ppp)
 #define PF_TO_CHANNEL(pf)	PF_TO_X(pf, struct channel)
 
+struct ppp_net;
+
 /*
  * Data structure describing one ppp unit.
  * A ppp unit corresponds to a ppp network interface device
@@ -131,6 +137,7 @@  struct ppp {
 	struct sock_filter *active_filter;/* filter for pkts to reset idle */
 	unsigned pass_len, active_len;
 #endif /* CONFIG_PPP_FILTER */
+	struct net	*ppp_net;	/* the net we belong to */
 };
 
 /*
@@ -173,25 +180,36 @@  struct channel {
  * channel.downl.
  */
 
-/*
- * all_ppp_mutex protects the all_ppp_units mapping.
- * It also ensures that finding a ppp unit in the all_ppp_units map
- * and updating its file.refcnt field is atomic.
- */
-static DEFINE_MUTEX(all_ppp_mutex);
 static atomic_t ppp_unit_count = ATOMIC_INIT(0);
-static DEFINE_IDR(ppp_units_idr);
+static atomic_t channel_count = ATOMIC_INIT(0);
 
 /*
- * all_channels_lock protects all_channels and last_channel_index,
- * and the atomicity of find a channel and updating its file.refcnt
- * field.
+ * per net-namespace data for this module
  */
-static DEFINE_SPINLOCK(all_channels_lock);
-static LIST_HEAD(all_channels);
-static LIST_HEAD(new_channels);
-static int last_channel_index;
-static atomic_t channel_count = ATOMIC_INIT(0);
+static unsigned int ppp_net_id;
+struct ppp_net {
+	/* units to ppp mapping */
+	struct idr units_idr;
+
+	/* channels */
+	struct list_head all_channels;
+	struct list_head new_channels;
+	int last_channel_index;
+
+	/*
+	 * all_ppp_mutex protects the units_idr mapping.
+	 * It also ensures that finding a ppp unit in the units_idr
+	 * map and updating its file.refcnt field is atomic.
+	 */
+	struct mutex all_ppp_mutex;
+
+	/*
+	 * all_channels_lock protects all_channels and
+	 * last_channel_index, and the atomicity of find
+	 * a channel and updating its file.refcnt field.
+	 */
+	spinlock_t all_channels_lock;
+};
 
 /* Get the PPP protocol number from a skb */
 #define PPP_PROTO(skb)	(((skb)->data[0] << 8) + (skb)->data[1])
@@ -240,21 +258,28 @@  static void ppp_ccp_peek(struct ppp *ppp
 static void ppp_ccp_closed(struct ppp *ppp);
 static struct compressor *find_compressor(int type);
 static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
-static struct ppp *ppp_create_interface(int unit, int *retp);
+static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp);
 static void init_ppp_file(struct ppp_file *pf, int kind);
 static void ppp_shutdown_interface(struct ppp *ppp);
 static void ppp_destroy_interface(struct ppp *ppp);
-static struct ppp *ppp_find_unit(int unit);
-static struct channel *ppp_find_channel(int unit);
+static struct channel *ppp_find_channel(struct net *net, int unit);
 static int ppp_connect_channel(struct channel *pch, int unit);
 static int ppp_disconnect_channel(struct channel *pch);
 static void ppp_destroy_channel(struct channel *pch);
-static int unit_get(struct idr *p, void *ptr);
-static void unit_put(struct idr *p, int n);
-static void *unit_find(struct idr *p, int n);
+static int unit_get(struct net *net, void *ptr);
+static void unit_put(struct net *net, int n);
+static void *unit_find(struct net *net, int n);
 
 static struct class *ppp_class;
 
+/* per net-namespace data */
+static inline struct ppp_net *ppp_pernet(struct net *net)
+{
+	BUG_ON(!net);
+
+	return net_generic(net, ppp_net_id);
+}
+
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
 static inline int proto_to_npindex(int proto)
 {
@@ -343,6 +368,7 @@  static int ppp_open(struct inode *inode,
 	 */
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
+
 	return 0;
 }
 
@@ -768,6 +794,7 @@  static int ppp_unattached_ioctl(struct p
 	int unit, err = -EFAULT;
 	struct ppp *ppp;
 	struct channel *chan;
+	struct ppp_net *pn;
 	int __user *p = (int __user *)arg;
 
 	lock_kernel();
@@ -776,7 +803,7 @@  static int ppp_unattached_ioctl(struct p
 		/* Create a new ppp unit */
 		if (get_user(unit, p))
 			break;
-		ppp = ppp_create_interface(unit, &err);
+		ppp = ppp_create_interface(current->nsproxy->net_ns, unit, &err);
 		if (!ppp)
 			break;
 		file->private_data = &ppp->file;
@@ -791,29 +818,31 @@  static int ppp_unattached_ioctl(struct p
 		/* Attach to an existing ppp unit */
 		if (get_user(unit, p))
 			break;
-		mutex_lock(&all_ppp_mutex);
+		pn = ppp_pernet(current->nsproxy->net_ns);
+		mutex_lock(&pn->all_ppp_mutex);
 		err = -ENXIO;
-		ppp = ppp_find_unit(unit);
+		ppp = unit_find(current->nsproxy->net_ns, unit);
 		if (ppp) {
 			atomic_inc(&ppp->file.refcnt);
 			file->private_data = &ppp->file;
 			err = 0;
 		}
-		mutex_unlock(&all_ppp_mutex);
+		mutex_unlock(&pn->all_ppp_mutex);
 		break;
 
 	case PPPIOCATTCHAN:
 		if (get_user(unit, p))
 			break;
-		spin_lock_bh(&all_channels_lock);
+		pn = ppp_pernet(current->nsproxy->net_ns);
+		spin_lock_bh(&pn->all_channels_lock);
 		err = -ENXIO;
-		chan = ppp_find_channel(unit);
+		chan = ppp_find_channel(current->nsproxy->net_ns, unit);
 		if (chan) {
 			atomic_inc(&chan->file.refcnt);
 			file->private_data = &chan->file;
 			err = 0;
 		}
-		spin_unlock_bh(&all_channels_lock);
+		spin_unlock_bh(&pn->all_channels_lock);
 		break;
 
 	default:
@@ -833,6 +862,54 @@  static const struct file_operations ppp_
 	.release	= ppp_release
 };
 
+static __net_init int ppp_init_net(struct net *net)
+{
+	struct ppp_net *pn;
+	int err;
+
+	pn = kzalloc(sizeof(*pn), GFP_KERNEL);
+	if (!pn)
+		return -ENOMEM;
+
+	idr_init(&pn->units_idr);
+
+	INIT_LIST_HEAD(&pn->all_channels);
+	INIT_LIST_HEAD(&pn->new_channels);
+
+	mutex_init(&pn->all_ppp_mutex);
+	spin_lock_init(&pn->all_channels_lock);
+
+	err = net_assign_generic(net, ppp_net_id, pn);
+	if (err) {
+		kfree(pn);
+		return err;
+	}
+
+	try_module_get(THIS_MODULE);
+	return 0;
+}
+
+static __net_exit void ppp_exit_net(struct net *net)
+{
+	struct ppp_net *pn;
+
+	pn = net_generic(net, ppp_net_id);
+	idr_destroy(&pn->units_idr);
+	/*
+	 * if someone has cached our net then
+	 * further net_generic call will return NULL
+	 */
+	net_assign_generic(net, ppp_net_id, NULL);
+	kfree(pn);
+
+	module_put(THIS_MODULE);
+}
+
+static __net_initdata struct pernet_operations ppp_net_ops = {
+	.init = ppp_init_net,
+	.exit = ppp_exit_net,
+};
+
 #define PPP_MAJOR	108
 
 /* Called at boot time if ppp is compiled into the kernel,
@@ -842,25 +919,36 @@  static int __init ppp_init(void)
 	int err;
 
 	printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
-	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
-	if (!err) {
-		ppp_class = class_create(THIS_MODULE, "ppp");
-		if (IS_ERR(ppp_class)) {
-			err = PTR_ERR(ppp_class);
-			goto out_chrdev;
-		}
-		device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL,
-			      "ppp");
+
+	err = register_pernet_gen_device(&ppp_net_id, &ppp_net_ops);
+	if (err) {
+		printk(KERN_ERR "failed to register PPP pernet device (%d)\n", err);
+		goto out;
 	}
 
-out:
-	if (err)
+	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
+	if (err) {
 		printk(KERN_ERR "failed to register PPP device (%d)\n", err);
-	return err;
+		goto out_net;
+	}
+
+	ppp_class = class_create(THIS_MODULE, "ppp");
+	if (IS_ERR(ppp_class)) {
+		err = PTR_ERR(ppp_class);
+		goto out_chrdev;
+	}
+
+	/* not a big deal if we fail here :-) */
+	device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
+
+	return 0;
 
 out_chrdev:
 	unregister_chrdev(PPP_MAJOR, "ppp");
-	goto out;
+out_net:
+	unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops);
+out:
+	return err;
 }
 
 /*
@@ -1992,10 +2080,14 @@  int
 ppp_register_channel(struct ppp_channel *chan)
 {
 	struct channel *pch;
+	struct ppp_net *pn;
 
 	pch = kzalloc(sizeof(struct channel), GFP_KERNEL);
 	if (!pch)
 		return -ENOMEM;
+
+	pn = ppp_pernet(current->nsproxy->net_ns);
+
 	pch->ppp = NULL;
 	pch->chan = chan;
 	chan->ppp = pch;
@@ -2007,11 +2099,11 @@  ppp_register_channel(struct ppp_channel 
 	init_rwsem(&pch->chan_sem);
 	spin_lock_init(&pch->downl);
 	rwlock_init(&pch->upl);
-	spin_lock_bh(&all_channels_lock);
-	pch->file.index = ++last_channel_index;
-	list_add(&pch->list, &new_channels);
+	spin_lock_bh(&pn->all_channels_lock);
+	pch->file.index = ++pn->last_channel_index;
+	list_add(&pch->list, &pn->new_channels);
 	atomic_inc(&channel_count);
-	spin_unlock_bh(&all_channels_lock);
+	spin_unlock_bh(&pn->all_channels_lock);
 	return 0;
 }
 
@@ -2052,11 +2144,17 @@  void
 ppp_unregister_channel(struct ppp_channel *chan)
 {
 	struct channel *pch = chan->ppp;
+	struct ppp_net *pn;
 
 	if (!pch)
 		return;		/* should never happen */
 	chan->ppp = NULL;
 
+	if (pch->ppp->ppp_net)
+		pn = ppp_pernet(pch->ppp->ppp_net);
+	else
+		pn = ppp_pernet(current->nsproxy->net_ns);
+
 	/*
 	 * This ensures that we have returned from any calls into the
 	 * the channel's start_xmit or ioctl routine before we proceed.
@@ -2067,9 +2165,9 @@  ppp_unregister_channel(struct ppp_channe
 	spin_unlock_bh(&pch->downl);
 	up_write(&pch->chan_sem);
 	ppp_disconnect_channel(pch);
-	spin_lock_bh(&all_channels_lock);
+	spin_lock_bh(&pn->all_channels_lock);
 	list_del(&pch->list);
-	spin_unlock_bh(&all_channels_lock);
+	spin_unlock_bh(&pn->all_channels_lock);
 	pch->file.dead = 1;
 	wake_up_interruptible(&pch->file.rwait);
 	if (atomic_dec_and_test(&pch->file.refcnt))
@@ -2394,10 +2492,11 @@  ppp_get_stats(struct ppp *ppp, struct pp
  * unit == -1 means allocate a new number.
  */
 static struct ppp *
-ppp_create_interface(int unit, int *retp)
+ppp_create_interface(struct net *net, int unit, int *retp)
 {
 	struct ppp *ppp;
-	struct net_device *dev = NULL;
+	struct net_device *dev;
+	struct ppp_net *pn;
 	int ret = -ENOMEM;
 	int i;
 
@@ -2408,6 +2507,7 @@  ppp_create_interface(int unit, int *retp
 	ppp = netdev_priv(dev);
 	ppp->dev = dev;
 	ppp->mru = PPP_MRU;
+	ppp->ppp_net = net;
 	init_ppp_file(&ppp->file, INTERFACE);
 	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
 	for (i = 0; i < NUM_NP; ++i)
@@ -2421,19 +2521,21 @@  ppp_create_interface(int unit, int *retp
 #endif /* CONFIG_PPP_MULTILINK */
 
 	ret = -EEXIST;
-	mutex_lock(&all_ppp_mutex);
+
+	pn = ppp_pernet(net);
+	mutex_lock(&pn->all_ppp_mutex);
 
 	if (unit < 0) {
-		unit = unit_get(&ppp_units_idr, ppp);
+		unit = unit_get(net, ppp);
 		if (unit < 0) {
 			*retp = unit;
 			goto out2;
 		}
 	} else {
-		if (unit_find(&ppp_units_idr, unit))
+		if (unit_find(net, unit))
 			goto out2; /* unit already exists */
 		else {
-			/* darn, someone is cheating us? */
+			/* darn, someone is cheatting us? */
 			*retp = -EINVAL;
 			goto out2;
 		}
@@ -2445,20 +2547,20 @@  ppp_create_interface(int unit, int *retp
 
 	ret = register_netdev(dev);
 	if (ret != 0) {
-		unit_put(&ppp_units_idr, unit);
+		unit_put(net, unit);
 		printk(KERN_ERR "PPP: couldn't register device %s (%d)\n",
 		       dev->name, ret);
 		goto out2;
 	}
 
 	atomic_inc(&ppp_unit_count);
-	mutex_unlock(&all_ppp_mutex);
+	mutex_unlock(&pn->all_ppp_mutex);
 
 	*retp = 0;
 	return ppp;
 
 out2:
-	mutex_unlock(&all_ppp_mutex);
+	mutex_unlock(&pn->all_ppp_mutex);
 	free_netdev(dev);
 out1:
 	*retp = ret;
@@ -2484,7 +2586,9 @@  init_ppp_file(struct ppp_file *pf, int k
  */
 static void ppp_shutdown_interface(struct ppp *ppp)
 {
-	mutex_lock(&all_ppp_mutex);
+	struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
+
+	mutex_lock(&pn->all_ppp_mutex);
 	/* This will call dev_close() for us. */
 	ppp_lock(ppp);
 	if (!ppp->closing) {
@@ -2494,11 +2598,11 @@  static void ppp_shutdown_interface(struc
 	} else
 		ppp_unlock(ppp);
 
-	unit_put(&ppp_units_idr, ppp->file.index);
+	unit_put(ppp->ppp_net, ppp->file.index);
 	ppp->file.dead = 1;
 	ppp->owner = NULL;
 	wake_up_interruptible(&ppp->file.rwait);
-	mutex_unlock(&all_ppp_mutex);
+	mutex_unlock(&pn->all_ppp_mutex);
 }
 
 /*
@@ -2542,16 +2646,6 @@  static void ppp_destroy_interface(struct
 }
 
 /*
- * Locate an existing ppp unit.
- * The caller should have locked the all_ppp_mutex.
- */
-static struct ppp *
-ppp_find_unit(int unit)
-{
-	return unit_find(&ppp_units_idr, unit);
-}
-
-/*
  * Locate an existing ppp channel.
  * The caller should have locked the all_channels_lock.
  * First we look in the new_channels list, then in the
@@ -2560,20 +2654,25 @@  ppp_find_unit(int unit)
  * when we have a lot of channels in use.
  */
 static struct channel *
-ppp_find_channel(int unit)
+ppp_find_channel(struct net *net, int unit)
 {
 	struct channel *pch;
+	struct ppp_net *pn;
+
+	pn = ppp_pernet(net);
 
-	list_for_each_entry(pch, &new_channels, list) {
+	list_for_each_entry(pch, &pn->new_channels, list) {
 		if (pch->file.index == unit) {
-			list_move(&pch->list, &all_channels);
+			list_move(&pch->list, &pn->all_channels);
 			return pch;
 		}
 	}
-	list_for_each_entry(pch, &all_channels, list) {
+
+	list_for_each_entry(pch, &pn->all_channels, list) {
 		if (pch->file.index == unit)
 			return pch;
 	}
+
 	return NULL;
 }
 
@@ -2584,11 +2683,14 @@  static int
 ppp_connect_channel(struct channel *pch, int unit)
 {
 	struct ppp *ppp;
+	struct ppp_net *pn;
 	int ret = -ENXIO;
 	int hdrlen;
 
-	mutex_lock(&all_ppp_mutex);
-	ppp = ppp_find_unit(unit);
+	pn = ppp_pernet(current->nsproxy->net_ns);
+
+	mutex_lock(&pn->all_ppp_mutex);
+	ppp = unit_find(current->nsproxy->net_ns, unit);
 	if (!ppp)
 		goto out;
 	write_lock_bh(&pch->upl);
@@ -2612,7 +2714,7 @@  ppp_connect_channel(struct channel *pch,
  outl:
 	write_unlock_bh(&pch->upl);
  out:
-	mutex_unlock(&all_ppp_mutex);
+	mutex_unlock(&pn->all_ppp_mutex);
 	return ret;
 }
 
@@ -2669,7 +2771,7 @@  static void __exit ppp_cleanup(void)
 	unregister_chrdev(PPP_MAJOR, "ppp");
 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
 	class_destroy(ppp_class);
-	idr_destroy(&ppp_units_idr);
+	unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops);
 }
 
 /*
@@ -2678,9 +2780,14 @@  static void __exit ppp_cleanup(void)
  */
 
 /* get new free unit number and associate pointer with it */
-static int unit_get(struct idr *p, void *ptr)
+static int unit_get(struct net *net, void *ptr)
 {
 	int unit, err;
+	struct ppp_net *pn;
+	struct idr *p;
+
+	pn = ppp_pernet(net);
+	p = &pn->units_idr;
 
 again:
 	if (idr_pre_get(p, GFP_KERNEL) == 0) {
@@ -2696,14 +2803,26 @@  again:
 }
 
 /* put unit number back to a pool */
-static void unit_put(struct idr *p, int n)
+static void unit_put(struct net *net, int n)
 {
+	struct ppp_net *pn;
+	struct idr *p;
+
+	pn = ppp_pernet(net);
+	p = &pn->units_idr;
+
 	idr_remove(p, n);
 }
 
 /* get pointer associated with the number */
-static void *unit_find(struct idr *p, int n)
+static void *unit_find(struct net *net, int n)
 {
+	struct ppp_net *pn;
+	struct idr *p;
+
+	pn = ppp_pernet(net);
+	p = &pn->units_idr;
+
 	return idr_find(p, n);
 }