From f170c204c3fe0737d6c9afa6708a194e35395f98 Mon Sep 17 00:00:00 2001 From: lly Date: Thu, 15 Jul 2010 17:29:01 -0400 Subject: [PATCH] bridge: backports from 2.6 upstream 4505a3ef720845b5db3ddb440de13cd4800fd508 bridge: allow setting hardware address of bridge pseudo-dev 92c0574f11598c8036f81e27d2e8bdd6eed7d76d bridge: make bridge address settings sticky 7ce54e3f428b33af714271140601c87b8bf2c544 bridge: receive path optimization 3ae412544cde6d987e0e48778bd87bc96a5749df bridge: assign random address --- .../src/linux/linux/include/linux/etherdevice.h | 30 ++++++++++++++++++ release/src/linux/linux/include/linux/kernel.h | 36 ++++++++++++++++++++++ release/src/linux/linux/net/bridge/br.c | 2 ++ release/src/linux/linux/net/bridge/br_device.c | 30 +++++++++--------- release/src/linux/linux/net/bridge/br_fdb.c | 27 ++++++++-------- release/src/linux/linux/net/bridge/br_input.c | 2 +- release/src/linux/linux/net/bridge/br_private.h | 5 ++- release/src/linux/linux/net/bridge/br_stp_if.c | 14 +++------ 8 files changed, 108 insertions(+), 38 deletions(-) diff --git a/release/src/linux/linux/include/linux/etherdevice.h b/release/src/linux/linux/include/linux/etherdevice.h index bac9b4d5ad..13026a44ba 100644 --- a/release/src/linux/linux/include/linux/etherdevice.h +++ b/release/src/linux/linux/include/linux/etherdevice.h @@ -25,6 +25,7 @@ #define _LINUX_ETHERDEVICE_H #include +#include #ifdef __KERNEL__ extern int eth_header(struct sk_buff *skb, struct net_device *dev, @@ -63,6 +64,35 @@ static inline int is_valid_ether_addr( u8 *addr ) return !(addr[0]&1) && memcmp( addr, zaddr, 6); } +/** + * random_ether_addr - Generate software assigned random Ethernet address + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Generate a random Ethernet address (MAC) that is not multicast + * and has the local assigned bit set. + */ +static inline void random_ether_addr(u8 *addr) +{ + get_random_bytes (addr, ETH_ALEN); + addr [0] &= 0xfe; /* clear multicast bit */ + addr [0] |= 0x02; /* set local assignment bit (IEEE802) */ +} + +/** + * compare_ether_addr - Compare two Ethernet addresses + * @addr1: Pointer to a six-byte array containing the Ethernet address + * @addr2: Pointer other six-byte array containing the Ethernet address + * + * Compare two ethernet addresses, returns 0 if equal + */ +static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) +{ + const u16 *a = (const u16 *) addr1; + const u16 *b = (const u16 *) addr2; + + BUILD_BUG_ON(ETH_ALEN != 6); + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; +} #endif #endif /* _LINUX_ETHERDEVICE_H */ diff --git a/release/src/linux/linux/include/linux/kernel.h b/release/src/linux/linux/include/linux/kernel.h index 495c14f762..3c48f3cd0b 100644 --- a/release/src/linux/linux/include/linux/kernel.h +++ b/release/src/linux/linux/include/linux/kernel.h @@ -145,6 +145,18 @@ extern void dump_stack(void); ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) +#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +#define NIP6_SEQFMT "%04x%04x%04x%04x%04x%04x%04x%04x" + #if defined(__LITTLE_ENDIAN) #define HIPQUAD(addr) \ ((unsigned char *)&addr)[3], \ @@ -185,6 +197,17 @@ extern void dump_stack(void); #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + extern void __out_of_line_bug(int line) ATTRIB_NORET; #define out_of_line_bug() __out_of_line_bug(__LINE__) @@ -217,4 +240,17 @@ struct sysinfo { } \ } while (0) +/* Force a compilation error if condition is true */ +#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) + +/* Force a compilation error if condition is constant and true */ +#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)])) + +/* Force a compilation error if condition is true, but also produce a + result (of value 0 and type size_t), so the expression can be used + e.g. in a structure initializer (or where-ever else comma expressions + aren't permitted). */ +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) +#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) + #endif /* _LINUX_KERNEL_H */ diff --git a/release/src/linux/linux/net/bridge/br.c b/release/src/linux/linux/net/bridge/br.c index 5b4223f981..77d59ee18a 100644 --- a/release/src/linux/linux/net/bridge/br.c +++ b/release/src/linux/linux/net/bridge/br.c @@ -44,6 +44,8 @@ static int __init br_init(void) { printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n"); + br_fdb_init(); + br_handle_frame_hook = br_handle_frame; br_ioctl_hook = br_ioctl_deviceless_stub; #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) diff --git a/release/src/linux/linux/net/bridge/br_device.c b/release/src/linux/linux/net/bridge/br_device.c index 3832bfb7d0..251629fbd5 100644 --- a/release/src/linux/linux/net/bridge/br_device.c +++ b/release/src/linux/linux/net/bridge/br_device.c @@ -15,8 +15,8 @@ #include #include -#include #include +#include #include #include "br_private.h" @@ -117,32 +117,32 @@ static int br_dev_stop(struct net_device *dev) return 0; } -static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst) -{ - return -1; -} - /* Allow setting mac address to any valid ethernet address. */ -static int -br_set_mac_address(struct net_device *dev, void *addr) +static int br_set_mac_address(struct net_device *dev, void *p) { struct net_bridge *br = dev->priv; - struct sockaddr *sa = (struct sockaddr *) addr; + struct sockaddr *addr = p; - if (!is_valid_ether_addr(sa->sa_data)) + if (!is_valid_ether_addr(addr->sa_data)) return -EINVAL; - write_lock_bh(&br->lock); - memcpy(br->preferred_id.addr, sa->sa_data, ETH_ALEN); - br_stp_recalculate_bridge_id(br); - write_unlock_bh(&br->lock); + read_lock(&br->lock); + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + br_stp_change_bridge_id(br, addr->sa_data); + br->flags |= BR_SET_MAC_ADDR; + read_unlock(&br->lock); return 0; } +static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +{ + return -1; +} + void br_dev_setup(struct net_device *dev) { - memset(dev->dev_addr, 0, ETH_ALEN); + random_ether_addr(dev->dev_addr); dev->do_ioctl = br_dev_do_ioctl; dev->get_stats = br_dev_get_stats; diff --git a/release/src/linux/linux/net/bridge/br_fdb.c b/release/src/linux/linux/net/bridge/br_fdb.c index 78b8223ce6..56a7c3c49b 100644 --- a/release/src/linux/linux/net/bridge/br_fdb.c +++ b/release/src/linux/linux/net/bridge/br_fdb.c @@ -15,11 +15,23 @@ #include #include +#include #include +#include +#include #include #include +#include #include "br_private.h" +static u32 fdb_salt; + +int __init br_fdb_init(void) +{ + get_random_bytes(&fdb_salt, sizeof(fdb_salt)); + return 0; +} + static __inline__ unsigned long __timeout(struct net_bridge *br) { unsigned long timeout; @@ -54,18 +66,9 @@ static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_e static __inline__ int br_mac_hash(unsigned char *mac) { - unsigned long x; - - x = mac[0]; - x = (x << 2) ^ mac[1]; - x = (x << 2) ^ mac[2]; - x = (x << 2) ^ mac[3]; - x = (x << 2) ^ mac[4]; - x = (x << 2) ^ mac[5]; - - x ^= x >> 8; - - return x & (BR_HASH_SIZE - 1); + /* use 1 byte of OUI cnd 3 bytes of NIC */ + u32 key = get_unaligned((u32 *)(mac + 2)); + return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); } static __inline__ void __hash_link(struct net_bridge *br, diff --git a/release/src/linux/linux/net/bridge/br_input.c b/release/src/linux/linux/net/bridge/br_input.c index 75a44be5f3..d83b14a2a2 100644 --- a/release/src/linux/linux/net/bridge/br_input.c +++ b/release/src/linux/linux/net/bridge/br_input.c @@ -24,7 +24,7 @@ unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; static int br_pass_frame_up_finish(struct sk_buff *skb) { - netif_rx(skb); + netif_receive_skb(skb); return 0; } diff --git a/release/src/linux/linux/net/bridge/br_private.h b/release/src/linux/linux/net/bridge/br_private.h index eafecd7ce7..bf2112c06a 100644 --- a/release/src/linux/linux/net/bridge/br_private.h +++ b/release/src/linux/linux/net/bridge/br_private.h @@ -86,6 +86,8 @@ struct net_bridge rwlock_t hash_lock; struct net_bridge_fdb_entry *hash[BR_HASH_SIZE]; struct timer_list tick; + unsigned int flags; +#define BR_SET_MAC_ADDR 0x00000001 /* STP */ bridge_id designated_root; @@ -95,7 +97,6 @@ struct net_bridge int hello_time; int forward_delay; bridge_id bridge_id; - bridge_id preferred_id; int bridge_max_age; int bridge_hello_time; int bridge_forward_delay; @@ -124,6 +125,7 @@ extern void br_dev_setup(struct net_device *dev); extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); /* br_fdb.c */ +extern int br_fdb_init(void); extern void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr); extern void br_fdb_cleanup(struct net_bridge *br); @@ -189,6 +191,7 @@ extern void br_stp_enable_bridge(struct net_bridge *br); extern void br_stp_disable_bridge(struct net_bridge *br); extern void br_stp_enable_port(struct net_bridge_port *p); extern void br_stp_disable_port(struct net_bridge_port *p); +extern void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr); extern void br_stp_recalculate_bridge_id(struct net_bridge *br); extern void br_stp_set_bridge_priority(struct net_bridge *br, int newprio); diff --git a/release/src/linux/linux/net/bridge/br_stp_if.c b/release/src/linux/linux/net/bridge/br_stp_if.c index c4bc49a4ec..51ef6ec796 100644 --- a/release/src/linux/linux/net/bridge/br_stp_if.c +++ b/release/src/linux/linux/net/bridge/br_stp_if.c @@ -121,7 +121,7 @@ void br_stp_disable_port(struct net_bridge_port *p) } /* called under bridge lock */ -static void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr) +void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr) { unsigned char oldaddr[6]; struct net_bridge_port *p; @@ -155,19 +155,15 @@ static unsigned char br_mac_zero[6] = {0,0,0,0,0,0}; /* called under bridge lock */ void br_stp_recalculate_bridge_id(struct net_bridge *br) { - unsigned char *addr; + unsigned char *addr = br_mac_zero; struct net_bridge_port *p; - addr = br_mac_zero; + /* user has chosen a value so keep it */ + if (br->flags & BR_SET_MAC_ADDR) + return; p = br->port_list; while (p != NULL) { - /* match against preferred address first */ - if (memcmp(p->dev->dev_addr, br->preferred_id.addr, ETH_ALEN) == 0) { - addr = p->dev->dev_addr; - break; - } - if (addr == br_mac_zero || memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) addr = p->dev->dev_addr; -- 2.11.4.GIT