From f93a354b921041c70b5c6335e0b0d0abfce3f49f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 16 Apr 2004 00:21:57 -0700 Subject: [PATCH] [BRIDGE]: Support lots of 1k ports. Support >256 ports on a bridge. Use the suggestion of reducing the number of bits of priority and increasing the number of bits for port number. Easy to increase to even larger if necessary. --- net/bridge/br_if.c | 27 ++++++++++++++------------- net/bridge/br_ioctl.c | 19 ++++++++++++++----- net/bridge/br_private.h | 3 +++ net/bridge/br_stp_if.c | 18 +++++++++++------- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 9d59dac9fb89d..df93dccbfa8d2 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -24,9 +24,6 @@ #include "br_private.h" -/* Limited to 256 ports because of STP protocol pdu */ -#define BR_MAX_PORTS 256 - /* * Determine initial path cost based on speed. * using recommendations from 802.1d standard @@ -166,23 +163,27 @@ static struct net_bridge *new_nb(const char *name) return br; } -static int free_port(struct net_bridge *br) +/* find an available port number */ +static int find_portno(struct net_bridge *br) { int index; struct net_bridge_port *p; - long inuse[BR_MAX_PORTS/(sizeof(long)*8)]; + unsigned long *inuse; + + inuse = kmalloc(BITS_TO_LONGS(BR_MAX_PORTS)*sizeof(unsigned long), + GFP_ATOMIC); + if (!inuse) + return -ENOMEM; - /* find free port number */ - memset(inuse, 0, sizeof(inuse)); + CLEAR_BITMAP(inuse, BR_MAX_PORTS); + set_bit(0, inuse); /* zero is reserved */ list_for_each_entry(p, &br->port_list, list) { set_bit(p->port_no, inuse); } - index = find_first_zero_bit(inuse, BR_MAX_PORTS); - if (index >= BR_MAX_PORTS) - return -EXFULL; + kfree(inuse); - return index; + return (index >= BR_MAX_PORTS) ? -EXFULL : index; } /* called under bridge lock */ @@ -193,7 +194,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, int index; struct net_bridge_port *p; - index = free_port(br); + index = find_portno(br); if (index < 0) return ERR_PTR(index); @@ -206,7 +207,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, dev_hold(dev); p->dev = dev; p->path_cost = cost; - p->priority = 0x80; + p->priority = 0x8000 >> BR_PORT_BITS; dev->br_port = p; p->port_no = index; br_init_port(p); diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index f452f46dcb8d3..4cff15b1c7056 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -91,9 +91,15 @@ int br_ioctl_device(struct net_bridge *br, unsigned int cmd, case BRCTL_GET_PORT_LIST: { - int num = arg1 ? arg1 : 256; /* compatiablity */ - int ret = 0; - int *indices; + int num, *indices; + + num = arg1; + if (num < 0) + return -EINVAL; + if (num == 0) + num = 256; + if (num > BR_MAX_PORTS) + num = BR_MAX_PORTS; indices = kmalloc(num*sizeof(int), GFP_KERNEL); if (indices == NULL) @@ -103,9 +109,9 @@ int br_ioctl_device(struct net_bridge *br, unsigned int cmd, br_get_port_ifindices(br, indices, num); if (copy_to_user((void *)arg0, indices, num*sizeof(int))) - ret = -EFAULT; + num = -EFAULT; kfree(indices); - return ret; + return num; } case BRCTL_SET_BRIDGE_FORWARD_DELAY: @@ -205,6 +211,9 @@ int br_ioctl_device(struct net_bridge *br, unsigned int cmd, if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (arg1 >= (1<<(16-BR_PORT_BITS))) + return -ERANGE; + spin_lock_bh(&br->lock); if ((p = br_get_port(br, arg0)) == NULL) ret = -EINVAL; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 12107da1ee0fe..1e3ad5078d727 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -24,6 +24,9 @@ #define BR_HOLD_TIME (1*HZ) +#define BR_PORT_BITS 10 +#define BR_MAX_PORTS (1<priority << 8) | p->port_no; + return ((u16)priority << BR_PORT_BITS) + | (port_no & ((1<port_id = br_make_port_id(p); + p->port_id = br_make_port_id(p->priority, p->port_no); br_become_designated_port(p); p->state = BR_STATE_BLOCKING; p->topology_change_ack = 0; @@ -185,15 +191,13 @@ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) /* called under bridge lock */ void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio) { - __u16 new_port_id; - - p->priority = newprio & 0xFF; - new_port_id = br_make_port_id(p); + port_id new_port_id = br_make_port_id(newprio, p->port_no); if (br_is_designated_port(p)) p->designated_port = new_port_id; p->port_id = new_port_id; + p->priority = newprio; if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) && p->port_id < p->designated_port) { br_become_designated_port(p); -- 2.53.0