gre: transparent ethernet bridging
Subsystems (5)
RFC 1/1 gre: transparent ethernet bridging
This patch implements transparent ethernet bridging for gre tunnels. There are a few outstanding issues.
There is no way for userspace to select the type of gre tunnel. The #if 0 near the top of the patch forces all gre tunnels to be bridges. The problem is that userspace uses an IPPROTO_ to select the type of tunnel, but both types of gre tunnel are IPPROTO_GRE. I can't see anything else in struct ip_tunnel_parm that could be used to select this. One approach that I've seen mentioned in the archives is to add a netlink interface to replace the tunnel ioctls.
Network loops are bad. See the comments at the top of ip_gre.c for a description of how gre tunnels handle this normally. But for gre bridges, we don't want to copy the ttl (it breaks routing protocols), and we don't want to force DF (we want to bridge 1500 byte packets). I couldn't think of any solution for this.
Some routers set LLC_SAP_BSPAN in the gre protocol field, and then give the bpdu packet without any other ethernet/llc header. This patch currently tries to fake the ethernet/llc header before passing the packet up, but it is buggy (mac addresses are wrong at least). Maybe a better approach is to call directly into the bridging code. I didn't try that at first because it isn't modular, and may break other things that want to see the packet.
net/ipv4/ip_gre.c +130 -44
@@ -30,6 +30,8 @@#include <linux/igmp.h> #include <linux/netfilter_ipv4.h> #include <linux/if_ether.h> +#include <linux/etherdevice.h> +#include <linux/llc.h> #include <net/sock.h> #include <net/ip.h>
@@ -41,6 +43,8 @@#include <net/dsfield.h> #include <net/inet_ecn.h> #include <net/xfrm.h> +#include <net/llc.h> +#include <net/llc_pdu.h> #ifdef CONFIG_IPV6 #include <net/ipv6.h>
@@ -119,6 +123,7 @@static int ipgre_tunnel_init (struct net_device *dev);static void ipgre_tunnel_setup (struct net_device *dev); +static void ipgre_ether_tunnel_setup (struct net_device *dev);/* Fallback tunnel: no source, no destination, no key, no options */
@@ -274,7 +279,11 @@ static struct ip_tunnel * ipgre_tunnel_l goto failed; } +#if 0 dev =alloc_netdev (sizeof (*t), name, ipgre_tunnel_setup); +#else + dev =alloc_netdev (sizeof (*t), name, ipgre_ether_tunnel_setup); +#endif if (!dev)return NULL ;
@@ -550,6 +559,68 @@ ipgre_ecn_encapsulate(u8 tos, struct iphreturn INET_ECN_encapsulate (tos, inner); } +__be16 ipgre_type_trans (struct sk_buff *skb,int offset) +{ +u8 *h = skb->data; +__be16 flags = *(__be16 *)h; +__be16 proto = *(__be16 *)(h +2 ); + +/* WCCP version 1 and 2 protocol decoding. +* - Change protocol to IP +* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header +*/ +if (flags ==0 && + proto ==__constant_htons (ETH_P_WCCP )) { + proto =__constant_htons (ETH_P_IP ); +if ((*(h + offset) &0xF0 ) !=0x40 ) + offset +=4 ; + } + + skb->mac.raw = skb->nh.raw; + skb->nh.raw =__pskb_pull (skb, offset); +skb_postpull_rcsum (skb, skb->h.raw, offset); +#ifdef CONFIG_NET_IPGRE_BROADCAST +if (MULTICAST (iph->daddr)) { +/* Looped back packet, drop it! */ +if (((struct rtable *)skb->dst)->fl.iif ==0 ) +return 0 ; +/* tunnel->stat.multicast++; */ + skb->pkt_type =PACKET_BROADCAST ; + } +#endif + +return proto; +} + +extern const u8 br_group_address[ETH_ALEN ]; + +__be16 ipgre_ether_type_trans (struct sk_buff *skb,struct net_device *dev, +int offset) +{ +u8 *h = skb->data; +__be16 proto = *(__be16 *)(h +2 ); + +if (proto ==htons (ETH_P_BRIDGE )) { +if (!pskb_may_pull (skb, offset +ETH_HLEN )) +return 0 ; +skb_pull_rcsum (skb, offset); +return eth_type_trans (skb, dev); + }else if (proto ==htons (LLC_SAP_BSPAN )) { +skb_pull_rcsum (skb, offset); + +llc_pdu_header_init (skb,LLC_PDU_TYPE_U ,LLC_SAP_BSPAN , +LLC_SAP_BSPAN ,LLC_PDU_CMD ); +llc_pdu_init_as_ui_cmd (skb); + +llc_mac_hdr_init (skb, dev->dev_addr, dev->dev_addr); +skb_pull (skb,ETH_HLEN ); + +return htons (ETH_P_802_2 ); + } + +return 0 ; +} +static int ipgre_rcv (struct sk_buff *skb) {struct iphdr *iph;
@@ -603,32 +674,8 @@ static int ipgre_rcv(struct sk_buff *skbif ((tunnel =ipgre_tunnel_lookup (iph->saddr, iph->daddr, key)) !=NULL ) {secpath_reset (skb); - skb->protocol = *(u16 *)(h +2 ); -/* WCCP version 1 and 2 protocol decoding. -* - Change protocol to IP -* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header -*/ -if (flags ==0 && - skb->protocol ==__constant_htons (ETH_P_WCCP )) { - skb->protocol =__constant_htons (ETH_P_IP ); -if ((*(h + offset) &0xF0 ) !=0x40 ) - offset +=4 ; - } - - skb->mac.raw = skb->nh.raw; - skb->nh.raw =__pskb_pull (skb, offset); -skb_postpull_rcsum (skb, skb->h.raw, offset);memset (&(IPCB (skb)->opt),0 ,sizeof (struct ip_options )); skb->pkt_type =PACKET_HOST ; -#ifdef CONFIG_NET_IPGRE_BROADCAST -if (MULTICAST (iph->daddr)) { -/* Looped back packet, drop it! */ -if (((struct rtable *)skb->dst)->fl.iif ==0 ) - goto drop; - tunnel->stat.multicast++; - skb->pkt_type =PACKET_BROADCAST ; - } -#endif if (((flags&GRE_CSUM ) && csum) || (!(flags&GRE_CSUM ) && tunnel->parms.i_flags&GRE_CSUM )) {
@@ -645,6 +692,15 @@ static int ipgre_rcv(struct sk_buff *skb } tunnel->i_seqno = seqno +1 ; } +if (tunnel->dev->type ==ARPHRD_ETHER ) + skb->protocol =ipgre_ether_type_trans (skb, tunnel->dev, + offset); +else + skb->protocol =ipgre_type_trans (skb, offset); +if (!skb->protocol) { + tunnel->stat.rx_errors++; + goto drop; + } tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; skb->dev = tunnel->dev;
@@ -686,7 +742,10 @@ static int ipgre_tunnel_xmit(struct sk_b goto tx_error; } -if (dev->hard_header) { +if (dev->type ==ARPHRD_ETHER ) { + gre_hlen = tunnel->hlen -ETH_HLEN ; + tiph = &tunnel->parms.iph; + }else if (dev->hard_header) { gre_hlen =0 ; tiph = (struct iphdr *)skb->data; }else {
@@ -767,7 +826,7 @@ static int ipgre_tunnel_xmit(struct sk_belse mtu = skb->dst ?dst_mtu (skb->dst) : dev->mtu; -if (skb->dst) +if (skb->dst && skb->dst->ops) skb->dst->ops->update_pmtu (skb->dst, mtu);if (skb->protocol ==htons (ETH_P_IP )) {
@@ -849,7 +908,9 @@ static int ipgre_tunnel_xmit(struct sk_b iph->saddr = rt->rt_src;if ((iph->ttl = tiph->ttl) ==0 ) { -if (skb->protocol ==htons (ETH_P_IP )) +if (dev->type ==ARPHRD_ETHER ) + iph->ttl =dst_metric (&rt->u.dst,RTAX_HOPLIMIT ); +else if (skb->protocol ==htons (ETH_P_IP )) iph->ttl = old_iph->ttl;#ifdef CONFIG_IPV6 else if (skb->protocol == htons(ETH_P_IPV6))
@@ -860,7 +921,10 @@ static int ipgre_tunnel_xmit(struct sk_b } ((u16 *)(iph+1 ))[0 ] = tunnel->parms.o_flags; - ((u16 *)(iph+1 ))[1 ] = skb->protocol; +if (dev->type ==ARPHRD_ETHER ) + ((__be16 *)(iph+1 ))[1 ] =htons (ETH_P_BRIDGE ); +else + ((__be16 *)(iph+1 ))[1 ] = skb->protocol;if (tunnel->parms.o_flags&(GRE_KEY |GRE_CSUM |GRE_SEQ )) {u32 *ptr = (u32 *)(((u8 *)iph) + tunnel->hlen -4 );
@@ -956,7 +1020,9 @@ ipgre_tunnel_ioctl (struct net_device *d t =netdev_priv (dev); -if (MULTICAST (p.iph.daddr)) +if (t->dev->type ==ARPHRD_ETHER ) + nflags =IFF_BROADCAST ; +else if (MULTICAST (p.iph.daddr)) nflags =IFF_BROADCAST ;else if (p.iph.daddr) nflags =IFF_POINTOPOINT ;
@@ -1147,6 +1213,18 @@ static void ipgre_tunnel_setup(struct ne dev->addr_len =4 ; } +static void ipgre_ether_tunnel_setup (struct net_device *dev) +{ +ether_setup (dev); + +SET_MODULE_OWNER (dev); + dev->uninit = ipgre_tunnel_uninit; + dev->destructor = free_netdev; + dev->hard_start_xmit = ipgre_tunnel_xmit; + dev->get_stats = ipgre_tunnel_get_stats; + dev->do_ioctl = ipgre_tunnel_ioctl; +} +static int ipgre_tunnel_init (struct net_device *dev) {struct net_device *tdev =NULL ;
@@ -1162,8 +1240,27 @@ static int ipgre_tunnel_init(struct net_ tunnel->dev = dev;strcpy (tunnel->parms.name, dev->name); -memcpy (dev->dev_addr, &tunnel->parms.iph.saddr,4 ); -memcpy (dev->broadcast, &tunnel->parms.iph.daddr,4 ); +if (dev->type ==ARPHRD_ETHER ) +random_ether_addr (dev->dev_addr); +else { +memcpy (dev->dev_addr, &tunnel->parms.iph.saddr,4 ); +memcpy (dev->broadcast, &tunnel->parms.iph.daddr,4 ); + } + +if (dev->type ==ARPHRD_ETHER ) + dev->flags |=IFF_BROADCAST ; +#ifdef CONFIG_NET_IPGRE_BROADCAST + else if (MULTICAST(iph->daddr)) { +if (!iph->saddr) +return -EINVAL ; + dev->flags =IFF_BROADCAST ; + dev->hard_header = ipgre_header; + dev->open = ipgre_open; + dev->stop = ipgre_close; + } +#endif + else if (iph->daddr) + dev->flags |= IFF_POINTOPOINT;/* Guess output device to choose reasonable mtu and hard_header_len */
@@ -1179,19 +1276,6 @@ static int ipgre_tunnel_init(struct net_ tdev = rt->u.dst.dev;ip_rt_put (rt); } - - dev->flags |=IFF_POINTOPOINT ; - -#ifdef CONFIG_NET_IPGRE_BROADCAST -if (MULTICAST (iph->daddr)) { -if (!iph->saddr) -return -EINVAL ; - dev->flags =IFF_BROADCAST ; - dev->hard_header = ipgre_header; - dev->open = ipgre_open; - dev->stop = ipgre_close; - } -#endif }if (!tdev && tunnel->parms.link)
@@ -1212,6 +1296,8 @@ static int ipgre_tunnel_init(struct net_if (tunnel->parms.o_flags&GRE_SEQ ) addend +=4 ; } +if (dev->type ==ARPHRD_ETHER ) + addend +=ETH_HLEN ; dev->hard_header_len = hlen + addend; dev->mtu = mtu - addend; tunnel->hlen = addend;
include/linux/if_ether.h +1 -0
@@ -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 */
Quoted 2 lines · On Mon, 31 Jul 2006 20:06:41 +1000 Philip Craig <[email protected]> wrote:
This patch implements transparent ethernet bridging for gre tunnels. There are a few outstanding issues.
Why not use existing bridge code?
Quoted 14 lines
There is no way for userspace to select the type of gre tunnel. The #if 0 near the top of the patch forces all gre tunnels to be bridges. The problem is that userspace uses an
IPPROTO_to select the type of tunnel, but both types of gre tunnel areIPPROTO_GRE. I can't see anything else in structip_tunnel_parmthat could be used to select this. One approach that I've seen mentioned in the archives is to add a netlink interface to replace the tunnel ioctls.Network loops are bad. See the comments at the top of
ip_gre.cfor a description of how gre tunnels handle this normally. But for gre bridges, we don't want to copy the ttl (it breaks routing protocols), and we don't want to force DF (we want to bridge 1500 byte packets). I couldn't think of any solution for this.
Quoted 7 lines
Some routers set
LLC_SAP_BSPANin the gre protocol field, and then give the bpdu packet without any other ethernet/llc header. This patch currently tries to fake the ethernet/llc header before passing the packet up, but it is buggy (mac addresses are wrong at least). Maybe a better approach is to call directly into the bridging code. I didn't try that at first because it isn't modular, and may break other things that want to see the packet.
Existing bridge code already has spanning tree.
Quoted 29 lines
net/ipv4/ip_gre.c +5
-0@@ -30,6 +30,8 @@#include <linux/igmp.h> #include <linux/netfilter_ipv4.h> #include <linux/if_ether.h> +#include <linux/etherdevice.h> +#include <linux/llc.h> #include <net/sock.h> #include <net/ip.h> @@ -41,6 +43,8 @@#include <net/dsfield.h> #include <net/inet_ecn.h> #include <net/xfrm.h> +#include <net/llc.h> +#include <net/llc_pdu.h> #ifdef CONFIG_IPV6 #include <net/ipv6.h> @@ -119,6 +123,7 @@static int ipgre_tunnel_init (struct net_device *dev);static void ipgre_tunnel_setup (struct net_device *dev); +static void ipgre_ether_tunnel_setup (struct net_device *dev);/* Fallback tunnel: no source, no destination, no key, no options */
net/ipv4/ip_gre.c static struct ip_tunnel * ipgre_tunnel_l · line 286
Quoted 8 lines
net/ipv4/ip_gre.c +4
-0@@ -274,7 +279,11 @@ static struct ip_tunnel * ipgre_tunnel_l goto failed; } +#if 0 dev =alloc_netdev (sizeof (*t), name, ipgre_tunnel_setup); +#else + dev =alloc_netdev (sizeof (*t), name, ipgre_ether_tunnel_setup); +#endif
"Do, or do not there is no try"
Quoted 6 lines
net/ipv4/ip_gre.c +6
-0+__be16 ipgre_type_trans (struct sk_buff *skb,int offset) +{ +u8 *h = skb->data; +__be16 flags = *(__be16 *)h; +__be16 proto = *(__be16 *)(h +2 ); +
net/ipv4/ip_gre.c ipgre_ecn_encapsulate(u8 tos, struct iph · line 577
Quoted 10 lines
net/ipv4/ip_gre.c +10
-0+/* WCCP version 1 and 2 protocol decoding. +* - Change protocol to IP +* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header +*/ +if (flags ==0 && + proto ==__constant_htons (ETH_P_WCCP )) { + proto =__constant_htons (ETH_P_IP ); +if ((*(h + offset) &0xF0 ) !=0x40 ) + offset +=4 ; + }
Don't use __constant_htons() except in initializers and switch cases (where gcc is too stupid to optimize the macro).
Signature · 2 lines
Stephen Hemminger <[email protected]> "And in the Packet there writ down that doome"
Quoted 7 lines · Stephen Hemminger
Quoted 2 lines · On Mon, 31 Jul 2006 20:06:41 +1000 Philip Craig <[email protected]> wrote:
This patch implements transparent ethernet bridging for gre tunnels. There are a few outstanding issues.
Why not use existing bridge code?
It does use the existing bridge code. Perhaps the name is misleading. All it does is encapsulate the full ethernet header in a gre packet, rather than only layer 3. That is, currently gre uses ARPHRD_IPGRE, but bridging requires ARPHRD_ETHER.
Quoted 9 lines
Quoted 7 lines
Some routers set
LLC_SAP_BSPANin the gre protocol field, and then give the bpdu packet without any other ethernet/llc header. This patch currently tries to fake the ethernet/llc header before passing the packet up, but it is buggy (mac addresses are wrong at least). Maybe a better approach is to call directly into the bridging code. I didn't try that at first because it isn't modular, and may break other things that want to see the packet.Existing bridge code already has spanning tree.
Yes, and I want to use that. But this packet is a bit strange in
that it does not have the ethernet header on it. So what is the
best way to pass it to existing code? Either fake the ethernet header, or pass it directly?
Quoted 7 lines
net/ipv4/ip_gre.c static struct ip_tunnel * ipgre_tunnel_l · line 286
Quoted 5 lines
net/ipv4/ip_gre.c +4
-0+#if 0 dev =alloc_netdev (sizeof (*t), name, ipgre_tunnel_setup); +#else + dev =alloc_netdev (sizeof (*t), name, ipgre_ether_tunnel_setup); +#endif "Do, or do not there is no try"
I am looking for comments as to whether adding a netlink interface to control this is appropriate.
Quoted 11 lines
Quoted 11 lines
net/ipv4/ip_gre.c +11
-0+__be16 ipgre_type_trans (struct sk_buff *skb,int offset) +{ +u8 *h = skb->data; +__be16 flags = *(__be16 *)h; +__be16 proto = *(__be16 *)(h +2 ); + +/* WCCP version 1 and 2 protocol decoding. +* - Change protocol to IP +* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header +*/ + if (flags == 0 &&
Quoted 9 lines
net/ipv4/ip_gre.c ipgre_ecn_encapsulate(u8 tos, struct iph · line 577
Quoted 5 lines
net/ipv4/ip_gre.c +5
-0+ proto == __constant_htons(ETH_P_WCCP)) { + proto =__constant_htons (ETH_P_IP ); +if ((*(h + offset) &0xF0 ) !=0x40 ) + offset +=4 ; + }Don't use
__constant_htons()except in initializers and switch cases (where gcc is too stupid to optimize the macro).
This is a problem in the existing code, which I am simply moving around. Should I fix it at the same time?
Quoted 7 lines · On Tue, 01 Aug 2006 11:15:29 +1000 Philip Craig <[email protected]> wrote:
Quoted 6 lines · Stephen Hemminger
Quoted 2 lines · On Mon, 31 Jul 2006 20:06:41 +1000 Philip Craig <[email protected]> wrote:
This patch implements transparent ethernet bridging for gre tunnels. There are a few outstanding issues.
Quoted 7 lines
Quoted 1 line
Why not use existing bridge code?
It does use the existing bridge code. Perhaps the name is misleading. All it does is encapsulate the full ethernet header in a gre packet, rather than only layer 3. That is, currently gre uses
ARPHRD_IPGRE, but bridging requiresARPHRD_ETHER.
I am not against making the bridge code smarter to handle other encapsulation.
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Some routers set
LLC_SAP_BSPANin the gre protocol field, and then give the bpdu packet without any other ethernet/llc header. This patch currently tries to fake the ethernet/llc header before passing the packet up, but it is buggy (mac addresses are wrong at least). Maybe a better approach is to call directly into the bridging code. I didn't try that at first because it isn't modular, and may break other things that want to see the packet.
Quoted 6 lines
Quoted 1 line
Existing bridge code already has spanning tree.
Yes, and I want to use that. But this packet is a bit strange in
that it does not have the ethernet header on it. So what is the
best way to pass it to existing code? Either fake the ethernet header, or pass it directly?
Likewise if the bridge STP bpdu input code was smarter, it could deal with it maybe?
Quoted 11 lines
Quoted 8 lines
net/ipv4/ip_gre.c static struct ip_tunnel * ipgre_tunnel_l · line 286
Quoted 6 lines
net/ipv4/ip_gre.c +4
-0+#if 0 dev =alloc_netdev (sizeof (*t), name, ipgre_tunnel_setup); +#else + dev =alloc_netdev (sizeof (*t), name, ipgre_ether_tunnel_setup); +#endif "Do, or do not there is no try"
I am looking for comments as to whether adding a netlink interface to control this is appropriate.
If we make bridge code type aware, then the ipgre tunnel wouldn't have to change.
Quoted 21 lines
Quoted 11 lines
Quoted 11 lines
net/ipv4/ip_gre.c +11
-0+__be16 ipgre_type_trans (struct sk_buff *skb,int offset) +{ +u8 *h = skb->data; +__be16 flags = *(__be16 *)h; +__be16 proto = *(__be16 *)(h +2 ); + +/* WCCP version 1 and 2 protocol decoding. +* - Change protocol to IP +* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header +*/ + if (flags == 0 &&Quoted 9 lines
net/ipv4/ip_gre.c ipgre_ecn_encapsulate(u8 tos, struct iph · line 577
Quoted 5 lines
net/ipv4/ip_gre.c +5
-0+ proto == __constant_htons(ETH_P_WCCP)) { + proto =__constant_htons (ETH_P_IP ); +if ((*(h + offset) &0xF0 ) !=0x40 ) + offset +=4 ; + }Don't use
__constant_htons()except in initializers and switch cases (where gcc is too stupid to optimize the macro).
Quoted 2 lines
This is a problem in the existing code, which I am simply moving around. Should I fix it at the same time?
Usually if a diff touches some code, I try to make it use current practice.
Quoted 2 lines · Stephen Hemminger
I am not against making the bridge code smarter to handle other encapsulation.
Do you mean something like this patch?
The only drawback I see for this approach is that it means you can only encapsulate the ethernet header if the gre interface is bridged. That's not too bad a restriction though.
This patch only works for local packets so far, and doesn't handle the LLC_SAP_BSPAN packets.
Also, if the gre interface is the only port on the bridge, then we have no mac address.
net/bridge/br_device.c +4 -1
@@ -17,6 +17,7 @@#include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> +#include <linux/if_arp.h> #include <asm/uaccess.h> #include "br_private.h"
@@ -95,7 +96,9 @@ static int br_set_mac_address(struct netspin_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 (port->dev->type ==ARPHRD_ETHER && + !compare_ether_addr (port->dev->dev_addr, + addr->sa_data)) {br_stp_change_bridge_id (br, addr->sa_data); err =0 ;break ;
net/bridge/br_fdb.c +3 -0
@@ -20,6 +20,7 @@#include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/jhash.h> +#include <linux/if_arp.h> #include <asm/atomic.h> #include "br_private.h"
@@ -86,6 +87,7 @@ void br_fdb_changeaddr(struct net_bridgestruct net_bridge_port *op;list_for_each_entry (op, &br->port_list, list) {if (op != p && + op->dev->type ==ARPHRD_ETHER && !compare_ether_addr (op->dev->dev_addr, f->addr.addr)) { f->dst = op;
@@ -151,6 +153,7 @@ void br_fdb_delete_by_port(struct net_brstruct net_bridge_port *op;list_for_each_entry (op, &br->port_list, list) {if (op != p && + op->dev->type ==ARPHRD_ETHER && !compare_ether_addr (op->dev->dev_addr, f->addr.addr)) { f->dst = op;
net/bridge/br_forward.c +3 -0
@@ -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_bufnf_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); }
net/bridge/br_if.c +9 -4
@@ -391,7 +391,10 @@ int br_add_if(struct net_bridge *br, strstruct 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,9 +411,11 @@ int br_add_if(struct net_bridge *br, strif (err) goto err0; - err =br_fdb_insert (br, p, dev->dev_addr); -if (err) - goto err1; +if (dev->type ==ARPHRD_ETHER ) { + err =br_fdb_insert (br, p, dev->dev_addr); +if (err) + goto err1; + } err =br_sysfs_addif (p);if (err)
net/bridge/br_input.c +13 -1
@@ -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 unint 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,
net/bridge/br_notify.c +5 -2
@@ -14,6 +14,7 @@*/ #include <linux/kernel.h> +#include <linux/if_arp.h> #include "br_private.h"
@@ -48,8 +49,10 @@ static int br_device_event(struct notifibreak ;case NETDEV_CHANGEADDR : -br_fdb_changeaddr (p, dev->dev_addr); -br_stp_recalculate_bridge_id (br); +if (dev->type ==ARPHRD_ETHER ) { +br_fdb_changeaddr (p, dev->dev_addr); +br_stp_recalculate_bridge_id (br); + }break ;case NETDEV_CHANGE :
include/linux/if_ether.h +1 -0
@@ -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 */
Quoted 3 lines
Quoted 2 lines · Stephen Hemminger
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.
net/bridge/br.c +8 -0
@@ -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 ();
net/bridge/br_device.c +1 -1
@@ -95,7 +95,7 @@ static int br_set_mac_address(struct netspin_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 ;
net/bridge/br_fdb.c +9 -11
@@ -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(structbr_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_bridgestruct 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_brstruct 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_bridgereturn 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; }
net/bridge/br_forward.c +3 -0
@@ -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_bufnf_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); }
net/bridge/br_if.c +11 -2
@@ -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, strstruct 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, strif (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;
net/bridge/br_input.c +13 -1
@@ -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 unint 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,
net/bridge/br_netfilter.c +12 -2
@@ -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 ********************************************/
net/bridge/br_notify.c +6 -2
@@ -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 notifibreak ;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 :
net/bridge/br_private.h +6 -4
@@ -77,6 +77,7 @@ struct net_bridge_portbridge_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_bridgeextern 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);
net/bridge/br_stp_bpdu.c +39 -19
95 lines not on this page · raw message
net/bridge/br_stp_if.c +2 -2
@@ -155,8 +155,8 @@ void br_stp_recalculate_bridge_id(structlist_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; }
include/linux/if_ether.h +1 -0
@@ -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 */
Quoted 9 lines · Stephen Hemminger
Quoted 6 lines
Quoted 1 line
Why not use existing bridge code?
It does use the existing bridge code. Perhaps the name is misleading. All it does is encapsulate the full ethernet header in a gre packet, rather than only layer 3. That is, currently gre uses
ARPHRD_IPGRE, but bridging requiresARPHRD_ETHER.I am not against making the bridge code smarter to handle other encapsulation.
What if you want to run ethernet directly over a GRE tunnel, without using bridging?
Quoted 9 lines · On Wed, 02 Aug 2006 16:17:42 +1000 Philip Craig <[email protected]> wrote:
Quoted 3 lines
Quoted 2 lines · Stephen Hemminger
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->typeeverywhere.
That looks cleaner. I wonder if using a fixed OUI would be better than random addresses but then choosing an OUI would be a problem.
You probably should add a comment about what this function is doing, and why.
Quoted 10 lines
static int
__br_nf_dev_queue_xmit(struct sk_buff *skb)net/bridge/br_netfilter.c +9
-0+{ +if (skb->dst == (struct dst_entry *)&__fake_rtable) { +dst_release (skb->dst); + skb->dst =NULL ; + } + +return br_dev_queue_push_xmit (skb); +} +
Quoted 8 lines · Stephen Hemminger
Quoted 3 lines · On Wed, 02 Aug 2006 16:17:42 +1000 Philip Craig <[email protected]> wrote:
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->typeeverywhere.That looks cleaner. I wonder if using a fixed OUI would be better than random addresses but then choosing an OUI would be a problem.
random_ether_addr() sets the local assignment bit. This is what various other virtual devices do (including tap devices, which can also be bridged).
Quoted 2 lines
You probably should add a comment about what this function is doing, and why.
Okay.
Quoted 7 lines · Lennert Buytenhek
Quoted 5 lines · Stephen Hemminger
Quoted 5 lines
Quoted 1 line
Why not use existing bridge code?
It does use the existing bridge code. Perhaps the name is misleading. All it does is encapsulate the full ethernet header in a gre packet, rather than only layer 3. That is, currently gre uses
ARPHRD_IPGRE, but bridging requiresARPHRD_ETHER.
Quoted 5 lines
Quoted 2 lines
I am not against making the bridge code smarter to handle other encapsulation.
What if you want to run ethernet directly over a GRE tunnel, without using bridging?
But on the other hand, this method allows you to send both ethernet and non-ethernet traffic over the same GRE tunnel. Is that useful? Actually, this feature is what makes the handling of the LLC_SAP_BSPAN packets simple.
The patch to bridging is a lot cleaner than the patch to GRE, and it also sidesteps the userspace configuration issues, so I don't want to go back to modifying the GRE device.
Both could be achieved by creating a new virtual device that sits between GRE and bridging.
Quoted 10 lines · Philip Craig
Quoted 9 lines
Quoted 6 lines
Quoted 3 lines
All it does is encapsulate the full ethernet header in a gre packet, rather than only layer 3. That is, currently gre uses
ARPHRD_IPGRE, but bridging requiresARPHRD_ETHER.I am not against making the bridge code smarter to handle other encapsulation.
What if you want to run ethernet directly over a GRE tunnel, without using bridging?
Quoted 8 lines
But on the other hand, this method allows you to send both ethernet and non-ethernet traffic over the same GRE tunnel. Is that useful? Actually, this feature is what makes the handling of the
LLC_SAP_BSPANpackets simple.The patch to bridging is a lot cleaner than the patch to GRE, and it also sidesteps the userspace configuration issues, so I don't want to go back to modifying the GRE device.
So now you _need_ bridging in the middle to send ethernet traffic over a GRE tunnel? Ugh.
If you really want to send ethernet and non-ethernet traffic over the same tunnel, can't you make multiple devices?
If GRE generally transmits BPDUs without ethernet header, the handling for that ought to be in GRE, IMHO.
cheers,
Lennert
Quoted 2 lines · Lennert Buytenhek
So now you _need_ bridging in the middle to send ethernet traffic over a GRE tunnel? Ugh.
Agreed that would not be nice. What is the usage scenario for this? At least one end of the tunnel will be bridged?
Quoted 2 lines
If you really want to send ethernet and non-ethernet traffic over the same tunnel, can't you make multiple devices?
Do you mean make multiple GRE devices, where one has an ethernet mode set? That would require more extensive changes to GRE than my original patch. I don't think being able to send both is important enough to justify that. Better to just use my original patch if that is acceptable. There are parts of it I can clean up more, but nothing major. And it still needs some userspace modifications.
Or create a new virtual device to sit between gre and bridging that simply adds the ethernet header? This is the most modular approach, but it seems like overkill for such a simple thing.
Quoted 2 lines
If GRE generally transmits BPDUs without ethernet header, the handling for that ought to be in GRE, IMHO.
I don't think this is normal behaviour. At least, not all routers do it. More likely some routers have done it as an optimisation. It does appear to be specific to GRE.
Quoted 5 lines · Philip Craig
Quoted 2 lines
So now you _need_ bridging in the middle to send ethernet traffic over a GRE tunnel? Ugh.
Agreed that would not be nice. What is the usage scenario for this? At least one end of the tunnel will be bridged?
For example for VPN purposes, I could imagine that you wouldn't want to use bridging.
Quoted 4 lines
Quoted 2 lines
If you really want to send ethernet and non-ethernet traffic over the same tunnel, can't you make multiple devices?
Do you mean make multiple GRE devices, where one has an ethernet mode set?
For example. If you want to send ethernet-encapsulated and other-protocol- encapsulated traffic over the same GRE tunnel, that would seem like the cleanest solution to me.
Quoted 6 lines
Quoted 2 lines
If GRE generally transmits BPDUs without ethernet header, the handling for that ought to be in GRE, IMHO.
I don't think this is normal behaviour. At least, not all routers do it. More likely some routers have done it as an optimisation. It does appear to be specific to GRE.
Hmm, so it depends on the device whether BPDUs are sent with or without an ethernet header? Do the devices that send BPDUs without ethernet header at least accept a BPDU with an ethernet header (and vice versa), or aren't the two modes compatible at all?
cheers,
Lennert
Quoted 9 lines · Lennert Buytenhek
Quoted 4 lines · Philip Craig
Quoted 2 lines
So now you _need_ bridging in the middle to send ethernet traffic over a GRE tunnel? Ugh.
Agreed that would not be nice. What is the usage scenario for this? At least one end of the tunnel will be bridged?
For example for VPN purposes, I could imagine that you wouldn't want to use bridging.
What is the purpose of including the ethernet header if it only exists on the tunnel? I have used GRE tunnels for VPNs, but they have always needed bridging. If I don't need bridging, then the VPN is only passing IP traffic and I just send that without GRE at all.
Quoted 7 lines
Quoted 3 lines
Quoted 2 lines
If you really want to send ethernet and non-ethernet traffic over the same tunnel, can't you make multiple devices?
Do you mean make multiple GRE devices, where one has an ethernet mode set?
For example. If you want to send ethernet-encapsulated and other-protocol- encapsulated traffic over the same GRE tunnel, that would seem like the cleanest solution to me.
It is fine for sending, but when receiving, which packets go to which device? Does a packet appear on only one device when sending, but both devices when receiving? Or does the operation of the non-ethernet device change based on whether an ethernet device exists? Modifying GRE to handle multiple GRE tunnels that are actually the same does not seem clean.
This seems cleaner to me:
The GRE tunnel receives a packet of any protocol (ethernet included), and adds the IP/GRE header. Anything else is done above GRE. Whatever needs the ethernet header should add it.
And then the decision is, how do we add the ethernet header?
- an option to GRE to always add the ethernet header
- a new virtual device
- as part of bridging
Any of these will work for me.
Quoted 4 lines
Hmm, so it depends on the device whether BPDUs are sent with or without an ethernet header? Do the devices that send BPDUs without ethernet header at least accept a BPDU with an ethernet header (and vice versa), or aren't the two modes compatible at all?
I don't have any to test with currently, but we only had complaints about us not receiving them, and only at some sites. So I assume that devices can accept either format.
Quoted 10 lines · Philip Craig
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
So now you _need_ bridging in the middle to send ethernet traffic over a GRE tunnel? Ugh.
Agreed that would not be nice. What is the usage scenario for this? At least one end of the tunnel will be bridged?
For example for VPN purposes, I could imagine that you wouldn't want to use bridging.
What is the purpose of including the ethernet header if it only exists on the tunnel?
I have one machine at home that appears to be on my employer's network via such a tunnel. I don't use bridging, because I don't need any other machine at home to access this tunnel. I do want bridging, and not proxy ARP, because it allows me to run arpwatch, and doesn't require me to reconfigure something at the remote end if I, for example, want to add another IP address to my home box.
Quoted 11 lines
Quoted 7 lines
Quoted 3 lines
Quoted 2 lines
If you really want to send ethernet and non-ethernet traffic over the same tunnel, can't you make multiple devices?
Do you mean make multiple GRE devices, where one has an ethernet mode set?
For example. If you want to send ethernet-encapsulated and other-protocol- encapsulated traffic over the same GRE tunnel, that would seem like the cleanest solution to me.
It is fine for sending, but when receiving, which packets go to which device? Does a packet appear on only one device when sending, but both devices when receiving?
No, just send it to the device that matches the lower-level protocol. So if you receive an ethernet packet, make it be received on the ethernet sub-device, if it's IP, make it be received on the IP sub-device, etc.
Note that I'm not saying that this is necessarily a good idea, it's just what I would suggest if you want to run both 'bare IP' and ethernet encapsulated traffic over the same GRE tunnel at the same time. (Not sure why you'd want that.)
Quoted 7 lines
This seems cleaner to me:
The GRE tunnel receives a packet of any protocol (ethernet included), and adds the IP/GRE header. Anything else is done above GRE. Whatever needs the ethernet header should add it.And then the decision is, how do we add the ethernet header?
- an option to GRE to always add the ethernet header
I think I lost you here. You surely can't just 'make up' any ethernet header?
cheers,
Lennert
Quoted 6 lines · Lennert Buytenhek
I have one machine at home that appears to be on my employer's network via such a tunnel. I don't use bridging, because I don't need any other machine at home to access this tunnel. I do want bridging, and not proxy ARP, because it allows me to run arpwatch, and doesn't require me to reconfigure something at the remote end if I, for example, want to add another IP address to my home box.
Okay.
If this is using Linux, do you have a patch that does this already?
Quoted 8 lines
No, just send it to the device that matches the lower-level protocol. So if you receive an ethernet packet, make it be received on the ethernet sub-device, if it's IP, make it be received on the IP sub-device, etc.
Note that I'm not saying that this is necessarily a good idea, it's just what I would suggest if you want to run both 'bare IP' and ethernet encapsulated traffic over the same GRE tunnel at the same time. (Not sure why you'd want that.)
I still don't understand what the IP sub-device is, or whether this is different from the options I list below.
But I don't have a good reason for wanting this either. So lets forget about this and talk about the three options below.
Quoted 10 lines
Quoted 7 lines
This seems cleaner to me:
The GRE tunnel receives a packet of any protocol (ethernet included), and adds the IP/GRE header. Anything else is done above GRE. Whatever needs the ethernet header should add it.And then the decision is, how do we add the ethernet header?
- an option to GRE to always add the ethernet headerI think I lost you here. You surely can't just 'make up' any ethernet header?
No, you need a device that looks like an ethernet device.
We can modify the GRE device to look like ethernet (as an option). Or we can create a new ethernet device stacked on top of the GRE device. Or we can use the bridge device, which already looks like ethernet.
My first patch in this thread did it by modifying the GRE device. Look at that patch if my explanation still doesn't make sense. The option part is controlled by the "#if 0" in that patch (which needs fixing of course).
You have a valid use that doesn't need bridging, so IMO we can rule out doing it in the bridging code.
Quoted 9 lines · Philip Craig
Quoted 6 lines
I have one machine at home that appears to be on my employer's network via such a tunnel. I don't use bridging, because I don't need any other machine at home to access this tunnel. I do want bridging, and not proxy ARP, because it allows me to run arpwatch, and doesn't require me to reconfigure something at the remote end if I, for example, want to add another IP address to my home box.
Okay.
If this is using Linux, do you have a patch that does this already?
I use vtun:
But I would prefer using some in-kernel ethernet tunneling method with ipsec instead.