Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 266910
b: refs/heads/master
c: e09eff7
h: refs/heads/master
v: v3
  • Loading branch information
Eric W. Biederman authored and David S. Miller committed Oct 21, 2011
1 parent 5fc6836 commit e8af534
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 17 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9bf1907f4293d61d5a283d18c4ad28d048261797
refs/heads/master: e09eff7fc1c6f011f7bdb304e10d2ceef08c88ab
87 changes: 71 additions & 16 deletions trunk/drivers/net/macvtap.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,13 @@ static struct proto macvtap_proto = {
};

/*
* Minor number matches netdev->ifindex, so need a potentially
* large value. This also makes it possible to split the
* tap functionality out again in the future by offering it
* from other drivers besides macvtap. As long as every device
* only has one tap, the interface numbers assure that the
* device nodes are unique.
* Variables for dealing with macvtaps device numbers.
*/
static dev_t macvtap_major;
#define MACVTAP_NUM_DEVS 65536
#define MACVTAP_NUM_DEVS (1U << MINORBITS)
static DEFINE_MUTEX(minor_lock);
static DEFINE_IDR(minor_idr);

#define GOODCOPY_LEN 128
static struct class *macvtap_class;
static struct cdev macvtap_cdev;
Expand Down Expand Up @@ -275,6 +273,58 @@ static int macvtap_receive(struct sk_buff *skb)
return macvtap_forward(skb->dev, skb);
}

static int macvtap_get_minor(struct macvlan_dev *vlan)
{
int retval = -ENOMEM;
int id;

mutex_lock(&minor_lock);
if (idr_pre_get(&minor_idr, GFP_KERNEL) == 0)
goto exit;

retval = idr_get_new_above(&minor_idr, vlan, 1, &id);
if (retval < 0) {
if (retval == -EAGAIN)
retval = -ENOMEM;
goto exit;
}
if (id < MACVTAP_NUM_DEVS) {
vlan->minor = id;
} else {
printk(KERN_ERR "too many macvtap devices\n");
retval = -EINVAL;
idr_remove(&minor_idr, id);
}
exit:
mutex_unlock(&minor_lock);
return retval;
}

static void macvtap_free_minor(struct macvlan_dev *vlan)
{
mutex_lock(&minor_lock);
if (vlan->minor) {
idr_remove(&minor_idr, vlan->minor);
vlan->minor = 0;
}
mutex_unlock(&minor_lock);
}

static struct net_device *dev_get_by_macvtap_minor(int minor)
{
struct net_device *dev = NULL;
struct macvlan_dev *vlan;

mutex_lock(&minor_lock);
vlan = idr_find(&minor_idr, minor);
if (vlan) {
dev = vlan->dev;
dev_hold(dev);
}
mutex_unlock(&minor_lock);
return dev;
}

static int macvtap_newlink(struct net *src_net,
struct net_device *dev,
struct nlattr *tb[],
Expand Down Expand Up @@ -329,19 +379,14 @@ static void macvtap_sock_destruct(struct sock *sk)
static int macvtap_open(struct inode *inode, struct file *file)
{
struct net *net = current->nsproxy->net_ns;
struct net_device *dev = dev_get_by_index(net, iminor(inode));
struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode));
struct macvtap_queue *q;
int err;

err = -ENODEV;
if (!dev)
goto out;

/* check if this is a macvtap device */
err = -EINVAL;
if (dev->rtnl_link_ops != &macvtap_link_ops)
goto out;

err = -ENOMEM;
q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
&macvtap_proto);
Expand Down Expand Up @@ -961,28 +1006,38 @@ static int macvtap_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
struct macvlan_dev *vlan;
struct device *classdev;
dev_t devt;
int err;

if (dev->rtnl_link_ops != &macvtap_link_ops)
return NOTIFY_DONE;

vlan = netdev_priv(dev);

switch (event) {
case NETDEV_REGISTER:
/* Create the device node here after the network device has
* been registered but before register_netdevice has
* finished running.
*/
devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
err = macvtap_get_minor(vlan);
if (err)
return notifier_from_errno(err);

devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
classdev = device_create(macvtap_class, &dev->dev, devt,
dev, "tap%d", dev->ifindex);
if (IS_ERR(classdev))
if (IS_ERR(classdev)) {
macvtap_free_minor(vlan);
return notifier_from_errno(PTR_ERR(classdev));
}
break;
case NETDEV_UNREGISTER:
devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
device_destroy(macvtap_class, devt);
macvtap_free_minor(vlan);
break;
}

Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/if_macvlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct macvlan_dev {
int (*forward)(struct net_device *dev, struct sk_buff *skb);
struct macvtap_queue *taps[MAX_MACVTAP_QUEUES];
int numvtaps;
int minor;
};

static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
Expand Down

0 comments on commit e8af534

Please sign in to comment.