diff mbox

Bridge allows the userspace to configure the bridge parameters with values not defined in the IEEE 802.1D std

Message ID 1301150997-4639-1-git-send-email-sasikanth.v19@gmail.com
State Awaiting Upstream, archived
Delegated to: stephen hemminger
Headers show

Commit Message

Sasikanth V March 26, 2011, 2:49 p.m. UTC
Signed-off-by: Sasikanth V <sasikanth.v19@gmail.com>
---
 include/linux/if_bridge.h |   28 +++++++++++++++
 net/bridge/br_ioctl.c     |   35 +++++++-----------
 net/bridge/br_private.h   |    7 +++-
 net/bridge/br_stp_if.c    |    7 +++-
 net/bridge/br_sysfs_br.c  |   83 ++++++++++++++++++++++++++++++++++++---------
 net/bridge/br_sysfs_if.c  |    3 +-
 6 files changed, 122 insertions(+), 41 deletions(-)

Comments

Stephen Hemminger March 26, 2011, 3:55 p.m. UTC | #1
On Sat, 26 Mar 2011 20:19:57 +0530
Sasikanth V <sasikanth.v19@gmail.com> wrote:

> 
> Signed-off-by: Sasikanth V <sasikanth.v19@gmail.com>
> ---

I will clean this up. There are things like introducing
global function names (set_forward_delay, etc) that need
to be fixed.
--
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
diff mbox

Patch

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index dd3f201..9c6cc49 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -49,6 +49,34 @@ 
 #define BR_STATE_FORWARDING 3
 #define BR_STATE_BLOCKING 4
 
+/*802.1D STP compatibility Range*/
+#define BR_DEFAULT_BRIDGE_PRIORITY 32768 
+#define BR_MIN_BRIDGE_PRIORITY 0
+#define BR_MAX_BRIDGE_PRIORITY 65535
+
+#define BR_DEFAULT_PORT_PRIORITY 128
+#define BR_MIN_PORT_PRIORITY 0
+#define BR_MAX_PORT_PRIORITY 240
+
+#define BR_MIN_PATH_COST 1
+#define BR_MAX_PATH_COST 200000000
+
+#define BR_DEFAULT_HELLO_TIME 2
+#define BR_MIN_HELLO_TIME 1
+#define BR_MAX_HELLO_TIME 10
+
+#define BR_DEFAULT_MAX_AGE  20
+#define BR_MIN_MAX_AGE  6
+#define BR_MAX_MAX_AGE  40
+
+#define BR_DEFAULT_FORWARD_DELAY  15
+#define BR_MIN_FORWARD_DELAY  2
+#define BR_MAX_FORWARD_DELAY 30 
+
+#define BR_DEFAULT_AGEING_TIME 300
+#define BR_MIN_AGEING_TIME 10
+#define BR_MAX_AGEING_TIME 1000000
+
 struct __bridge_info {
 	__u64 designated_root;
 	__u64 bridge_id;
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index cb43312..72cf6b6 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -112,6 +112,7 @@  static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct net_bridge *br = netdev_priv(dev);
 	unsigned long args[4];
+	int rval = 0;
 
 	if (copy_from_user(args, rq->ifr_data, sizeof(args)))
 		return -EFAULT;
@@ -182,27 +183,19 @@  static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 			return -EPERM;
 
 		spin_lock_bh(&br->lock);
-		br->bridge_forward_delay = clock_t_to_jiffies(args[1]);
-		if (br_is_root_bridge(br))
-			br->forward_delay = br->bridge_forward_delay;
+		rval = set_forward_delay (br, args[1]);
 		spin_unlock_bh(&br->lock);
-		return 0;
+		return rval;
 
 	case BRCTL_SET_BRIDGE_HELLO_TIME:
 	{
-		unsigned long t = clock_t_to_jiffies(args[1]);
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if (t < HZ)
-			return -EINVAL;
-
 		spin_lock_bh(&br->lock);
-		br->bridge_hello_time = t;
-		if (br_is_root_bridge(br))
-			br->hello_time = br->bridge_hello_time;
+		rval = set_hello_time (br, args[1]);
 		spin_unlock_bh(&br->lock);
-		return 0;
+		return rval;
 	}
 
 	case BRCTL_SET_BRIDGE_MAX_AGE:
@@ -210,18 +203,18 @@  static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 			return -EPERM;
 
 		spin_lock_bh(&br->lock);
-		br->bridge_max_age = clock_t_to_jiffies(args[1]);
-		if (br_is_root_bridge(br))
-			br->max_age = br->bridge_max_age;
+		rval = set_max_age (br, args[1]);
 		spin_unlock_bh(&br->lock);
-		return 0;
+		return rval;
 
 	case BRCTL_SET_AGEING_TIME:
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		br->ageing_time = clock_t_to_jiffies(args[1]);
-		return 0;
+		spin_lock_bh(&br->lock);
+		rval = set_ageing_time (br, args[1]);
+		spin_unlock_bh(&br->lock);
+		return rval;
 
 	case BRCTL_GET_PORT_INFO:
 	{
@@ -268,9 +261,9 @@  static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 			return -EPERM;
 
 		spin_lock_bh(&br->lock);
-		br_stp_set_bridge_priority(br, args[1]);
+		rval = set_priority (br, args[1]);
 		spin_unlock_bh(&br->lock);
-		return 0;
+		return rval;
 
 	case BRCTL_SET_PORT_PRIORITY:
 	{
@@ -303,7 +296,7 @@  static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 		if ((p = br_get_port(br, args[1])) == NULL)
 			ret = -EINVAL;
 		else
-			br_stp_set_path_cost(p, args[2]);
+			ret = br_stp_set_path_cost(p, args[2]);
 
 		return ret;
 	}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 19e2f46..87dd054 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -503,7 +503,7 @@  extern void br_stp_set_bridge_priority(struct net_bridge *br,
 				       u16 newprio);
 extern void br_stp_set_port_priority(struct net_bridge_port *p,
 				     u8 newprio);
-extern void br_stp_set_path_cost(struct net_bridge_port *p,
+extern int br_stp_set_path_cost(struct net_bridge_port *p,
 				 u32 path_cost);
 extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id);
 
@@ -536,6 +536,11 @@  extern int br_sysfs_renameif(struct net_bridge_port *p);
 /* br_sysfs_br.c */
 extern int br_sysfs_addbr(struct net_device *dev);
 extern void br_sysfs_delbr(struct net_device *dev);
+extern int set_forward_delay(struct net_bridge *br, unsigned long val);
+extern int set_max_age(struct net_bridge *br, unsigned long val);
+extern int set_hello_time(struct net_bridge *br, unsigned long val);
+extern int set_priority(struct net_bridge *br, unsigned long val);
+extern int set_ageing_time(struct net_bridge *br, unsigned long val);
 
 #else
 
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 79372d4..6b9923c 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -269,11 +269,16 @@  void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio)
 }
 
 /* called under bridge lock */
-void br_stp_set_path_cost(struct net_bridge_port *p, u32 path_cost)
+int br_stp_set_path_cost(struct net_bridge_port *p, u32 path_cost)
 {
+	if (path_cost < BR_MIN_PATH_COST &&
+	    path_cost > BR_MAX_PATH_COST)
+		return -ERANGE;
+
 	p->path_cost = path_cost;
 	br_configuration_update(p->br);
 	br_port_state_selection(p->br);
+	return 0;
 }
 
 ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id)
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 5c1e555..31a09c5 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -57,12 +57,25 @@  static ssize_t show_forward_delay(struct device *d,
 	return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
 }
 
-static int set_forward_delay(struct net_bridge *br, unsigned long val)
+int set_forward_delay(struct net_bridge *br, unsigned long val)
 {
-	unsigned long delay = clock_t_to_jiffies(val);
-	br->forward_delay = delay;
+	unsigned long fwd_dly = clock_t_to_jiffies(val) / HZ;
+	unsigned long max_age = br->max_age / HZ;
+
+	if ((fwd_dly < BR_MIN_FORWARD_DELAY) ||
+	    (fwd_dly > BR_MAX_FORWARD_DELAY))
+		return -ERANGE;
+
+	/*2 × (Bridge_Forward_Delay – 1.0 seconds) >= Bridge_Max_Age*/
+	if ((2 * (fwd_dly - 1) < (max_age))) {
+		return -EINVAL;
+	}
+
+	fwd_dly *= HZ;
+
+	br->forward_delay = fwd_dly;
 	if (br_is_root_bridge(br))
-		br->bridge_forward_delay = delay;
+		br->bridge_forward_delay = fwd_dly;
 	return 0;
 }
 
@@ -82,16 +95,25 @@  static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
 		       jiffies_to_clock_t(to_bridge(d)->hello_time));
 }
 
-static int set_hello_time(struct net_bridge *br, unsigned long val)
+int set_hello_time(struct net_bridge *br, unsigned long val)
 {
-	unsigned long t = clock_t_to_jiffies(val);
+	unsigned long hello_time = clock_t_to_jiffies(val) / HZ;
+	unsigned long max_age = br->max_age / HZ;
+
+	if ((hello_time < BR_MIN_HELLO_TIME) ||
+   	    (hello_time > BR_MAX_HELLO_TIME))
+		return -ERANGE;
 
-	if (t < HZ)
+	/*Bridge_Max_Age >= 2 × (Bridge_Hello_Time + 1.0 seconds)*/
+
+	if (max_age < ( 2 * (hello_time + 1)))
 		return -EINVAL;
 
-	br->hello_time = t;
+	hello_time *= HZ;
+
+	br->hello_time = hello_time;
 	if (br_is_root_bridge(br))
-		br->bridge_hello_time = t;
+		br->bridge_hello_time = hello_time;
 	return 0;
 }
 
@@ -111,12 +133,31 @@  static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
 		       jiffies_to_clock_t(to_bridge(d)->max_age));
 }
 
-static int set_max_age(struct net_bridge *br, unsigned long val)
+int set_max_age(struct net_bridge *br, unsigned long val)
 {
-	unsigned long t = clock_t_to_jiffies(val);
-	br->max_age = t;
+	unsigned long max_age = clock_t_to_jiffies(val) / HZ;
+	unsigned long hello_time = br->hello_time / HZ;
+	unsigned long fwd_dly = br->forward_delay / HZ;
+
+	if ((max_age < BR_MIN_MAX_AGE) ||
+	    (max_age > BR_MAX_MAX_AGE)) 
+		return -ERANGE;
+
+	/* To support interoperability with legacy Bridges, 
+   	   a Bridge shall enforce the following relationships
+  	   2 × (Bridge_Forward_Delay – 1.0 seconds) >= Bridge_Max_Age
+	   Bridge_Max_Age >= 2 × (Bridge_Hello_Time + 1.0 seconds)
+	*/
+
+       if ((max_age < ( 2 * (hello_time + 1))) || 
+	   (2 * (fwd_dly - 1) < (max_age)))
+                return -EINVAL;
+
+	max_age *= HZ;
+
+	br->max_age = max_age;
 	if (br_is_root_bridge(br))
-		br->bridge_max_age = t;
+		br->bridge_max_age = max_age;
 	return 0;
 }
 
@@ -134,9 +175,15 @@  static ssize_t show_ageing_time(struct device *d,
 	return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 }
 
-static int set_ageing_time(struct net_bridge *br, unsigned long val)
+int set_ageing_time(struct net_bridge *br, unsigned long val)
 {
-	br->ageing_time = clock_t_to_jiffies(val);
+	val = clock_t_to_jiffies(val) / HZ;
+
+	if (val < BR_MIN_AGEING_TIME ||
+	    val > BR_MAX_AGEING_TIME)
+		return -ERANGE;
+
+	br->ageing_time = val * HZ;
 	return 0;
 }
 
@@ -190,8 +237,12 @@  static ssize_t show_priority(struct device *d, struct device_attribute *attr,
 		       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 }
 
-static int set_priority(struct net_bridge *br, unsigned long val)
+int set_priority(struct net_bridge *br, unsigned long val)
 {
+	if ((val < BR_MIN_BRIDGE_PRIORITY) ||
+	    (val > BR_MAX_BRIDGE_PRIORITY)) 
+		return -ERANGE;
+
 	br_stp_set_bridge_priority(br, (u16) val);
 	return 0;
 }
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index fd5799c..6bd4520 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -40,8 +40,7 @@  static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
 }
 static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v)
 {
-	br_stp_set_path_cost(p, v);
-	return 0;
+	return br_stp_set_path_cost(p, v);
 }
 static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
 		   show_path_cost, store_path_cost);