[patch v3, kernel version 3.2.1] net/ipv4/ip_gre: Ethernetmultipoint GRE over IP

From: Stefan Gula
Date: Tue Jan 17 2012 - 17:32:44 EST


From: Stefan Gula <steweg@xxxxxxxxx>

This patch is an extension for current Ethernet over GRE
implementation, which allows user to create virtual bridge (multipoint
VPN) and forward traffic based on Ethernet MAC address information in
it. It simulates the Bridge behavior learning mechanism, but instead
of learning port ID from which given MAC address comes, it learns IP
address of peer which encapsulated given packet. Multicast, Broadcast
and unknown-multicast traffic is send over network as multicast
encapsulated GRE packet, so one Ethernet multipoint GRE tunnel can be
represented as one single virtual switch on logical level and be also
represented as one multicast IPv4 address on network level.

Signed-off-by: Stefan Gula <steweg@xxxxxxxxx>

---

code was merged with Eric Dumazet proposal (all except the reordering of orig_source as that needed to be previous value), tested and fixed with additional lines in ipgre_tap_netdev_ops struct

diff -uprN -X linux-3.2.1-orig/Documentation/dontdiff linux-3.2.1-orig/include/net/ipip.h linux-3.2.1-my/include/net/ipip.h
--- linux-3.2.1-orig/include/net/ipip.hÂÂÂÂÂÂÂÂ2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-my/include/net/ipip.hÂÂÂÂÂÂÂÂ2012-01-16 11:17:01.000000000 +0100
@@ -27,6 +27,14 @@ struct ip_tunnel {
ÂÂÂÂÂÂÂÂÂ__u32ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂo_seqno;ÂÂÂÂÂÂÂÂ/* The last output seqno */
ÂÂÂÂÂÂÂÂÂintÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhlen;ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ/* Precalculated GRE header length */
ÂÂÂÂÂÂÂÂÂintÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂmlink;
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+#define GRETAP_BR_HASH_BITS 8
+#define GRETAP_BR_HASH_SIZE (1 << GRETAP_BR_HASH_BITS)
+ÂÂÂÂÂÂÂÂstruct hlist_headÂÂÂÂÂÂÂÂhash[GRETAP_BR_HASH_SIZE];
+ÂÂÂÂÂÂÂÂspinlock_tÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhash_lock;
+ÂÂÂÂÂÂÂÂunsigned longÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂageing_time;
+ÂÂÂÂÂÂÂÂstruct timer_listÂÂÂÂÂÂÂÂgc_timer;
+#endif
Â
ÂÂÂÂÂÂÂÂÂstruct ip_tunnel_parmÂÂÂÂÂÂÂÂparms;
Â
diff -uprN -X linux-3.2.1-orig/Documentation/dontdiff linux-3.2.1-orig/net/ipv4/Kconfig linux-3.2.1-my/net/ipv4/Kconfig
--- linux-3.2.1-orig/net/ipv4/KconfigÂÂÂÂÂÂÂÂ2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-my/net/ipv4/KconfigÂÂÂÂÂÂÂÂ2012-01-16 12:37:00.000000000 +0100
@@ -211,6 +211,15 @@ config NET_IPGRE_BROADCAST
ÂÂÂÂÂÂÂÂÂ ÂNetwork), but can be distributed all over the Internet. If you want
ÂÂÂÂÂÂÂÂÂ Âto do that, say Y here and to "IP multicast routing" below.
Â
+config NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂbool "IP: Ethernet over multipoint GRE over IP"
+ÂÂÂÂÂÂÂÂdepends on IP_MULTICAST && NET_IPGRE && NET_IPGRE_BROADCAST
+ÂÂÂÂÂÂÂÂhelp
+ÂÂÂÂÂÂÂÂ ÂAllows you to use multipoint GRE VPN as virtual switch and interconnect
+ÂÂÂÂÂÂÂÂ Âseveral L2 endpoints over L3 routed infrastructure. It is useful for
+ÂÂÂÂÂÂÂÂ Âcreating multipoint L2 VPNs which can be later used inside bridge
+ÂÂÂÂÂÂÂÂ Âinterfaces If you want to use. GRE multipoint L2 VPN feature say Y.
+
Âconfig IP_MROUTE
ÂÂÂÂÂÂÂÂÂbool "IP: multicast routing"
ÂÂÂÂÂÂÂÂÂdepends on IP_MULTICAST
diff -uprN -X linux-3.2.1-orig/Documentation/dontdiff linux-3.2.1-orig/net/ipv4/ip_gre.c linux-3.2.1-my/net/ipv4/ip_gre.c
--- linux-3.2.1-orig/net/ipv4/ip_gre.cÂÂÂÂÂÂÂÂ2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-my/net/ipv4/ip_gre.cÂÂÂÂÂÂÂÂ2012-01-17 22:58:43.000000000 +0100
@@ -52,6 +52,11 @@
Â#include <net/ip6_route.h>
Â#endif
Â
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+#include <linux/jhash.h>
+#include <asm/unaligned.h>
+#endif
+
Â/*
ÂÂ ÂProblems & solutions
ÂÂ Â--------------------
@@ -134,6 +139,172 @@ struct ipgre_net {
ÂÂÂÂÂÂÂÂÂstruct net_device *fb_tunnel_dev;
Â};
Â
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂ/*
+ÂÂÂÂÂÂÂÂ * This part of code includes codes to enable L2 ethernet
+ÂÂÂÂÂÂÂÂ * switch virtualization over IP routed infrastructure with
+ÂÂÂÂÂÂÂÂ * utilization of multicast capable endpoint using Ethernet
+ÂÂÂÂÂÂÂÂ * over GRE
+ÂÂÂÂÂÂÂÂ *
+ÂÂÂÂÂÂÂÂ * Author: Stefan Gula
+ÂÂÂÂÂÂÂÂ * Signed-off-by: Stefan Gula <steweg@xxxxxxxxx>
+ÂÂÂÂÂÂÂÂ */
+struct ipgre_tap_bridge_entry {
+ÂÂÂÂÂÂÂÂstruct hlist_nodeÂÂÂÂÂÂÂÂhlist;
+ÂÂÂÂÂÂÂÂ__be32ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂraddr;
+ÂÂÂÂÂÂÂÂunsigned charÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂaddr[ETH_ALEN];
+ÂÂÂÂÂÂÂÂunsigned longÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂupdated;
+ÂÂÂÂÂÂÂÂstruct rcu_headÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂrcu;
+};
+
+static u32 ipgre_salt __read_mostly;
+
+static inline int ipgre_tap_bridge_hash(const unsigned char *mac)
+{
+ÂÂÂÂÂÂÂÂu32 key = get_unaligned((u32 *)(mac + 2));
+
+ÂÂÂÂÂÂÂÂreturn jhash_1word(key, ipgre_salt) & (GRETAP_BR_HASH_SIZE - 1);
+}
+
+static inline int ipgre_tap_bridge_has_expired(const struct ip_tunnel *tunnel,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂconst struct ipgre_tap_bridge_entry *entry)
+{
+ÂÂÂÂÂÂÂÂreturn time_before_eq(entry->updated + tunnel->ageing_time,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂjiffies);
+}
+
+static inline void ipgre_tap_bridge_delete(struct ipgre_tap_bridge_entry *entry)
+{
+ÂÂÂÂÂÂÂÂhlist_del_rcu(&entry->hlist);
+ÂÂÂÂÂÂÂÂkfree_rcu(entry, rcu);
+}
+
+static void ipgre_tap_bridge_cleanup(unsigned long _data)
+{
+ÂÂÂÂÂÂÂÂstruct ip_tunnel *tunnel = (struct ip_tunnel *)_data;
+ÂÂÂÂÂÂÂÂunsigned long delay = tunnel->ageing_time;
+ÂÂÂÂÂÂÂÂunsigned long next_timer = jiffies + tunnel->ageing_time;
+ÂÂÂÂÂÂÂÂint i;
+
+ÂÂÂÂÂÂÂÂspin_lock(&tunnel->hash_lock);
+ÂÂÂÂÂÂÂÂfor (i = 0; i < GRETAP_BR_HASH_SIZE; i++) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂstruct hlist_node *h, *n;
+
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhlist_for_each_entry_safe(entry, h, n,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ&tunnel->hash[i], hlist)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ{
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂunsigned long this_timer;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂthis_timer = entry->updated + delay;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (time_before_eq(this_timer, jiffies))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂipgre_tap_bridge_delete(entry);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂelse if (time_before(this_timer, next_timer))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂnext_timer = this_timer;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂspin_unlock(&tunnel->hash_lock);
+ÂÂÂÂÂÂÂÂmod_timer(&tunnel->gc_timer, round_jiffies_up(next_timer));
+}
+
+static void ipgre_tap_bridge_flush(struct ip_tunnel *tunnel)
+{
+ÂÂÂÂÂÂÂÂint i;
+
+ÂÂÂÂÂÂÂÂspin_lock_bh(&tunnel->hash_lock);
+ÂÂÂÂÂÂÂÂfor (i = 0; i < GRETAP_BR_HASH_SIZE; i++) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂstruct hlist_node *h, *n;
+
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhlist_for_each_entry_safe(entry, h, n,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ&tunnel->hash[i], hlist)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ{
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂipgre_tap_bridge_delete(entry);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂspin_unlock_bh(&tunnel->hash_lock);
+}
+
+static struct ipgre_tap_bridge_entry *__ipgre_tap_bridge_get(
+ÂÂÂÂÂÂÂÂstruct ip_tunnel *tunnel, const unsigned char *addr)
+{
+ÂÂÂÂÂÂÂÂstruct hlist_node *h;
+ÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+
+ÂÂÂÂÂÂÂÂhlist_for_each_entry_rcu(entry, h,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ&tunnel->hash[ipgre_tap_bridge_hash(addr)], hlist) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (!compare_ether_addr(entry->addr, addr)) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (unlikely(ipgre_tap_bridge_has_expired(tunnel,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂentry)))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂbreak;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn entry;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂ}
+
+ÂÂÂÂÂÂÂÂreturn NULL;
+}
+
+static struct ipgre_tap_bridge_entry *ipgre_tap_bridge_find(
+ÂÂÂÂÂÂÂÂstruct hlist_head *head,
+ÂÂÂÂÂÂÂÂconst unsigned char *addr)
+{
+ÂÂÂÂÂÂÂÂstruct hlist_node *h;
+ÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+
+ÂÂÂÂÂÂÂÂhlist_for_each_entry(entry, h, head, hlist) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (!compare_ether_addr(entry->addr, addr))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn entry;
+ÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂreturn NULL;
+}
+
+
+static struct ipgre_tap_bridge_entry *ipgre_tap_bridge_find_rcu(
+ÂÂÂÂÂÂÂÂstruct hlist_head *head,
+ÂÂÂÂÂÂÂÂconst unsigned char *addr)
+{
+ÂÂÂÂÂÂÂÂstruct hlist_node *h;
+ÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+
+ÂÂÂÂÂÂÂÂhlist_for_each_entry_rcu(entry, h, head, hlist) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (!compare_ether_addr(entry->addr, addr))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn entry;
+ÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂreturn NULL;
+}
+
+static struct ipgre_tap_bridge_entry *ipgre_tap_bridge_create(
+ÂÂÂÂÂÂÂÂstruct hlist_head *head,
+ÂÂÂÂÂÂÂÂ__be32 source,
+ÂÂÂÂÂÂÂÂconst unsigned char *addr)
+{
+ÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+
+ÂÂÂÂÂÂÂÂentry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ÂÂÂÂÂÂÂÂif (entry) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂmemcpy(entry->addr, addr, ETH_ALEN);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂentry->raddr = source;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂentry->updated = jiffies;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhlist_add_head_rcu(&entry->hlist, head);
+ÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂreturn entry;
+}
+
+static __be32 ipgre_tap_bridge_get_raddr(struct ip_tunnel *tunnel,
+ÂÂÂÂÂÂÂÂconst unsigned char *addr)
+{
+ÂÂÂÂÂÂÂÂ__be32 raddr = 0;
+ÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+
+ÂÂÂÂÂÂÂÂrcu_read_lock();
+ÂÂÂÂÂÂÂÂentry = __ipgre_tap_bridge_get(tunnel, addr);
+ÂÂÂÂÂÂÂÂif (entry)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂraddr = entry->raddr;
+ÂÂÂÂÂÂÂÂrcu_read_unlock();
+
+ÂÂÂÂÂÂÂÂreturn raddr;
+}
+
+#endif
Â/* Tunnel hash table */
Â
Â/*
@@ -562,6 +733,12 @@ static int ipgre_rcv(struct sk_buff *skb
ÂÂÂÂÂÂÂÂÂstruct ip_tunnel *tunnel;
ÂÂÂÂÂÂÂÂÂint  Âoffset = 4;
ÂÂÂÂÂÂÂÂÂ__be16 gre_proto;
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂ__be32 orig_source;
+ÂÂÂÂÂÂÂÂstruct hlist_head *head;
+ÂÂÂÂÂÂÂÂstruct ipgre_tap_bridge_entry *entry;
+ÂÂÂÂÂÂÂÂconst struct ethhdr *tethhdr;
+#endif
Â
ÂÂÂÂÂÂÂÂÂif (!pskb_may_pull(skb, 16))
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂgoto drop_nolock;
@@ -659,10 +836,38 @@ static int ipgre_rcv(struct sk_buff *skb
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtunnel->dev->stats.rx_errors++;
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂgoto drop;
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
-
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂorig_source = iph->saddr;
+#endif
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂiph = ip_hdr(skb);
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂskb->protocol = eth_type_trans(skb, tunnel->dev);
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂskb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (ipv4_is_multicast(tunnel->parms.iph.daddr)) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtethhdr = eth_hdr(skb);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (!is_multicast_ether_addr(
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtethhdr->h_source)) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhead = &tunnel->hash[
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂipgre_tap_bridge_hash(
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtethhdr->h_source)];
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂentry = ipgre_tap_bridge_find_rcu(head,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtethhdr->h_source);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (likely(entry)) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂentry->raddr = orig_source;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂentry->updated = jiffies;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ} else {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ Âspin_lock(&tunnel->hash_lock);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ Âif (!ipgre_tap_bridge_find(head,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtethhdr->h_source))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂipgre_tap_bridge_create(
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂhead,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂorig_source,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtethhdr->h_source);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ Âspin_unlock(&tunnel->hash_lock);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+#endif
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
Â
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtstats = this_cpu_ptr(tunnel->dev->tstats);
@@ -702,7 +907,7 @@ static netdev_tx_t ipgre_tunnel_xmit(str
ÂÂÂÂÂÂÂÂÂstruct iphdr Â*iph;ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ/* Our new IP header */
ÂÂÂÂÂÂÂÂÂunsigned int max_headroom;ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ/* The extra header space needed */
ÂÂÂÂÂÂÂÂÂint  Âgre_hlen;
-ÂÂÂÂÂÂÂÂ__be32 dst;
+ÂÂÂÂÂÂÂÂ__be32 dst = 0;
ÂÂÂÂÂÂÂÂÂint  Âmtu;
Â
ÂÂÂÂÂÂÂÂÂif (dev->type == ARPHRD_ETHER)
@@ -716,7 +921,15 @@ static netdev_tx_t ipgre_tunnel_xmit(str
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂtiph = &tunnel->parms.iph;
ÂÂÂÂÂÂÂÂÂ}
Â
-ÂÂÂÂÂÂÂÂif ((dst = tiph->daddr) == 0) {
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂif ((dev->type == ARPHRD_ETHER) &&
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂipv4_is_multicast(tunnel->parms.iph.daddr))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂdst = ipgre_tap_bridge_get_raddr(tunnel,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ((struct ethhdr *)skb->data)->h_dest);
+#endif
+ÂÂÂÂÂÂÂÂif (dst == 0)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂdst = tiph->daddr;
+ÂÂÂÂÂÂÂÂif (dst == 0) {
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ/* NBMA tunnel */
Â
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (skb_dst(skb) == NULL) {
@@ -1209,6 +1422,16 @@ static int ipgre_open(struct net_device
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn -EADDRNOTAVAIL;
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂt->mlink = dev->ifindex;
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr);
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (t->dev->type == ARPHRD_ETHER) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂINIT_HLIST_HEAD(t->hash);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂspin_lock_init(&t->hash_lock);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂt->ageing_time = 300 * HZ;
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂsetup_timer(&t->gc_timer, ipgre_tap_bridge_cleanup,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ(unsigned long) t);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂmod_timer(&t->gc_timer, jiffies + t->ageing_time);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+#endif
ÂÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂÂreturn 0;
Â}
@@ -1219,6 +1442,12 @@ static int ipgre_close(struct net_device
Â
ÂÂÂÂÂÂÂÂÂif (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂstruct in_device *in_dev;
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (t->dev->type == ARPHRD_ETHER) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂipgre_tap_bridge_flush(t);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂdel_timer_sync(&t->gc_timer);
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
+#endif
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂin_dev = inetdev_by_index(dev_net(dev), t->mlink);
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif (in_dev)
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂip_mc_dec_group(in_dev, t->parms.iph.daddr);
@@ -1488,6 +1717,10 @@ static int ipgre_tap_init(struct net_dev
Âstatic const struct net_device_ops ipgre_tap_netdev_ops = {
ÂÂÂÂÂÂÂÂÂ.ndo_initÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ= ipgre_tap_init,
ÂÂÂÂÂÂÂÂÂ.ndo_uninitÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ= ipgre_tunnel_uninit,
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂ.ndo_openÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ= ipgre_open,
+ÂÂÂÂÂÂÂÂ.ndo_stopÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ= ipgre_close,
+#endif
ÂÂÂÂÂÂÂÂÂ.ndo_start_xmitÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ= ipgre_tunnel_xmit,
ÂÂÂÂÂÂÂÂÂ.ndo_set_mac_address ÂÂÂÂÂÂÂÂ= eth_mac_addr,
ÂÂÂÂÂÂÂÂÂ.ndo_validate_addrÂÂÂÂÂÂÂÂ= eth_validate_addr,
@@ -1705,6 +1938,9 @@ static int __init ipgre_init(void)
Â
ÂÂÂÂÂÂÂÂÂprintk(KERN_INFO "GRE over IPv4 tunneling driver\n");
Â
+#ifdef CONFIG_NET_IPGRE_BRIDGE
+ÂÂÂÂÂÂÂÂget_random_bytes(&ipgre_salt, sizeof(ipgre_salt));
+#endif
ÂÂÂÂÂÂÂÂÂerr = register_pernet_device(&ipgre_net_ops);
ÂÂÂÂÂÂÂÂÂif (err < 0)
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn err;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/