> Stephen Hemminger wrote: >> I am not against making the bridge code smarter to handle other >> encapsulation.
Here's an updated patch that fixes all issues I am aware of. It generates a random mac address for gre ports, and also stores a copy of the mac address for ethernet ports, rather than checking dev->type everywhere. The LLC_SAP_BSPAN packets are handled by simply registering that protocol with dev_add_pack(). This would have worked for my original patch too. I had to release __fake_rtable as part of br_nf_dev_queue_xmit(), otherwise ip_gre.c paniced trying to call skb->dst->ops->update_ptmu. --- linux-2.6.x/net/bridge/br.c 18 Jun 2006 23:30:55 -0000 1.1.1.17 +++ linux-2.6.x/net/bridge/br.c 2 Aug 2006 06:05:10 -0000 @@ -26,6 +26,11 @@ int (*br_should_route_hook) (struct sk_buff **pskb) = NULL; +static struct packet_type br_stp_packet_type = { + .type = __constant_htons(LLC_SAP_BSPAN), + .func = br_stp_packet_rcv, +}; + static struct llc_sap *br_stp_sap; static int __init br_init(void) @@ -36,6 +41,8 @@ static int __init br_init(void) return -EBUSY; } + dev_add_pack(&br_stp_packet_type); + br_fdb_init(); #ifdef CONFIG_BRIDGE_NETFILTER @@ -56,6 +63,7 @@ static int __init br_init(void) static void __exit br_deinit(void) { rcu_assign_pointer(br_stp_sap->rcv_func, NULL); + dev_remove_pack(&br_stp_packet_type); #ifdef CONFIG_BRIDGE_NETFILTER br_netfilter_fini(); --- linux-2.6.x/net/bridge/br_device.c 18 Jun 2006 23:30:55 -0000 1.1.1.14 +++ linux-2.6.x/net/bridge/br_device.c 2 Aug 2006 06:05:10 -0000 @@ -95,7 +95,7 @@ static int br_set_mac_address(struct net spin_lock_bh(&br->lock); list_for_each_entry(port, &br->port_list, list) { - if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) { + if (!compare_ether_addr(port->addr.addr, addr->sa_data)) { br_stp_change_bridge_id(br, addr->sa_data); err = 0; break; --- linux-2.6.x/net/bridge/br_fdb.c 18 Jun 2006 23:30:55 -0000 1.1.1.13 +++ linux-2.6.x/net/bridge/br_fdb.c 2 Aug 2006 06:05:10 -0000 @@ -24,8 +24,7 @@ #include "br_private.h" static kmem_cache_t *br_fdb_cache __read_mostly; -static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, - const unsigned char *addr); +static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source); void __init br_fdb_init(void) { @@ -67,7 +66,7 @@ static __inline__ void fdb_delete(struct br_fdb_put(f); } -void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) +void br_fdb_changeaddr(struct net_bridge_port *p) { struct net_bridge *br = p->br; int i; @@ -86,7 +85,7 @@ void br_fdb_changeaddr(struct net_bridge struct net_bridge_port *op; list_for_each_entry(op, &br->port_list, list) { if (op != p && - !compare_ether_addr(op->dev->dev_addr, + !compare_ether_addr(op->addr.addr, f->addr.addr)) { f->dst = op; goto insert; @@ -101,7 +100,7 @@ void br_fdb_changeaddr(struct net_bridge } insert: /* insert new address, may fail if invalid address or dup. */ - fdb_insert(br, p, newaddr); + fdb_insert(br, p); spin_unlock_bh(&br->hash_lock); } @@ -151,7 +150,7 @@ void br_fdb_delete_by_port(struct net_br struct net_bridge_port *op; list_for_each_entry(op, &br->port_list, list) { if (op != p && - !compare_ether_addr(op->dev->dev_addr, + !compare_ether_addr(op->addr.addr, f->addr.addr)) { f->dst = op; goto skip_delete; @@ -291,9 +290,9 @@ static struct net_bridge_fdb_entry *fdb_ return fdb; } -static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, - const unsigned char *addr) +static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source) { + const unsigned char *addr = source->addr.addr; struct hlist_head *head = &br->hash[br_mac_hash(addr)]; struct net_bridge_fdb_entry *fdb; @@ -320,13 +319,12 @@ static int fdb_insert(struct net_bridge return 0; } -int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, - const unsigned char *addr) +int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source) { int ret; spin_lock_bh(&br->hash_lock); - ret = fdb_insert(br, source, addr); + ret = fdb_insert(br, source); spin_unlock_bh(&br->hash_lock); return ret; } --- linux-2.6.x/net/bridge/br_forward.c 18 Jun 2006 23:30:55 -0000 1.1.1.15 +++ linux-2.6.x/net/bridge/br_forward.c 2 Aug 2006 06:05:10 -0000 @@ -18,6 +18,7 @@ #include <linux/skbuff.h> #include <linux/if_vlan.h> #include <linux/netfilter_bridge.h> +#include <linux/if_arp.h> #include "br_private.h" static inline int should_deliver(const struct net_bridge_port *p, @@ -46,6 +47,8 @@ int br_dev_queue_push_xmit(struct sk_buf nf_bridge_maybe_copy_header(skb); #endif skb_push(skb, ETH_HLEN); + if (skb->dev->type == ARPHRD_IPGRE) + skb->protocol = htons(ETH_P_BRIDGE); dev_queue_xmit(skb); } --- linux-2.6.x/net/bridge/br_if.c 18 Jun 2006 23:30:55 -0000 1.1.1.23 +++ linux-2.6.x/net/bridge/br_if.c 2 Aug 2006 06:05:10 -0000 @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/rtnetlink.h> #include <linux/if_ether.h> +#include <linux/etherdevice.h> #include <net/sock.h> #include "br_private.h" @@ -391,7 +392,10 @@ int br_add_if(struct net_bridge *br, str struct net_bridge_port *p; int err = 0; - if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) + if (dev->flags & IFF_LOOPBACK) + return -EINVAL; + + if (dev->type != ARPHRD_ETHER && dev->type != ARPHRD_IPGRE) return -EINVAL; if (dev->hard_start_xmit == br_dev_xmit) @@ -408,7 +412,12 @@ int br_add_if(struct net_bridge *br, str if (err) goto err0; - err = br_fdb_insert(br, p, dev->dev_addr); + if (dev->type == ARPHRD_ETHER) + memcpy(p->addr.addr, dev->dev_addr, ETH_ALEN); + else + random_ether_addr(p->addr.addr); + + err = br_fdb_insert(br, p); if (err) goto err1; --- linux-2.6.x/net/bridge/br_input.c 18 Jun 2006 23:30:55 -0000 1.1.1.18 +++ linux-2.6.x/net/bridge/br_input.c 2 Aug 2006 06:05:10 -0000 @@ -17,6 +17,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/netfilter_bridge.h> +#include <linux/if_arp.h> #include "br_private.h" /* Bridge group multicast address 802.1d (pg 51). */ @@ -124,11 +125,22 @@ static inline int is_link_local(const un int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb) { struct sk_buff *skb = *pskb; - const unsigned char *dest = eth_hdr(skb)->h_dest; + const unsigned char *dest; + + if (skb->dev->type == ARPHRD_IPGRE) { + if (skb->protocol != htons(ETH_P_BRIDGE)) + return 0; + if (!pskb_may_pull(skb, ETH_HLEN)) + goto err; + skb->protocol = eth_type_trans(skb, p->br->dev); + skb_postpull_rcsum(skb, skb->mac.raw, ETH_HLEN); + skb->nh.raw += ETH_HLEN; + } if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) goto err; + dest = eth_hdr(skb)->h_dest; if (unlikely(is_link_local(dest))) { skb->pkt_type = PACKET_HOST; return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, --- linux-2.6.x/net/bridge/br_netfilter.c 18 Jun 2006 23:30:55 -0000 1.1.1.25 +++ linux-2.6.x/net/bridge/br_netfilter.c 2 Aug 2006 06:05:10 -0000 @@ -765,14 +765,24 @@ out: return NF_STOLEN; } +static int __br_nf_dev_queue_xmit(struct sk_buff *skb) +{ + if (skb->dst == (struct dst_entry *)&__fake_rtable) { + dst_release(skb->dst); + skb->dst = NULL; + } + + return br_dev_queue_push_xmit(skb); +} + static int br_nf_dev_queue_xmit(struct sk_buff *skb) { if (skb->protocol == htons(ETH_P_IP) && skb->len > skb->dev->mtu && !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) - return ip_fragment(skb, br_dev_queue_push_xmit); + return ip_fragment(skb, __br_nf_dev_queue_xmit); else - return br_dev_queue_push_xmit(skb); + return __br_nf_dev_queue_xmit(skb); } /* PF_BRIDGE/POST_ROUTING ********************************************/ --- linux-2.6.x/net/bridge/br_notify.c 21 Mar 2006 01:35:39 -0000 1.1.1.12 +++ linux-2.6.x/net/bridge/br_notify.c 2 Aug 2006 06:05:10 -0000 @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/if_arp.h> #include "br_private.h" @@ -48,8 +49,11 @@ static int br_device_event(struct notifi break; case NETDEV_CHANGEADDR: - br_fdb_changeaddr(p, dev->dev_addr); - br_stp_recalculate_bridge_id(br); + if (dev->type == ARPHRD_ETHER) { + memcpy(p->addr.addr, dev->dev_addr, ETH_ALEN); + br_fdb_changeaddr(p); + br_stp_recalculate_bridge_id(br); + } break; case NETDEV_CHANGE: --- linux-2.6.x/net/bridge/br_private.h 18 Jun 2006 23:30:55 -0000 1.1.1.16 +++ linux-2.6.x/net/bridge/br_private.h 2 Aug 2006 06:05:10 -0000 @@ -77,6 +77,7 @@ struct net_bridge_port bridge_id designated_bridge; u32 path_cost; u32 designated_cost; + mac_addr addr; struct timer_list forward_delay_timer; struct timer_list hold_timer; @@ -139,8 +140,7 @@ extern int br_dev_xmit(struct sk_buff *s /* br_fdb.c */ extern void br_fdb_init(void); extern void br_fdb_fini(void); -extern void br_fdb_changeaddr(struct net_bridge_port *p, - const unsigned char *newaddr); +extern void br_fdb_changeaddr(struct net_bridge_port *p); extern void br_fdb_cleanup(unsigned long arg); extern void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p); @@ -152,8 +152,7 @@ extern void br_fdb_put(struct net_bridge extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count, unsigned long off); extern int br_fdb_insert(struct net_bridge *br, - struct net_bridge_port *source, - const unsigned char *addr); + struct net_bridge_port *source); extern void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); @@ -220,6 +219,9 @@ extern ssize_t br_show_bridge_id(char *b /* br_stp_bpdu.c */ extern int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); +extern int br_stp_packet_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, + struct net_device *orig_dev); /* br_stp_timer.c */ extern void br_stp_timer_init(struct net_bridge *br); --- linux-2.6.x/net/bridge/br_stp_bpdu.c 18 Jun 2006 23:30:55 -0000 1.1.1.9 +++ linux-2.6.x/net/bridge/br_stp_bpdu.c 2 Aug 2006 06:05:10 -0000 @@ -50,7 +50,7 @@ static void br_send_bpdu(struct net_brid LLC_SAP_BSPAN, LLC_PDU_CMD); llc_pdu_init_as_ui_cmd(skb); - llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr); + llc_mac_hdr_init(skb, p->addr.addr, p->br->group_addr); NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, dev_queue_xmit); @@ -124,35 +124,23 @@ void br_send_tcn_bpdu(struct net_bridge_ br_send_bpdu(p, buf, 7); } -/* - * Called from llc. - * - * NO locks, but rcu_read_lock (preempt_disabled) - */ -int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) +static void __br_stp_rcv(struct sk_buff *skb, struct net_device *dev, + const unsigned char *dest) { - const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = rcu_dereference(dev->br_port); struct net_bridge *br; const unsigned char *buf; if (!p) - goto err; - - if (pdu->ssap != LLC_SAP_BSPAN - || pdu->dsap != LLC_SAP_BSPAN - || pdu->ctrl_1 != LLC_PDU_TYPE_U) - goto err; + return; if (!pskb_may_pull(skb, 4)) - goto err; + return; /* compare of protocol id and version */ buf = skb->data; if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) - goto err; + return; br = p->br; spin_lock(&br->lock); @@ -162,7 +150,7 @@ int br_stp_rcv(struct sk_buff *skb, stru || !(br->dev->flags & IFF_UP)) goto out; - if (compare_ether_addr(dest, br->group_addr) != 0) + if (dest && compare_ether_addr(dest, br->group_addr) != 0) goto out; buf = skb_pull(skb, 3); @@ -213,7 +201,39 @@ int br_stp_rcv(struct sk_buff *skb, stru } out: spin_unlock(&br->lock); +} + +/* + * Called from llc. + * + * NO locks, but rcu_read_lock (preempt_disabled) + */ +int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); + const unsigned char *dest = eth_hdr(skb)->h_dest; + + if (pdu->ssap != LLC_SAP_BSPAN + || pdu->dsap != LLC_SAP_BSPAN + || pdu->ctrl_1 != LLC_PDU_TYPE_U) + goto err; + + __br_stp_rcv(skb, dev, dest); err: kfree_skb(skb); return 0; } + +/* + * Called from dev/core.c for protocol LLC_SAP_BSPAN. + * This isn't a real ethernet protocol value, but it can occur for bridging + * over gre, and its value is less than 1536 so there is no confusion. + */ +int br_stp_packet_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + __br_stp_rcv(skb, dev, NULL); + kfree_skb(skb); + return 0; +} --- linux-2.6.x/net/bridge/br_stp_if.c 21 Mar 2006 01:35:39 -0000 1.1.1.13 +++ linux-2.6.x/net/bridge/br_stp_if.c 2 Aug 2006 06:05:10 -0000 @@ -155,8 +155,8 @@ void br_stp_recalculate_bridge_id(struct list_for_each_entry(p, &br->port_list, list) { if (addr == br_mac_zero || - memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) - addr = p->dev->dev_addr; + memcmp(p->addr.addr, addr, ETH_ALEN) < 0) + addr = p->addr.addr; } --- linux-2.6.x/include/linux/if_ether.h 18 Jun 2006 23:30:44 -0000 1.1.1.11 +++ linux-2.6.x/include/linux/if_ether.h 2 Aug 2006 06:05:10 -0000 @@ -55,6 +55,7 @@ #define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ #define ETH_P_CUST 0x6006 /* DEC Customer use */ #define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ +#define ETH_P_BRIDGE 0x6558 /* Transparent Ethernet Bridging */ #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ #define ETH_P_ATALK 0x809B /* Appletalk DDP */ #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html