netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC VLAN 00/08]: VLAN netlink support
@ 2007-06-05 14:23 Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 01/08]: Move device lookup to ioctl handler Patrick McHardy
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

These patches convert VLAN to the rtnl_link API as a more complex example.
The patches need some more work, not all VLAN features are supported yet.

 include/linux/if_link.h   |   25 +
 include/linux/if_vlan.h   |    8 
 include/linux/rtnetlink.h |    3 
 net/8021q/Makefile        |    2 
 net/8021q/vlan.c          |  698 +++++++++++++++++++++-------------------------
 net/8021q/vlan.h          |   22 +
 net/8021q/vlan_dev.c      |  170 +++--------
 net/8021q/vlan_netlink.c  |  194 ++++++++++++
 net/8021q/vlanproc.c      |    4 
 9 files changed, 627 insertions(+), 499 deletions(-)

Patrick McHardy (8):
      [VLAN]: Move device lookup to ioctl handler
      [VLAN]: Remove unregister_vlan_dev wrapper
      [VLAN]: Add device init callback
      [VLAN]: Move vlan_group allocation to seperate function
      [VLAN]: Split up device creation
      [VLAN]: Use 32 bit value for skb->priority mapping
      [VLAN]: Keep track of number of QoS mappings
      [VLAN]: Use rtnl_link API

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC VLAN 01/08]: Move device lookup to ioctl handler
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 02/08]: Remove unregister_vlan_dev wrapper Patrick McHardy
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Move device lookup to ioctl handler

Move the device lookup and checks to the ioctl handler under the RTNL and
change all name-based interfaces to take a struct net_device * instead.

This allows to use them from a netlink interface, which identifies devices
based on ifindex not name. It also avoids races between the ioctl interface
and the (upcoming) netlink interface since now all changes happen under the
RTNL.

As a nice side effect this greatly simplifies error handling in the helper
functions and fixes a number of incorrect error codes like -EINVAL for
device not found.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit b2981f2b9c99d414e9ea990cda7ca31c5bef2420
tree a50adf705ff34d1fd79dfc67f8f4305e40d686cb
parent 0047f79615df9f8340275f4088e0869398aaf52d
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:15 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:15 +0200

 net/8021q/vlan.c     |  148 +++++++++++++++++++++-----------------------------
 net/8021q/vlan.h     |   13 +++-
 net/8021q/vlan_dev.c |  143 +++++++++++++-----------------------------------
 3 files changed, 109 insertions(+), 195 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index bd93c45..0d95388 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -280,43 +280,16 @@ static int unregister_vlan_dev(struct net_device *real_dev,
 	return ret;
 }
 
-static int unregister_vlan_device(const char *vlan_IF_name)
+static int unregister_vlan_device(struct net_device *dev)
 {
-	struct net_device *dev = NULL;
 	int ret;
 
+	ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
+				  VLAN_DEV_INFO(dev)->vlan_id);
+	unregister_netdevice(dev);
 
-	dev = dev_get_by_name(vlan_IF_name);
-	ret = -EINVAL;
-	if (dev) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			rtnl_lock();
-
-			ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
-						  VLAN_DEV_INFO(dev)->vlan_id);
-
-			dev_put(dev);
-			unregister_netdevice(dev);
-
-			rtnl_unlock();
-
-			if (ret == 1)
-				ret = 0;
-		} else {
-			printk(VLAN_ERR
-			       "%s: ERROR:	Tried to remove a non-vlan device "
-			       "with VLAN code, name: %s  priv_flags: %hX\n",
-			       __FUNCTION__, dev->name, dev->priv_flags);
-			dev_put(dev);
-			ret = -EPERM;
-		}
-	} else {
-#ifdef VLAN_DEBUG
-		printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__);
-#endif
-		ret = -EINVAL;
-	}
-
+	if (ret == 1)
+		ret = 0;
 	return ret;
 }
 
@@ -380,12 +353,11 @@ static struct lock_class_key vlan_netdev_xmit_lock_key;
  *  Returns the device that was created, or NULL if there was
  *  an error of some kind.
  */
-static struct net_device *register_vlan_device(const char *eth_IF_name,
+static struct net_device *register_vlan_device(struct net_device *real_dev,
 					       unsigned short VLAN_ID)
 {
 	struct vlan_group *grp;
 	struct net_device *new_dev;
-	struct net_device *real_dev; /* the ethernet device */
 	char name[IFNAMSIZ];
 	int i;
 
@@ -397,15 +369,10 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	if (VLAN_ID >= VLAN_VID_MASK)
 		goto out_ret_null;
 
-	/* find the device relating to eth_IF_name. */
-	real_dev = dev_get_by_name(eth_IF_name);
-	if (!real_dev)
-		goto out_ret_null;
-
 	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
 		printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
 			__FUNCTION__, real_dev->name);
-		goto out_put_dev;
+		goto out_ret_null;
 	}
 
 	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
@@ -413,7 +380,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	     real_dev->vlan_rx_kill_vid == NULL)) {
 		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
 			__FUNCTION__, real_dev->name);
-		goto out_put_dev;
+		goto out_ret_null;
 	}
 
 	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
@@ -421,24 +388,19 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	     real_dev->vlan_rx_kill_vid == NULL)) {
 		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
 			__FUNCTION__, real_dev->name);
-		goto out_put_dev;
+		goto out_ret_null;
 	}
 
-	/* From this point on, all the data structures must remain
-	 * consistent.
-	 */
-	rtnl_lock();
-
 	/* The real device must be up and operating in order to
 	 * assosciate a VLAN device with it.
 	 */
 	if (!(real_dev->flags & IFF_UP))
-		goto out_unlock;
+		goto out_ret_null;
 
 	if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) {
 		/* was already registered. */
 		printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
-		goto out_unlock;
+		goto out_ret_null;
 	}
 
 	/* Gotta set up the fields for the device. */
@@ -475,7 +437,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 			       vlan_setup);
 
 	if (new_dev == NULL)
-		goto out_unlock;
+		goto out_ret_null;
 
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
@@ -581,9 +543,8 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
 		real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
 
-	rtnl_unlock();
-
-
+	/* Account for reference in struct vlan_dev_info */
+	dev_hold(real_dev);
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "Allocated new device successfully, returning.\n");
 #endif
@@ -594,17 +555,11 @@ out_free_arrays:
 
 out_free_unregister:
 	unregister_netdev(new_dev);
-	goto out_unlock;
+	goto out_ret_null;
 
 out_free_newdev:
 	free_netdev(new_dev);
 
-out_unlock:
-	rtnl_unlock();
-
-out_put_dev:
-	dev_put(real_dev);
-
 out_ret_null:
 	return NULL;
 }
@@ -697,9 +652,10 @@ out:
  */
 static int vlan_ioctl_handler(void __user *arg)
 {
-	int err = 0;
+	int err;
 	unsigned short vid = 0;
 	struct vlan_ioctl_args args;
+	struct net_device *dev = NULL;
 
 	if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args)))
 		return -EFAULT;
@@ -712,34 +668,59 @@ static int vlan_ioctl_handler(void __user *arg)
 	printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);
 #endif
 
+	rtnl_lock();
+
+	switch (args.cmd) {
+	case SET_VLAN_INGRESS_PRIORITY_CMD:
+	case SET_VLAN_EGRESS_PRIORITY_CMD:
+	case SET_VLAN_FLAG_CMD:
+	case ADD_VLAN_CMD:
+	case DEL_VLAN_CMD:
+	case GET_VLAN_REALDEV_NAME_CMD:
+	case GET_VLAN_VID_CMD:
+		err = -ENODEV;
+		dev = __dev_get_by_name(args.device1);
+		if (!dev)
+			goto out;
+
+		err = -EINVAL;
+		if (args.cmd != ADD_VLAN_CMD &&
+		    !(dev->priv_flags & IFF_802_1Q_VLAN))
+			goto out;
+	}
+
 	switch (args.cmd) {
 	case SET_VLAN_INGRESS_PRIORITY_CMD:
+		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		err = vlan_dev_set_ingress_priority(args.device1,
-						    args.u.skb_priority,
-						    args.vlan_qos);
+			break;
+		vlan_dev_set_ingress_priority(dev,
+					      args.u.skb_priority,
+					      args.vlan_qos);
 		break;
 
 	case SET_VLAN_EGRESS_PRIORITY_CMD:
+		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		err = vlan_dev_set_egress_priority(args.device1,
+			break;
+		err = vlan_dev_set_egress_priority(dev,
 						   args.u.skb_priority,
 						   args.vlan_qos);
 		break;
 
 	case SET_VLAN_FLAG_CMD:
+		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		err = vlan_dev_set_vlan_flag(args.device1,
+			break;
+		err = vlan_dev_set_vlan_flag(dev,
 					     args.u.flag,
 					     args.vlan_qos);
 		break;
 
 	case SET_VLAN_NAME_TYPE_CMD:
+		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+			break;
 		if ((args.u.name_type >= 0) &&
 		    (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
 			vlan_name_type = args.u.name_type;
@@ -750,13 +731,14 @@ static int vlan_ioctl_handler(void __user *arg)
 		break;
 
 	case ADD_VLAN_CMD:
+		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+			break;
 		/* we have been given the name of the Ethernet Device we want to
 		 * talk to:  args.dev1	 We also have the
 		 * VLAN ID:  args.u.VID
 		 */
-		if (register_vlan_device(args.device1, args.u.VID)) {
+		if (register_vlan_device(dev, args.u.VID)) {
 			err = 0;
 		} else {
 			err = -EINVAL;
@@ -764,12 +746,10 @@ static int vlan_ioctl_handler(void __user *arg)
 		break;
 
 	case DEL_VLAN_CMD:
+		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		/* Here, the args.dev1 is the actual VLAN we want
-		 * to get rid of.
-		 */
-		err = unregister_vlan_device(args.device1);
+			break;
+		err = unregister_vlan_device(dev);
 		break;
 
 	case GET_VLAN_INGRESS_PRIORITY_CMD:
@@ -793,9 +773,7 @@ static int vlan_ioctl_handler(void __user *arg)
 		err = -EINVAL;
 		break;
 	case GET_VLAN_REALDEV_NAME_CMD:
-		err = vlan_dev_get_realdev_name(args.device1, args.u.device2);
-		if (err)
-			goto out;
+		vlan_dev_get_realdev_name(dev, args.u.device2);
 		if (copy_to_user(arg, &args,
 				 sizeof(struct vlan_ioctl_args))) {
 			err = -EFAULT;
@@ -803,9 +781,7 @@ static int vlan_ioctl_handler(void __user *arg)
 		break;
 
 	case GET_VLAN_VID_CMD:
-		err = vlan_dev_get_vid(args.device1, &vid);
-		if (err)
-			goto out;
+		vlan_dev_get_vid(dev, &vid);
 		args.u.VID = vid;
 		if (copy_to_user(arg, &args,
 				 sizeof(struct vlan_ioctl_args))) {
@@ -817,9 +793,11 @@ static int vlan_ioctl_handler(void __user *arg)
 		/* pass on to underlying device instead?? */
 		printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
 			__FUNCTION__, args.cmd);
-		return -EINVAL;
+		err = -EINVAL;
+		break;
 	}
 out:
+	rtnl_unlock();
 	return err;
 }
 
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 1976cdb..b837390 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -62,11 +62,14 @@ int vlan_dev_set_mac_address(struct net_device *dev, void* addr);
 int vlan_dev_open(struct net_device* dev);
 int vlan_dev_stop(struct net_device* dev);
 int vlan_dev_ioctl(struct net_device* dev, struct ifreq *ifr, int cmd);
-int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
-int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
-int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val);
-int vlan_dev_get_realdev_name(const char* dev_name, char* result);
-int vlan_dev_get_vid(const char* dev_name, unsigned short* result);
+void vlan_dev_set_ingress_priority(const struct net_device *dev,
+				   u32 skb_prio, short vlan_prio);
+int vlan_dev_set_egress_priority(const struct net_device *dev,
+				 u32 skb_prio, short vlan_prio);
+int vlan_dev_set_vlan_flag(const struct net_device *dev,
+			   u32 flag, short flag_val);
+void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
+void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
 void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
 
 #endif /* !(__BEN_VLAN_802_1Q_INC__) */
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index ec46084..0b7e03e 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -534,136 +534,69 @@ int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
 	return 0;
 }
 
-int vlan_dev_set_ingress_priority(char *dev_name, __u32 skb_prio, short vlan_prio)
+void vlan_dev_set_ingress_priority(const struct net_device *dev,
+				   u32 skb_prio, short vlan_prio)
 {
-	struct net_device *dev = dev_get_by_name(dev_name);
-
-	if (dev) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			/* see if a priority mapping exists.. */
-			VLAN_DEV_INFO(dev)->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
-			dev_put(dev);
-			return 0;
-		}
-
-		dev_put(dev);
-	}
-	return -EINVAL;
+	VLAN_DEV_INFO(dev)->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
 }
 
-int vlan_dev_set_egress_priority(char *dev_name, __u32 skb_prio, short vlan_prio)
+int vlan_dev_set_egress_priority(const struct net_device *dev,
+				 u32 skb_prio, short vlan_prio)
 {
-	struct net_device *dev = dev_get_by_name(dev_name);
 	struct vlan_priority_tci_mapping *mp = NULL;
 	struct vlan_priority_tci_mapping *np;
 
-	if (dev) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			/* See if a priority mapping exists.. */
-			mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
-			while (mp) {
-				if (mp->priority == skb_prio) {
-					mp->vlan_qos = ((vlan_prio << 13) & 0xE000);
-					dev_put(dev);
-					return 0;
-				}
-				mp = mp->next;
-			}
-
-			/* Create a new mapping then. */
-			mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
-			np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
-			if (np) {
-				np->next = mp;
-				np->priority = skb_prio;
-				np->vlan_qos = ((vlan_prio << 13) & 0xE000);
-				VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF] = np;
-				dev_put(dev);
-				return 0;
-			} else {
-				dev_put(dev);
-				return -ENOBUFS;
-			}
+	/* See if a priority mapping exists.. */
+	mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
+	while (mp) {
+		if (mp->priority == skb_prio) {
+			mp->vlan_qos = ((vlan_prio << 13) & 0xE000);
+			return 0;
 		}
-		dev_put(dev);
+		mp = mp->next;
 	}
-	return -EINVAL;
+
+	/* Create a new mapping then. */
+	mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
+	np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
+	if (!np)
+		return -ENOBUFS;
+
+	np->next = mp;
+	np->priority = skb_prio;
+	np->vlan_qos = ((vlan_prio << 13) & 0xE000);
+	VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF] = np;
+	return 0;
 }
 
 /* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */
-int vlan_dev_set_vlan_flag(char *dev_name, __u32 flag, short flag_val)
+int vlan_dev_set_vlan_flag(const struct net_device *dev,
+			   u32 flag, short flag_val)
 {
-	struct net_device *dev = dev_get_by_name(dev_name);
-
-	if (dev) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			/* verify flag is supported */
-			if (flag == 1) {
-				if (flag_val) {
-					VLAN_DEV_INFO(dev)->flags |= 1;
-				} else {
-					VLAN_DEV_INFO(dev)->flags &= ~1;
-				}
-				dev_put(dev);
-				return 0;
-			} else {
-				printk(KERN_ERR  "%s: flag %i is not valid.\n",
-					__FUNCTION__, (int)(flag));
-				dev_put(dev);
-				return -EINVAL;
-			}
+	/* verify flag is supported */
+	if (flag == 1) {
+		if (flag_val) {
+			VLAN_DEV_INFO(dev)->flags |= 1;
 		} else {
-			printk(KERN_ERR
-			       "%s: %s is not a vlan device, priv_flags: %hX.\n",
-			       __FUNCTION__, dev->name, dev->priv_flags);
-			dev_put(dev);
+			VLAN_DEV_INFO(dev)->flags &= ~1;
 		}
-	} else {
-		printk(KERN_ERR  "%s: Could not find device: %s\n",
-			__FUNCTION__, dev_name);
+		return 0;
 	}
-
+	printk(KERN_ERR  "%s: flag %i is not valid.\n",
+			__FUNCTION__, (int)(flag));
 	return -EINVAL;
 }
 
-
-int vlan_dev_get_realdev_name(const char *dev_name, char* result)
+void vlan_dev_get_realdev_name(const struct net_device *dev, char *result)
 {
-	struct net_device *dev = dev_get_by_name(dev_name);
-	int rv = 0;
-	if (dev) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23);
-			rv = 0;
-		} else {
-			rv = -EINVAL;
-		}
-		dev_put(dev);
-	} else {
-		rv = -ENODEV;
-	}
-	return rv;
+	strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23);
 }
 
-int vlan_dev_get_vid(const char *dev_name, unsigned short* result)
+void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result)
 {
-	struct net_device *dev = dev_get_by_name(dev_name);
-	int rv = 0;
-	if (dev) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			*result = VLAN_DEV_INFO(dev)->vlan_id;
-			rv = 0;
-		} else {
-			rv = -EINVAL;
-		}
-		dev_put(dev);
-	} else {
-		rv = -ENODEV;
-	}
-	return rv;
+	*result = VLAN_DEV_INFO(dev)->vlan_id;
 }
 
-
 int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p)
 {
 	struct sockaddr *addr = (struct sockaddr *)(addr_struct_p);

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 02/08]: Remove unregister_vlan_dev wrapper
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 01/08]: Move device lookup to ioctl handler Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 03/08]: Add device init callback Patrick McHardy
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Remove unregister_vlan_dev wrapper

Remove the now useless unregister_vlan_dev wrapper by moving the final
unregister_netdev to unregister_vlan_dev itself. Also replace a few
impossible conditions by BUG_ON and don't try to handle them as valid.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 7286bd4222a1a9722b1d3b80988078b0af973a67
tree e9a21434dc634051d99513432b051b3e18c5e5c7
parent b2981f2b9c99d414e9ea990cda7ca31c5bef2420
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:16 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:16 +0200

 net/8021q/vlan.c |  140 +++++++++++++++++++-----------------------------------
 1 files changed, 48 insertions(+), 92 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 0d95388..87de961 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -51,7 +51,7 @@ static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
 static int vlan_device_event(struct notifier_block *, unsigned long, void *);
 static int vlan_ioctl_handler(void __user *);
-static int unregister_vlan_dev(struct net_device *, unsigned short );
+static int unregister_vlan_dev(struct net_device *);
 
 static struct notifier_block vlan_notifier_block = {
 	.notifier_call = vlan_device_event,
@@ -118,12 +118,8 @@ static void __exit vlan_cleanup_devices(void)
 
 	rtnl_lock();
 	for_each_netdev_safe(dev, nxt) {
-		if (dev->priv_flags & IFF_802_1Q_VLAN) {
-			unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
-					    VLAN_DEV_INFO(dev)->vlan_id);
-
-			unregister_netdevice(dev);
-		}
+		if (dev->priv_flags & IFF_802_1Q_VLAN)
+			unregister_vlan_dev(dev);
 	}
 	rtnl_unlock();
 }
@@ -202,94 +198,61 @@ static void vlan_rcu_free(struct rcu_head *rcu)
 	vlan_group_free(container_of(rcu, struct vlan_group, rcu));
 }
 
-
-/* This returns 0 if everything went fine.
- * It will return 1 if the group was killed as a result.
- * A negative return indicates failure.
- *
- * The RTNL lock must be held.
+/* Destroy a VLAN device. Returns 1 if the device destroyed was the
+ * last one on the underlying device and the group was destroyed,
+ * 0 otherwise.
  */
-static int unregister_vlan_dev(struct net_device *real_dev,
-			       unsigned short vlan_id)
+static int unregister_vlan_dev(struct net_device *dev)
 {
-	struct net_device *dev = NULL;
-	int real_dev_ifindex = real_dev->ifindex;
+	struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
+	unsigned short vlan_id = VLAN_DEV_INFO(dev)->vlan_id;
 	struct vlan_group *grp;
-	int i, ret;
+	int i, ret = 0;
 
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "%s: VID: %i\n", __FUNCTION__, vlan_id);
 #endif
+	ASSERT_RTNL();
 
-	/* sanity check */
-	if (vlan_id >= VLAN_VID_MASK)
-		return -EINVAL;
+	grp = __vlan_find_group(real_dev->ifindex);
 
-	ASSERT_RTNL();
-	grp = __vlan_find_group(real_dev_ifindex);
-
-	ret = 0;
-
-	if (grp) {
-		dev = vlan_group_get_device(grp, vlan_id);
-		if (dev) {
-			/* Remove proc entry */
-			vlan_proc_rem_dev(dev);
-
-			/* Take it out of our own structures, but be sure to
-			 * interlock with HW accelerating devices or SW vlan
-			 * input packet processing.
-			 */
-			if (real_dev->features &
-			    (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER)) {
-				real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
-			}
-
-			vlan_group_set_device(grp, vlan_id, NULL);
-			synchronize_net();
-
-
-			/* Caller unregisters (and if necessary, puts)
-			 * VLAN device, but we get rid of the reference to
-			 * real_dev here.
-			 */
-			dev_put(real_dev);
-
-			/* If the group is now empty, kill off the
-			 * group.
-			 */
-			for (i = 0; i < VLAN_VID_MASK; i++)
-				if (vlan_group_get_device(grp, i))
-					break;
-
-			if (i == VLAN_VID_MASK) {
-				if (real_dev->features & NETIF_F_HW_VLAN_RX)
-					real_dev->vlan_rx_register(real_dev, NULL);
-
-				hlist_del_rcu(&grp->hlist);
-
-				/* Free the group, after all cpu's are done. */
-				call_rcu(&grp->rcu, vlan_rcu_free);
-
-				grp = NULL;
-				ret = 1;
-			}
-		}
-	}
+	BUG_ON(!grp);
+	BUG_ON(vlan_id >= VLAN_VID_MASK);
+	BUG_ON(vlan_group_get_device(grp, vlan_id) != dev);
 
-	return ret;
-}
+	/* Remove proc entry */
+	vlan_proc_rem_dev(dev);
 
-static int unregister_vlan_device(struct net_device *dev)
-{
-	int ret;
+	/* Take it out of our own structures, but be sure to interlock with
+	 * HW accelerating devices or SW vlan input packet processing.
+	 */
+	if (real_dev->features &
+	    (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER))
+		real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
 
-	ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
-				  VLAN_DEV_INFO(dev)->vlan_id);
-	unregister_netdevice(dev);
+	vlan_group_set_device(grp, vlan_id, NULL);
+	synchronize_net();
+
+	/* Get rid of the reference to real_dev in struct vlan_dev_info */
+	dev_put(real_dev);
+
+	/* If the group is now empty, kill off the group. */
+	for (i = 0; i < VLAN_VID_MASK; i++)
+		if (vlan_group_get_device(grp, i))
+			break;
+
+	if (i == VLAN_VID_MASK) {
+		if (real_dev->features & NETIF_F_HW_VLAN_RX)
+			real_dev->vlan_rx_register(real_dev, NULL);
 
-	if (ret == 1)
-		ret = 0;
+		hlist_del_rcu(&grp->hlist);
+
+		/* Free the group, after all cpu's are done. */
+		call_rcu(&grp->rcu, vlan_rcu_free);
+		ret = 1;
+
+	}
+	unregister_netdevice(dev);
 	return ret;
 }
 
@@ -623,19 +586,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
 	case NETDEV_UNREGISTER:
 		/* Delete all VLANs for this dev. */
 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-			int ret;
-
 			vlandev = vlan_group_get_device(grp, i);
 			if (!vlandev)
 				continue;
 
-			ret = unregister_vlan_dev(dev,
-						  VLAN_DEV_INFO(vlandev)->vlan_id);
-
-			unregister_netdevice(vlandev);
-
-			/* Group was destroyed? */
-			if (ret == 1)
+			if (unregister_vlan_dev(vlandev))
+				/* Group was destroyed? */
 				break;
 		}
 		break;
@@ -749,7 +705,7 @@ static int vlan_ioctl_handler(void __user *arg)
 		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
 			break;
-		err = unregister_vlan_device(dev);
+		err = unregister_vlan_dev(dev);
 		break;
 
 	case GET_VLAN_INGRESS_PRIORITY_CMD:

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 03/08]: Add device init callback
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 01/08]: Move device lookup to ioctl handler Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 02/08]: Remove unregister_vlan_dev wrapper Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 04/08]: Move vlan_group allocation to seperate function Patrick McHardy
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Add device init callback

Move device initialization to ->init callback to fix an incorrect iflink
value in the initial NEWLINK message. Additionally this makes sure the
lockdep class is properly set before the device will be used.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit c771a6df20db3f21062bbbf56f09f2a64535cb71
tree 7068db9a14adb06df077b6634318db72d0eb6c7d
parent 7286bd4222a1a9722b1d3b80988078b0af973a67
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:16 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:16 +0200

 net/8021q/vlan.c |  103 +++++++++++++++++++++++++++---------------------------
 1 files changed, 52 insertions(+), 51 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 87de961..c745530 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -256,6 +256,53 @@ static int unregister_vlan_dev(struct net_device *dev)
 	return ret;
 }
 
+/*
+ * vlan network devices have devices nesting below it, and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key vlan_netdev_xmit_lock_key;
+
+static int vlan_dev_init(struct net_device *dev)
+{
+	struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
+
+	/* IFF_BROADCAST|IFF_MULTICAST; ??? */
+	dev->flags  = real_dev->flags & ~IFF_UP;
+	dev->iflink = real_dev->ifindex;
+	dev->state  = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
+					  (1<<__LINK_STATE_DORMANT))) |
+		      (1<<__LINK_STATE_PRESENT);
+
+	/* need 4 bytes for extra VLAN header info,
+	 * hope the underlying device can handle it.
+	 */
+	dev->mtu = real_dev->mtu;
+
+	/* TODO: maybe just assign it to be ETHERNET? */
+	dev->type = real_dev->type;
+
+	memcpy(dev->broadcast, real_dev->broadcast, real_dev->addr_len);
+	memcpy(dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
+	dev->addr_len = real_dev->addr_len;
+
+	if (real_dev->features & NETIF_F_HW_VLAN_TX) {
+		dev->hard_header     = real_dev->hard_header;
+		dev->hard_header_len = real_dev->hard_header_len;
+		dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
+		dev->rebuild_header  = real_dev->rebuild_header;
+	} else {
+		dev->hard_header     = vlan_dev_hard_header;
+		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
+		dev->hard_start_xmit = vlan_dev_hard_start_xmit;
+		dev->rebuild_header  = vlan_dev_rebuild_header;
+	}
+	dev->hard_header_parse = real_dev->hard_header_parse;
+
+	lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
+	return 0;
+}
+
 static void vlan_setup(struct net_device *new_dev)
 {
 	SET_MODULE_OWNER(new_dev);
@@ -276,6 +323,7 @@ static void vlan_setup(struct net_device *new_dev)
 
 	/* set up method calls */
 	new_dev->change_mtu = vlan_dev_change_mtu;
+	new_dev->init = vlan_dev_init;
 	new_dev->open = vlan_dev_open;
 	new_dev->stop = vlan_dev_stop;
 	new_dev->set_mac_address = vlan_dev_set_mac_address;
@@ -304,14 +352,6 @@ static void vlan_transfer_operstate(const struct net_device *dev, struct net_dev
 	}
 }
 
-/*
- * vlan network devices have devices nesting below it, and are a special
- * "super class" of normal network devices; split their locks off into a
- * separate class since they always nest.
- */
-static struct lock_class_key vlan_netdev_xmit_lock_key;
-
-
 /*  Attach a VLAN device to a mac address (ie Ethernet Card).
  *  Returns the device that was created, or NULL if there was
  *  an error of some kind.
@@ -405,52 +445,16 @@ static struct net_device *register_vlan_device(struct net_device *real_dev,
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
 #endif
-	/* IFF_BROADCAST|IFF_MULTICAST; ??? */
-	new_dev->flags = real_dev->flags;
-	new_dev->flags &= ~IFF_UP;
-
-	new_dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
-					     (1<<__LINK_STATE_DORMANT))) |
-			 (1<<__LINK_STATE_PRESENT);
-
-	/* need 4 bytes for extra VLAN header info,
-	 * hope the underlying device can handle it.
-	 */
-	new_dev->mtu = real_dev->mtu;
-
-	/* TODO: maybe just assign it to be ETHERNET? */
-	new_dev->type = real_dev->type;
-
-	new_dev->hard_header_len = real_dev->hard_header_len;
-	if (!(real_dev->features & NETIF_F_HW_VLAN_TX)) {
-		/* Regular ethernet + 4 bytes (18 total). */
-		new_dev->hard_header_len += VLAN_HLEN;
-	}
-
-	VLAN_MEM_DBG("new_dev->priv malloc, addr: %p  size: %i\n",
-		     new_dev->priv,
-		     sizeof(struct vlan_dev_info));
-
-	memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len);
-	memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
-	new_dev->addr_len = real_dev->addr_len;
-
-	if (real_dev->features & NETIF_F_HW_VLAN_TX) {
-		new_dev->hard_header = real_dev->hard_header;
-		new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
-		new_dev->rebuild_header = real_dev->rebuild_header;
-	} else {
-		new_dev->hard_header = vlan_dev_hard_header;
-		new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
-		new_dev->rebuild_header = vlan_dev_rebuild_header;
-	}
-	new_dev->hard_header_parse = real_dev->hard_header_parse;
 
 	VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
 	VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
 	VLAN_DEV_INFO(new_dev)->dent = NULL;
 	VLAN_DEV_INFO(new_dev)->flags = 1;
 
+	VLAN_MEM_DBG("new_dev->priv malloc, addr: %p  size: %i\n",
+		     new_dev->priv,
+		     sizeof(struct vlan_dev_info));
+
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "About to go find the group for idx: %i\n",
 	       real_dev->ifindex);
@@ -459,9 +463,6 @@ static struct net_device *register_vlan_device(struct net_device *real_dev,
 	if (register_netdevice(new_dev))
 		goto out_free_newdev;
 
-	lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
-
-	new_dev->iflink = real_dev->ifindex;
 	vlan_transfer_operstate(real_dev, new_dev);
 	linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
 

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 04/08]: Move vlan_group allocation to seperate function
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (2 preceding siblings ...)
  2007-06-05 14:23 ` [RFC VLAN 03/08]: Add device init callback Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 05/08]: Split up device creation Patrick McHardy
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Move vlan_group allocation to seperate function

Move group allocation to a seperate function to clean up the code a bit
and allocate groups before registering the device. Device registration
is globally visible and causes netlink events, so we shouldn't fail
afterwards.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 1057887432918a89e5b374c29ac36224716cb0e4
tree 280fcd63f25b1c19053285d5b0ebf983a95e08a9
parent c771a6df20db3f21062bbbf56f09f2a64535cb71
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:16 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 15:48:16 +0200

 net/8021q/vlan.c |   78 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 41 insertions(+), 37 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index c745530..d470913 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -193,6 +193,34 @@ static void vlan_group_free(struct vlan_group *grp)
 	kfree(grp);
 }
 
+static struct vlan_group *vlan_group_alloc(int ifindex)
+{
+	struct vlan_group *group;
+	unsigned int size;
+	unsigned int i;
+
+	group = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
+	if (!group)
+		return NULL;
+
+	size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
+
+	for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
+		group->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL);
+		if (!group->vlan_devices_arrays[i])
+			goto err;
+	}
+
+	group->real_dev_ifindex = ifindex;
+	hlist_add_head_rcu(&group->hlist,
+			   &vlan_group_hash[vlan_grp_hashfn(ifindex)]);
+	return group;
+
+err:
+	vlan_group_free(group);
+	return NULL;
+}
+
 static void vlan_rcu_free(struct rcu_head *rcu)
 {
 	vlan_group_free(container_of(rcu, struct vlan_group, rcu));
@@ -359,10 +387,9 @@ static void vlan_transfer_operstate(const struct net_device *dev, struct net_dev
 static struct net_device *register_vlan_device(struct net_device *real_dev,
 					       unsigned short VLAN_ID)
 {
-	struct vlan_group *grp;
+	struct vlan_group *grp, *reg = NULL;
 	struct net_device *new_dev;
 	char name[IFNAMSIZ];
-	int i;
 
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "%s: if_name -:%s:-	vid: %i\n",
@@ -459,9 +486,15 @@ static struct net_device *register_vlan_device(struct net_device *real_dev,
 	printk(VLAN_DBG "About to go find the group for idx: %i\n",
 	       real_dev->ifindex);
 #endif
+	grp = __vlan_find_group(real_dev->ifindex);
+	if (!grp) {
+		reg = grp = vlan_group_alloc(real_dev->ifindex);
+		if (!grp)
+			goto out_free_newdev;
+	}
 
 	if (register_netdevice(new_dev))
-		goto out_free_newdev;
+		goto out_free_group;
 
 	vlan_transfer_operstate(real_dev, new_dev);
 	linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
@@ -469,34 +502,8 @@ static struct net_device *register_vlan_device(struct net_device *real_dev,
 	/* So, got the sucker initialized, now lets place
 	 * it into our local structure.
 	 */
-	grp = __vlan_find_group(real_dev->ifindex);
-
-	/* Note, we are running under the RTNL semaphore
-	 * so it cannot "appear" on us.
-	 */
-	if (!grp) { /* need to add a new group */
-		grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
-		if (!grp)
-			goto out_free_unregister;
-
-		for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
-			grp->vlan_devices_arrays[i] = kzalloc(
-				sizeof(struct net_device *)*VLAN_GROUP_ARRAY_PART_LEN,
-				GFP_KERNEL);
-
-			if (!grp->vlan_devices_arrays[i])
-				goto out_free_arrays;
-		}
-
-		/* printk(KERN_ALERT "VLAN REGISTER:  Allocated new group.\n"); */
-		grp->real_dev_ifindex = real_dev->ifindex;
-
-		hlist_add_head_rcu(&grp->hlist,
-				   &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
-
-		if (real_dev->features & NETIF_F_HW_VLAN_RX)
-			real_dev->vlan_rx_register(real_dev, grp);
-	}
+	if (reg && real_dev->features & NETIF_F_HW_VLAN_RX)
+		real_dev->vlan_rx_register(real_dev, reg);
 
 	vlan_group_set_device(grp, VLAN_ID, new_dev);
 
@@ -514,12 +521,9 @@ static struct net_device *register_vlan_device(struct net_device *real_dev,
 #endif
 	return new_dev;
 
-out_free_arrays:
-	vlan_group_free(grp);
-
-out_free_unregister:
-	unregister_netdev(new_dev);
-	goto out_ret_null;
+out_free_group:
+	if (reg)
+		vlan_group_free(reg);
 
 out_free_newdev:
 	free_netdev(new_dev);

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 05/08]: Split up device creation
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (3 preceding siblings ...)
  2007-06-05 14:23 ` [RFC VLAN 04/08]: Move vlan_group allocation to seperate function Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 06/08]: Use 32 bit value for skb->priority mapping Patrick McHardy
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Split up device creation

Split up device creation in allocation/registration functions taking
struct net_device * and a small wrapper for the ioctl handling. This is
needed by the netlink interface to properly set up the device before
registration.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit c59e99d32d8085f8ed1aa794106c28e546220581
tree dca7eeb9815666e863e5739a8c0a4698333026bc
parent 1057887432918a89e5b374c29ac36224716cb0e4
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:52:41 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:52:41 +0200

 net/8021q/vlan.c |  196 ++++++++++++++++++++++++++----------------------------
 net/8021q/vlan.h |    4 +
 2 files changed, 100 insertions(+), 100 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index d470913..e5405cf 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -380,64 +380,110 @@ static void vlan_transfer_operstate(const struct net_device *dev, struct net_dev
 	}
 }
 
-/*  Attach a VLAN device to a mac address (ie Ethernet Card).
- *  Returns the device that was created, or NULL if there was
- *  an error of some kind.
- */
-static struct net_device *register_vlan_device(struct net_device *real_dev,
-					       unsigned short VLAN_ID)
+int vlan_check_device(struct net_device *dev, unsigned short vlan_id)
 {
-	struct vlan_group *grp, *reg = NULL;
-	struct net_device *new_dev;
-	char name[IFNAMSIZ];
-
-#ifdef VLAN_DEBUG
-	printk(VLAN_DBG "%s: if_name -:%s:-	vid: %i\n",
-		__FUNCTION__, eth_IF_name, VLAN_ID);
-#endif
-
-	if (VLAN_ID >= VLAN_VID_MASK)
-		goto out_ret_null;
-
-	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
+	if (dev->features & NETIF_F_VLAN_CHALLENGED) {
 		printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
-			__FUNCTION__, real_dev->name);
-		goto out_ret_null;
+			__FUNCTION__, dev->name);
+		return -EOPNOTSUPP;
 	}
 
-	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
-	    (real_dev->vlan_rx_register == NULL ||
-	     real_dev->vlan_rx_kill_vid == NULL)) {
+	if ((dev->features & NETIF_F_HW_VLAN_RX) &&
+	    (dev->vlan_rx_register == NULL || dev->vlan_rx_kill_vid == NULL)) {
 		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
-			__FUNCTION__, real_dev->name);
-		goto out_ret_null;
+			__FUNCTION__, dev->name);
+		return -EOPNOTSUPP;
 	}
 
-	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-	    (real_dev->vlan_rx_add_vid == NULL ||
-	     real_dev->vlan_rx_kill_vid == NULL)) {
+	if ((dev->features & NETIF_F_HW_VLAN_FILTER) &&
+	    (dev->vlan_rx_add_vid == NULL || dev->vlan_rx_kill_vid == NULL)) {
 		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
-			__FUNCTION__, real_dev->name);
-		goto out_ret_null;
+			__FUNCTION__, dev->name);
+		return -EOPNOTSUPP;
 	}
 
 	/* The real device must be up and operating in order to
-	 * assosciate a VLAN device with it.
+	 * associate a VLAN device with it.
 	 */
-	if (!(real_dev->flags & IFF_UP))
-		goto out_ret_null;
+	if (!(dev->flags & IFF_UP))
+		return -ENETDOWN;
 
-	if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) {
-		/* was already registered. */
-		printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
-		goto out_ret_null;
+	if (__find_vlan_dev(dev, vlan_id) != NULL)
+		return -EEXIST;
+
+	return 0;
+}
+
+int vlan_register_dev(struct net_device *dev)
+{
+	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+	struct net_device *real_dev = vlan->real_dev;
+	struct vlan_group *group, *reg = NULL;
+	int err;
+
+	group = __vlan_find_group(real_dev->ifindex);
+	if (!group) {
+		err = -ENOMEM;
+		group = reg = vlan_group_alloc(real_dev->ifindex);
+		if (!group)
+			goto err1;
 	}
 
-	/* Gotta set up the fields for the device. */
+	err = register_netdevice(dev);
+	if (err < 0)
+		goto err2;
+
+	/* Account for reference in struct vlan_dev_info */
+	dev_hold(real_dev);
+
+	vlan_transfer_operstate(real_dev, dev);
+	linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
+
+	/* So, got the sucker initialized, now lets place
+	 * it into our local structure.
+	 */
+	vlan_group_set_device(group, vlan->vlan_id, dev);
+
+	if (reg && real_dev->features & NETIF_F_HW_VLAN_RX)
+		real_dev->vlan_rx_register(real_dev, reg);
+	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
+		real_dev->vlan_rx_add_vid(real_dev, vlan->vlan_id);
+
+	if (vlan_proc_add_dev(dev) < 0)
+		printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
+		       dev->name);
+	return 0;
+
+err2:
+	if (reg)
+		vlan_group_free(reg);
+err1:
+	return err;
+}
+
+/*  Attach a VLAN device to a mac address (ie Ethernet Card).
+ *  Returns 0 if the device was created or a negative error code otherwise.
+ */
+static int register_vlan_device(struct net_device *real_dev,
+				unsigned short VLAN_ID)
+{
+	struct net_device *new_dev;
+	char name[IFNAMSIZ];
+	int err;
+
 #ifdef VLAN_DEBUG
-	printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n",
-	       vlan_name_type);
+	printk(VLAN_DBG "%s: if_name -:%s:-	vid: %i\n",
+		__FUNCTION__, eth_IF_name, VLAN_ID);
 #endif
+
+	if (VLAN_ID >= VLAN_VID_MASK)
+		return -ERANGE;
+
+	err = vlan_check_device(real_dev, VLAN_ID);
+	if (err < 0)
+		return err;
+
+	/* Gotta set up the fields for the device. */
 	switch (vlan_name_type) {
 	case VLAN_NAME_TYPE_RAW_PLUS_VID:
 		/* name will look like:	 eth1.0005 */
@@ -465,71 +511,25 @@ static struct net_device *register_vlan_device(struct net_device *real_dev,
 
 	new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
 			       vlan_setup);
-
 	if (new_dev == NULL)
-		goto out_ret_null;
+		return -ENOMEM;
 
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
-#endif
-
-	VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
-	VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
-	VLAN_DEV_INFO(new_dev)->dent = NULL;
-	VLAN_DEV_INFO(new_dev)->flags = 1;
-
 	VLAN_MEM_DBG("new_dev->priv malloc, addr: %p  size: %i\n",
 		     new_dev->priv,
 		     sizeof(struct vlan_dev_info));
-
-#ifdef VLAN_DEBUG
-	printk(VLAN_DBG "About to go find the group for idx: %i\n",
-	       real_dev->ifindex);
-#endif
-	grp = __vlan_find_group(real_dev->ifindex);
-	if (!grp) {
-		reg = grp = vlan_group_alloc(real_dev->ifindex);
-		if (!grp)
-			goto out_free_newdev;
-	}
-
-	if (register_netdevice(new_dev))
-		goto out_free_group;
-
-	vlan_transfer_operstate(real_dev, new_dev);
-	linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
-
-	/* So, got the sucker initialized, now lets place
-	 * it into our local structure.
-	 */
-	if (reg && real_dev->features & NETIF_F_HW_VLAN_RX)
-		real_dev->vlan_rx_register(real_dev, reg);
-
-	vlan_group_set_device(grp, VLAN_ID, new_dev);
-
-	if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */
-		printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
-							 new_dev->name);
-
-	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
-		real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
-
-	/* Account for reference in struct vlan_dev_info */
-	dev_hold(real_dev);
-#ifdef VLAN_DEBUG
-	printk(VLAN_DBG "Allocated new device successfully, returning.\n");
 #endif
-	return new_dev;
 
-out_free_group:
-	if (reg)
-		vlan_group_free(reg);
+	VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
+	VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
+	VLAN_DEV_INFO(new_dev)->flags = 1;
 
-out_free_newdev:
-	free_netdev(new_dev);
+	err = vlan_register_dev(new_dev);
+	if (err < 0)
+		free_netdev(new_dev);
 
-out_ret_null:
-	return NULL;
+	return 0;
 }
 
 static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
@@ -699,11 +699,7 @@ static int vlan_ioctl_handler(void __user *arg)
 		 * talk to:  args.dev1	 We also have the
 		 * VLAN ID:  args.u.VID
 		 */
-		if (register_vlan_device(dev, args.u.VID)) {
-			err = 0;
-		} else {
-			err = -EINVAL;
-		}
+		err = register_vlan_device(dev, args.u.VID);
 		break;
 
 	case DEL_VLAN_CMD:
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index b837390..47f0c53 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -72,4 +72,8 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
 void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
 void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
 
+int vlan_check_device(struct net_device *dev, unsigned short vlan_id);
+int vlan_register_dev(struct net_device *dev);
+int vlan_unregister_dev(struct net_device *dev);
+
 #endif /* !(__BEN_VLAN_802_1Q_INC__) */

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 06/08]: Use 32 bit value for skb->priority mapping
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (4 preceding siblings ...)
  2007-06-05 14:23 ` [RFC VLAN 05/08]: Split up device creation Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 07/08]: Keep track of number of QoS mappings Patrick McHardy
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Use 32 bit value for skb->priority mapping

skb->priority has only 32 bits and even VLAN uses 32 bit values in its
API.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 24b7a56049e5e9f63e6fc5933d10b47c15294fea
tree 7c1d37c5c3b9f09c3c7d726d6fa922454d57bf16
parent c59e99d32d8085f8ed1aa794106c28e546220581
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:52:48 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:52:48 +0200

 include/linux/if_vlan.h |    4 ++--
 net/8021q/vlanproc.c    |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 81e9bc9..1889b29 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -99,7 +99,7 @@ static inline void vlan_group_set_device(struct vlan_group *vg, int vlan_id,
 }
 
 struct vlan_priority_tci_mapping {
-	unsigned long priority;
+	unsigned int priority;
 	unsigned short vlan_qos; /* This should be shifted when first set, so we only do it
 				  * at provisioning time.
 				  * ((skb->priority << 13) & 0xE000)
@@ -112,7 +112,7 @@ struct vlan_dev_info {
 	/** This will be the mapping that correlates skb->priority to
 	 * 3 bits of VLAN QOS tags...
 	 */
-	unsigned long ingress_priority_map[8];
+	unsigned int ingress_priority_map[8];
 	struct vlan_priority_tci_mapping *egress_priority_map[16]; /* hash table */
 
 	unsigned short vlan_id;        /*  The VLAN Identifier for this interface. */
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index d216a64..8693b21 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -342,7 +342,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
 	seq_printf(seq, "Device: %s", dev_info->real_dev->name);
 	/* now show all PRIORITY mappings relating to this VLAN */
 	seq_printf(seq,
-		       "\nINGRESS priority mappings: 0:%lu  1:%lu  2:%lu  3:%lu  4:%lu  5:%lu  6:%lu 7:%lu\n",
+		       "\nINGRESS priority mappings: 0:%u  1:%u  2:%u  3:%u  4:%u  5:%u  6:%u 7:%u\n",
 		       dev_info->ingress_priority_map[0],
 		       dev_info->ingress_priority_map[1],
 		       dev_info->ingress_priority_map[2],
@@ -357,7 +357,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
 		const struct vlan_priority_tci_mapping *mp
 			= dev_info->egress_priority_map[i];
 		while (mp) {
-			seq_printf(seq, "%lu:%hu ",
+			seq_printf(seq, "%u:%hu ",
 				   mp->priority, ((mp->vlan_qos >> 13) & 0x7));
 			mp = mp->next;
 		}

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 07/08]: Keep track of number of QoS mappings
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (5 preceding siblings ...)
  2007-06-05 14:23 ` [RFC VLAN 06/08]: Use 32 bit value for skb->priority mapping Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:23 ` [RFC VLAN 08/08]: Use rtnl_link API Patrick McHardy
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Keep track of number of QoS mappings

Keep track of the number of configured ingress/egress QoS mappings to
avoid iteration while calculating the netlink attribute size.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit fba4579d0d3c365f1ff5473e905dac68c5ec62f3
tree 892fa4a95ab163960573ee6bf1430279a1d697b8
parent 24b7a56049e5e9f63e6fc5933d10b47c15294fea
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:52:48 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:52:48 +0200

 include/linux/if_vlan.h |    4 ++++
 net/8021q/vlan_dev.c    |   27 +++++++++++++++++++++------
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 1889b29..ba48340 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -112,9 +112,13 @@ struct vlan_dev_info {
 	/** This will be the mapping that correlates skb->priority to
 	 * 3 bits of VLAN QOS tags...
 	 */
+	unsigned int nr_ingress_mappings;
 	unsigned int ingress_priority_map[8];
+
+	unsigned int nr_egress_mappings;
 	struct vlan_priority_tci_mapping *egress_priority_map[16]; /* hash table */
 
+
 	unsigned short vlan_id;        /*  The VLAN Identifier for this interface. */
 	unsigned short flags;          /* (1 << 0) re_order_header   This option will cause the
                                         *   VLAN code to move around the ethernet header on
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 0b7e03e..1644626 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -537,35 +537,50 @@ int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
 void vlan_dev_set_ingress_priority(const struct net_device *dev,
 				   u32 skb_prio, short vlan_prio)
 {
-	VLAN_DEV_INFO(dev)->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
+	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+
+	if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio)
+		vlan->nr_ingress_mappings--;
+	else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio)
+		vlan->nr_ingress_mappings++;
+
+	vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
 }
 
 int vlan_dev_set_egress_priority(const struct net_device *dev,
 				 u32 skb_prio, short vlan_prio)
 {
+	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
 	struct vlan_priority_tci_mapping *mp = NULL;
 	struct vlan_priority_tci_mapping *np;
+	u32 vlan_qos = (vlan_prio << 13) & 0xE000;
 
 	/* See if a priority mapping exists.. */
-	mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
+	mp = vlan->egress_priority_map[skb_prio & 0xF];
 	while (mp) {
 		if (mp->priority == skb_prio) {
-			mp->vlan_qos = ((vlan_prio << 13) & 0xE000);
+			if (mp->vlan_qos && !vlan_qos)
+				vlan->nr_egress_mappings--;
+			else if (!mp->vlan_qos && vlan_qos)
+				vlan->nr_egress_mappings++;
+			mp->vlan_qos = vlan_qos;
 			return 0;
 		}
 		mp = mp->next;
 	}
 
 	/* Create a new mapping then. */
-	mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
+	mp = vlan->egress_priority_map[skb_prio & 0xF];
 	np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
 	if (!np)
 		return -ENOBUFS;
 
 	np->next = mp;
 	np->priority = skb_prio;
-	np->vlan_qos = ((vlan_prio << 13) & 0xE000);
-	VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF] = np;
+	np->vlan_qos = vlan_qos;
+	vlan->egress_priority_map[skb_prio & 0xF] = np;
+	if (vlan_qos)
+		vlan->nr_egress_mappings++;
 	return 0;
 }
 

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC VLAN 08/08]: Use rtnl_link API
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (6 preceding siblings ...)
  2007-06-05 14:23 ` [RFC VLAN 07/08]: Keep track of number of QoS mappings Patrick McHardy
@ 2007-06-05 14:23 ` Patrick McHardy
  2007-06-05 14:26 ` [RFC IPROUTE]: VLAN support Patrick McHardy
  2007-06-05 14:33 ` [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:23 UTC (permalink / raw)
  To: netdev; +Cc: Patrick McHardy

[VLAN]: Use rtnl_link API

---
commit 6e11b791711627a87abfe1bd8c21a4f4d369bca6
tree 5fbe3c1ff51dd87c80748b2793878c076ed57ed7
parent fba4579d0d3c365f1ff5473e905dac68c5ec62f3
author Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:53:18 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 29 May 2007 17:53:18 +0200

 include/linux/if_link.h   |   25 ++++++
 include/linux/rtnetlink.h |    3 -
 net/8021q/Makefile        |    2 
 net/8021q/vlan.c          |   33 +++++---
 net/8021q/vlan.h          |    5 +
 net/8021q/vlan_netlink.c  |  194 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 248 insertions(+), 14 deletions(-)

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 936bd1b..b77e5a8 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -154,4 +154,29 @@ enum
 
 #define IFLA_INFO_MAX	(__IFLA_INFO_MAX - 1)
 
+enum
+{
+	IFLA_VLAN_UNSPEC,
+	IFLA_VLAN_ID,
+	IFLA_VLAN_EGRESS_QOS,
+	IFLA_VLAN_INGRESS_QOS,
+	__IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX	(__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_qos_mapping
+{
+	__u32 from;
+	__u32 to;
+};
+
+enum {
+	IFLA_VLAN_QOS_UNSPEC,
+	IFLA_VLAN_QOS_MAPPING,
+	__IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX	(__IFLA_VLAN_QOS_MAX - 1)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 6f228c7..dcc0202 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -409,7 +409,8 @@ struct rtgenmsg
 
 #define RTNL_LF_DUMMY		128
 #define RTNL_LF_IFB		129
-#define RTNL_LF_MAX		129
+#define RTNL_LF_VLAN		130
+#define RTNL_LF_MAX		130
 
 #define RTNL_LF_OFFSET		(RTNL_LF_COMPAT_END - RTNL_LF_COMPAT_MAX)
 #define RTNL_LF_NUM		(NPROTO + RTNL_LF_MAX - RTNL_LF_COMPAT_END)
diff --git a/net/8021q/Makefile b/net/8021q/Makefile
index 97feb44..10ca7f4 100644
--- a/net/8021q/Makefile
+++ b/net/8021q/Makefile
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_VLAN_8021Q) += 8021q.o
 
-8021q-objs := vlan.o vlan_dev.o
+8021q-objs := vlan.o vlan_dev.o vlan_netlink.o
 
 ifeq ($(CONFIG_PROC_FS),y)
 8021q-objs += vlanproc.o
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index e5405cf..475ca57 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -51,7 +51,6 @@ static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
 static int vlan_device_event(struct notifier_block *, unsigned long, void *);
 static int vlan_ioctl_handler(void __user *);
-static int unregister_vlan_dev(struct net_device *);
 
 static struct notifier_block vlan_notifier_block = {
 	.notifier_call = vlan_device_event,
@@ -97,15 +96,22 @@ static int __init vlan_proto_init(void)
 
 	/* Register us to receive netdevice events */
 	err = register_netdevice_notifier(&vlan_notifier_block);
-	if (err < 0) {
-		dev_remove_pack(&vlan_packet_type);
-		vlan_proc_cleanup();
-		return err;
-	}
+	if (err < 0)
+		goto err1;
 
-	vlan_ioctl_set(vlan_ioctl_handler);
+	err = vlan_netlink_init();
+	if (err < 0)
+		goto err2;
 
+	vlan_ioctl_set(vlan_ioctl_handler);
 	return 0;
+
+err2:
+	unregister_netdevice_notifier(&vlan_notifier_block);
+err1:
+	vlan_proc_cleanup();
+	dev_remove_pack(&vlan_packet_type);
+	return err;
 }
 
 /* Cleanup all vlan devices
@@ -119,7 +125,7 @@ static void __exit vlan_cleanup_devices(void)
 	rtnl_lock();
 	for_each_netdev_safe(dev, nxt) {
 		if (dev->priv_flags & IFF_802_1Q_VLAN)
-			unregister_vlan_dev(dev);
+			vlan_unregister_dev(dev);
 	}
 	rtnl_unlock();
 }
@@ -132,6 +138,7 @@ static void __exit vlan_cleanup_module(void)
 {
 	int i;
 
+	vlan_netlink_fini();
 	vlan_ioctl_set(NULL);
 
 	/* Un-register us from receiving netdevice events */
@@ -230,7 +237,7 @@ static void vlan_rcu_free(struct rcu_head *rcu)
  * last one on the underlying device and the group was destroyed,
  * 0 otherwise.
  */
-static int unregister_vlan_dev(struct net_device *dev)
+int vlan_unregister_dev(struct net_device *dev)
 {
 	struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
 	unsigned short vlan_id = VLAN_DEV_INFO(dev)->vlan_id;
@@ -331,7 +338,7 @@ static int vlan_dev_init(struct net_device *dev)
 	return 0;
 }
 
-static void vlan_setup(struct net_device *new_dev)
+void vlan_setup(struct net_device *new_dev)
 {
 	SET_MODULE_OWNER(new_dev);
 
@@ -358,6 +365,8 @@ static void vlan_setup(struct net_device *new_dev)
 	new_dev->set_multicast_list = vlan_dev_set_multicast_list;
 	new_dev->destructor = free_netdev;
 	new_dev->do_ioctl = vlan_dev_ioctl;
+
+	new_dev->link_family = RTNL_LF_VLAN;
 }
 
 static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
@@ -595,7 +604,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
 			if (!vlandev)
 				continue;
 
-			if (unregister_vlan_dev(vlandev))
+			if (vlan_unregister_dev(vlandev))
 				/* Group was destroyed? */
 				break;
 		}
@@ -706,7 +715,7 @@ static int vlan_ioctl_handler(void __user *arg)
 		err = -EPERM;
 		if (!capable(CAP_NET_ADMIN))
 			break;
-		err = unregister_vlan_dev(dev);
+		err = vlan_unregister_dev(dev);
 		break;
 
 	case GET_VLAN_INGRESS_PRIORITY_CMD:
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 47f0c53..351bd55 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -73,7 +73,12 @@ void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
 void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
 
 int vlan_check_device(struct net_device *dev, unsigned short vlan_id);
+int vlan_check_device(struct net_device *dev, unsigned short vlan_id);
+void vlan_setup(struct net_device *dev);
 int vlan_register_dev(struct net_device *dev);
 int vlan_unregister_dev(struct net_device *dev);
 
+int vlan_netlink_init(void);
+void vlan_netlink_fini(void);
+
 #endif /* !(__BEN_VLAN_802_1Q_INC__) */
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
new file mode 100644
index 0000000..32fb195
--- /dev/null
+++ b/net/8021q/vlan_netlink.c
@@ -0,0 +1,194 @@
+/*
+ *	VLAN netlink control interface
+ *
+ * 	Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
+#include <net/netlink.h>
+#include <net/rtnetlink.h>
+#include "vlan.h"
+
+
+static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
+	[IFLA_VLAN_ID]		= { .type = NLA_U16 },
+	[IFLA_VLAN_EGRESS_QOS]	= { .type = NLA_NESTED },
+	[IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
+	[IFLA_VLAN_QOS_MAPPING] = { .len = sizeof(struct ifla_vlan_qos_mapping) },
+};
+
+
+static inline int vlan_validate_qos_map(struct nlattr *attr)
+{
+	if (!attr)
+		return 0;
+	return nla_validate_nested(attr, IFLA_VLAN_QOS_MAX, vlan_map_policy);
+}
+
+static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	struct net_device *dev;
+	u16 id;
+	int err;
+
+	if (!tb[IFLA_LINK])
+		return -EINVAL;
+
+	if (!data || !data[IFLA_VLAN_ID])
+		return -EINVAL;
+
+	id = nla_get_u16(data[IFLA_VLAN_ID]);
+	if (id >= VLAN_VID_MASK)
+		return -EINVAL;
+
+	err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
+	if (err < 0)
+		return err;
+
+	err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
+	if (err < 0)
+		return err;
+
+	dev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+	if (!dev)
+		return -ENODEV;
+
+	return vlan_check_device(dev, id);
+}
+
+static int vlan_newlink(struct net_device *dev,
+			struct nlattr *tb[], struct nlattr *data[])
+{
+	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+	struct ifla_vlan_qos_mapping *m;
+	struct nlattr *attr;
+	int rem;
+
+	vlan->vlan_id  = nla_get_u16(data[IFLA_VLAN_ID]);
+	vlan->real_dev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+
+	if (data[IFLA_VLAN_INGRESS_QOS]) {
+		nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
+			m = nla_data(attr);
+			vlan_dev_set_ingress_priority(dev, m->to, m->from);
+		}
+	}
+	if (data[IFLA_VLAN_EGRESS_QOS]) {
+		nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
+			m = nla_data(attr);
+			vlan_dev_set_egress_priority(dev, m->from, m->to);
+		}
+	}
+	return vlan_register_dev(dev);
+}
+
+static void vlan_dellink(struct net_device *dev)
+{
+	vlan_unregister_dev(dev);
+}
+
+static inline size_t vlan_qos_map_size(unsigned int n)
+{
+	if (n == 0)
+		return 0;
+	/* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
+	return nla_total_size(sizeof(struct nlattr)) +
+	       nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
+}
+
+static size_t vlan_get_size(struct net_device *dev)
+{
+	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+
+	return nla_total_size(2) +	/* IFLA_VLAN_ID */
+	       vlan_qos_map_size(vlan->nr_ingress_mappings) +
+	       vlan_qos_map_size(vlan->nr_egress_mappings);
+}
+
+static int vlan_fill_info(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+	struct vlan_priority_tci_mapping *pm;
+	struct ifla_vlan_qos_mapping m;
+	struct nlattr *nest;
+	unsigned int i;
+
+	NLA_PUT_U16(skb, IFLA_VLAN_ID, VLAN_DEV_INFO(dev)->vlan_id);
+
+	if (vlan->nr_ingress_mappings) {
+		nest = nla_nest_start(skb, IFLA_VLAN_INGRESS_QOS);
+		if (nest == NULL)
+			goto nla_put_failure;
+
+		for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
+			if (!vlan->ingress_priority_map[i])
+				continue;
+
+			m.from = i;
+			m.to   = vlan->ingress_priority_map[i];
+			NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
+				sizeof(m), &m);
+		}
+		nla_nest_end(skb, nest);
+	}
+
+	if (vlan->nr_egress_mappings) {
+		nest = nla_nest_start(skb, IFLA_VLAN_EGRESS_QOS);
+		if (nest == NULL)
+			goto nla_put_failure;
+
+		for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
+			for (pm = vlan->egress_priority_map[i]; pm;
+			     pm = pm->next) {
+				if (!pm->vlan_qos)
+					continue;
+
+				m.from = pm->priority;
+				m.to   = (pm->vlan_qos >> 13) & 0x7;
+				NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
+					sizeof(m), &m);
+			}
+		}
+		nla_nest_end(skb, nest);
+	}
+	return 0;
+
+nla_put_failure:
+	return -EMSGSIZE;
+}
+
+static const struct rtnl_link_ops vlan_link_ops = {
+	.name			= "vlan",
+	.family			= RTNL_LF_VLAN,
+	.maxtype		= IFLA_VLAN_MAX,
+	.policy			= vlan_policy,
+	.dev_priv_size		= sizeof(struct vlan_dev_info),
+	.dev_setup		= vlan_setup,
+	.validate		= vlan_validate,
+	.newlink		= vlan_newlink,
+	.dellink		= vlan_dellink,
+	.get_size		= vlan_get_size,
+	.fill_info		= vlan_fill_info,
+};
+
+int __init vlan_netlink_init(void)
+{
+	return rtnl_link_register(&vlan_link_ops);
+}
+
+void __exit vlan_netlink_fini(void)
+{
+	rtnl_link_unregister(&vlan_link_ops);
+}
+
+MODULE_ALIAS_RTNL_LINK_FAMILY("vlan", RTNL_LF_VLAN);

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC IPROUTE]: VLAN support
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (7 preceding siblings ...)
  2007-06-05 14:23 ` [RFC VLAN 08/08]: Use rtnl_link API Patrick McHardy
@ 2007-06-05 14:26 ` Patrick McHardy
  2007-06-05 14:33 ` [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:26 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 503 bytes --]

This patch contains the iproute changes needed for VLAN configuration.

Examples:

Add VLAN device:

# ip link add dev eth0.1000 link eth0 type vlan \
	id 1000 \
	egress-qos-map 1:2 2:3 \
	ingress-qos-map 2:1 3:2

Show new device:

# ip link list eth0.1000

9: eth0.1000@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop
    link/ether 8e:bb:6f:05:29:e9 brd ff:ff:ff:ff:ff:ff
    vlan id 1000
      ingress-qos-map { 2:1 3:2 }
      egress-qos-map { 1:2 2:3 }

Delete device:

# ip link delete eth0.1000


[-- Attachment #2: x --]
[-- Type: text/plain, Size: 5062 bytes --]

[IPROUTE]: VLAN support

---
commit a00ac9fcbd7b84f442c5290594afa8572cf6fd8b
tree b60f6e564a83d40f8173c8dda62d9d46e51cb655
parent e59a7a02053c997a2b7ff9a4436bd3deb4781bf4
author Patrick McHardy <kaber@trash.net> Tue, 05 Jun 2007 16:20:34 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 05 Jun 2007 16:20:34 +0200

 include/linux/if_link.h |   25 ++++++++
 ip/Makefile             |    2 +
 ip/iplink_vlan.c        |  140 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index aac0df1..4ab8a07 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -150,4 +150,29 @@ enum
 
 #define IFLA_INFO_MAX	(__IFLA_INFO_MAX - 1)
 
+enum
+{
+	IFLA_VLAN_UNSPEC,
+	IFLA_VLAN_ID,
+	IFLA_VLAN_EGRESS_QOS,
+	IFLA_VLAN_INGRESS_QOS,
+	__IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX	(__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_qos_mapping
+{
+	__u32 from;
+	__u32 to;
+};
+
+enum {
+	IFLA_VLAN_QOS_UNSPEC,
+	IFLA_VLAN_QOS_MAPPING,
+	__IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX	(__IFLA_VLAN_QOS_MAX - 1)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/ip/Makefile b/ip/Makefile
index 9a5bfe3..b6d8693 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -3,6 +3,8 @@ IPOBJ=ip.o ipaddress.o iproute.o iprule.o \
     ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \
     ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o
 
+IPOBJ += iplink_vlan.o
+
 RTMONOBJ=rtmon.o
 
 ALLOBJ=$(IPOBJ) $(RTMONOBJ)
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
new file mode 100644
index 0000000..00fce6c
--- /dev/null
+++ b/ip/iplink_vlan.c
@@ -0,0 +1,140 @@
+/*
+ * iplink_vlan.c	VLAN device support
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Patrick McHardy <kaber@trash.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+	fprintf(stderr,
+		"Usage: ... vlan id VLANID [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
+		"\n"
+		"VLANID := 0-4095\n"
+		"QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
+		"QOS-MAPPING := FROM:TO\n"
+	);
+}
+
+static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
+			      int attrtype)
+{
+	int argc = *argcp;
+	char **argv = *argvp;
+	struct ifla_vlan_qos_mapping m;
+	struct rtattr *tail;
+
+	tail = NLMSG_TAIL(n);
+	addattr_l(n, 1024, attrtype, NULL, 0);
+
+	while (argc > 0) {
+		char *colon = strchr(*argv, ':');
+
+		if (!colon)
+			break;
+		*colon = '\0';
+
+		if (get_u32(&m.from, *argv, 0))
+			return 1;
+		if (get_u32(&m.to, colon + 1, 0))
+			return 1;
+		argc--, argv++;
+
+		addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
+	}
+
+	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+
+	*argcp = argc;
+	*argvp = argv;
+	return 0;
+}
+
+static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
+			  struct nlmsghdr *n)
+{
+	__u16 id;
+
+	while (argc > 0) {
+		if (matches(*argv, "id") == 0) {
+			NEXT_ARG();
+			if (get_u16(&id, *argv, 0))
+				invarg("id is invalid", *argv);
+			addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
+		} else if (matches(*argv, "ingress-qos-map") == 0) {
+			NEXT_ARG();
+			if (vlan_parse_qos_map(&argc, &argv, n,
+					       IFLA_VLAN_INGRESS_QOS))
+				invarg("invalid ingress-qos-map", *argv);
+			continue;
+		} else if (matches(*argv, "egress-qos-map") == 0) {
+			NEXT_ARG();
+			if (vlan_parse_qos_map(&argc, &argv, n,
+					       IFLA_VLAN_EGRESS_QOS))
+				invarg("invalid egress-qos-map", *argv);
+			continue;
+		} else if (matches(*argv, "help") == 0) {
+			explain();
+			return -1;
+		} else {
+			fprintf(stderr, "vlan: what is \"%s\"?\n", *argv);
+			explain();
+			return -1;
+		}
+		argc--, argv++;
+	}
+	return 0;
+}
+
+static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
+{
+	struct ifla_vlan_qos_mapping *m;
+	struct rtattr *i;
+	int rem;
+
+	
+	fprintf(f, "\n      %s { ", name);
+
+	rem = RTA_PAYLOAD(attr);
+	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		m = RTA_DATA(i);
+		fprintf(f, "%u:%u ", m->from, m->to);
+	}
+	fprintf(f, "} ");
+}
+
+static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+	if (!tb)
+		return;
+
+	if (!tb[IFLA_VLAN_ID] ||
+	    RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
+		return;
+
+	fprintf(f, "id %u", *(__u16 *)RTA_DATA(tb[IFLA_VLAN_ID]));
+
+	if (tb[IFLA_VLAN_INGRESS_QOS])
+		vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
+	if (tb[IFLA_VLAN_EGRESS_QOS])
+		vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
+}
+
+struct link_util vlan_link_util = {
+	.id		= "vlan",
+	.maxattr	= IFLA_VLAN_MAX,
+	.parse_opt	= vlan_parse_opt,
+	.print_opt	= vlan_print_opt,
+};

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [RFC VLAN 00/08]: VLAN netlink support
  2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
                   ` (8 preceding siblings ...)
  2007-06-05 14:26 ` [RFC IPROUTE]: VLAN support Patrick McHardy
@ 2007-06-05 14:33 ` Patrick McHardy
  9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2007-06-05 14:33 UTC (permalink / raw)
  To: netdev

Patrick McHardy wrote:
> These patches convert VLAN to the rtnl_link API as a more complex example.
> The patches need some more work, not all VLAN features are supported yet.


Unfortunately I managed to send the wrong patchset :(
Please ignore (only the VLAN kernel patches), new patches
coming up.


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2007-06-05 14:33 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-05 14:23 [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 01/08]: Move device lookup to ioctl handler Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 02/08]: Remove unregister_vlan_dev wrapper Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 03/08]: Add device init callback Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 04/08]: Move vlan_group allocation to seperate function Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 05/08]: Split up device creation Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 06/08]: Use 32 bit value for skb->priority mapping Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 07/08]: Keep track of number of QoS mappings Patrick McHardy
2007-06-05 14:23 ` [RFC VLAN 08/08]: Use rtnl_link API Patrick McHardy
2007-06-05 14:26 ` [RFC IPROUTE]: VLAN support Patrick McHardy
2007-06-05 14:33 ` [RFC VLAN 00/08]: VLAN netlink support Patrick McHardy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).