> 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

Reply via email to