All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philip Craig <philipc@snapgear.com>
To: Stephen Hemminger <shemminger@osdl.org>
Cc: netdev@vger.kernel.org
Subject: Re: [RFC] gre: transparent ethernet bridging
Date: Wed, 02 Aug 2006 16:17:42 +1000	[thread overview]
Message-ID: <44D04386.2040705@snapgear.com> (raw)
In-Reply-To: <44CF1EF8.2090800@snapgear.com>

> 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		*/

  reply	other threads:[~2006-08-02  6:17 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-31 10:06 [RFC] gre: transparent ethernet bridging Philip Craig
2006-07-31 16:14 ` Stephen Hemminger
2006-08-01  1:15   ` Philip Craig
2006-08-01  5:08     ` Stephen Hemminger
2006-08-01  9:29       ` Philip Craig
2006-08-02  6:17         ` Philip Craig [this message]
2006-08-02 17:23           ` Stephen Hemminger
2006-08-03  1:08             ` Philip Craig
2006-08-02  7:42       ` Lennert Buytenhek
2006-08-03  1:33         ` Philip Craig
2006-08-03  7:33           ` Lennert Buytenhek
2006-08-03  9:14             ` Philip Craig
2006-08-03 19:40               ` Lennert Buytenhek
2006-08-04  1:00                 ` Philip Craig
2006-08-04  8:02                   ` Lennert Buytenhek
2006-08-07  1:55                     ` Philip Craig
2006-08-10 13:09                       ` Lennert Buytenhek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44D04386.2040705@snapgear.com \
    --to=philipc@snapgear.com \
    --cc=netdev@vger.kernel.org \
    --cc=shemminger@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.