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. diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c --- a/net/bridge/br_if.c Tue Apr 13 13:16:56 2004 +++ b/net/bridge/br_if.c Tue Apr 13 13:16:56 2004 @@ -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 @@ 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 @@ 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 @@ 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 -Nru a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c --- a/net/bridge/br_ioctl.c Tue Apr 13 13:16:56 2004 +++ b/net/bridge/br_ioctl.c Tue Apr 13 13:16:56 2004 @@ -91,9 +91,15 @@ 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 @@ 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: @@ -204,6 +210,9 @@ 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) diff -Nru a/net/bridge/br_private.h b/net/bridge/br_private.h --- a/net/bridge/br_private.h Tue Apr 13 13:16:56 2004 +++ b/net/bridge/br_private.h Tue Apr 13 13:16:56 2004 @@ -24,6 +24,9 @@ #define BR_HOLD_TIME (1*HZ) +#define BR_PORT_BITS 10 +#define BR_MAX_PORTS (1<<BR_PORT_BITS) + typedef struct bridge_id bridge_id; typedef struct mac_addr mac_addr; typedef __u16 port_id; diff -Nru a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c --- a/net/bridge/br_stp_if.c Tue Apr 13 13:16:56 2004 +++ b/net/bridge/br_stp_if.c Tue Apr 13 13:16:56 2004 @@ -19,15 +19,21 @@ #include "br_private.h" #include "br_private_stp.h" -static inline __u16 br_make_port_id(const struct net_bridge_port *p) + +/* Port id is composed of priority and port number. + * NB: least significant bits of priority are dropped to + * make room for more ports. + */ +static inline port_id br_make_port_id(__u8 priority, __u16 port_no) { - return (p->priority << 8) | p->port_no; + return ((u16)priority << BR_PORT_BITS) + | (port_no & ((1<<BR_PORT_BITS)-1)); } /* called under bridge lock */ void br_init_port(struct net_bridge_port *p) { - p->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 @@ /* 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);