[kernel] r15162 - in dists/trunk/linux-2.6/debian: . patches/features/all patches/series

Ben Hutchings benh at alioth.debian.org
Tue Feb 16 03:10:07 UTC 2010


Author: benh
Date: Tue Feb 16 03:10:04 2010
New Revision: 15162

Log:
macvlan: Add bridge, VEPA and private modes (Closes: #568756)

Added:
   dists/trunk/linux-2.6/debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch
   dists/trunk/linux-2.6/debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch
   dists/trunk/linux-2.6/debian/patches/features/all/macvlan-cleanup-rx-statistics.patch
   dists/trunk/linux-2.6/debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch
   dists/trunk/linux-2.6/debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch
Modified:
   dists/trunk/linux-2.6/debian/changelog
   dists/trunk/linux-2.6/debian/patches/series/9

Modified: dists/trunk/linux-2.6/debian/changelog
==============================================================================
--- dists/trunk/linux-2.6/debian/changelog	Tue Feb 16 02:42:05 2010	(r15161)
+++ dists/trunk/linux-2.6/debian/changelog	Tue Feb 16 03:10:04 2010	(r15162)
@@ -5,6 +5,7 @@
   * [x86] Enable USB IP drivers (Closes: #568903)
   * Ignore failure of lsusb when gathering information for bug reports
     (Closes: #569725)
+  * macvlan: Add bridge, VEPA and private modes (Closes: #568756)
 
   [ maximilian attems]
   * Postinst don't refercence k-p related manpage. (Closes: #542208)

Added: dists/trunk/linux-2.6/debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch	Tue Feb 16 03:10:04 2010	(r15162)
@@ -0,0 +1,64 @@
+From 2b071e9effc16db91cd17577a35b0e61e9fcee9d Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Tue, 16 Feb 2010 03:06:44 +0000
+Subject: [PATCH] macvlan: Copy necessary helper functions from 2.6.33 net/core/dev.c
+
+---
+ drivers/net/macvlan.c |   41 +++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 41 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index 2490aa3..cb4a16e 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -46,6 +46,47 @@ struct macvlan_dev {
+ 	struct net_device	*lowerdev;
+ };
+ 
++/* From 2.6.33 net/core/dev.c */
++static int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
++{
++	skb_orphan(skb);
++
++	if (!(dev->flags & IFF_UP))
++		return NET_RX_DROP;
++
++	if (skb->len > (dev->mtu + dev->hard_header_len))
++		return NET_RX_DROP;
++
++	skb_dst_drop(skb);
++	skb->tstamp.tv64 = 0;
++	skb->pkt_type = PACKET_HOST;
++	skb->protocol = eth_type_trans(skb, dev);
++	skb->mark = 0;
++	secpath_reset(skb);
++	nf_reset(skb);
++	return netif_rx(skb);
++}
++
++/* From 2.6.33 net/core/dev.c */
++static void dev_txq_stats_fold(const struct net_device *dev,
++			       struct net_device_stats *stats)
++{
++	unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
++	unsigned int i;
++	struct netdev_queue *txq;
++
++	for (i = 0; i < dev->num_tx_queues; i++) {
++		txq = netdev_get_tx_queue(dev, i);
++		tx_bytes   += txq->tx_bytes;
++		tx_packets += txq->tx_packets;
++		tx_dropped += txq->tx_dropped;
++	}
++	if (tx_bytes || tx_packets || tx_dropped) {
++		stats->tx_bytes   = tx_bytes;
++		stats->tx_packets = tx_packets;
++		stats->tx_dropped = tx_dropped;
++	}
++}
+ 
+ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
+ 					       const unsigned char *addr)
+-- 
+1.6.6.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch	Tue Feb 16 03:10:04 2010	(r15162)
@@ -0,0 +1,183 @@
+From fccaf71011b171883efee5bae321eac4760584d1 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <eric.dumazet at gmail.com>
+Date: Tue, 17 Nov 2009 08:53:49 +0000
+Subject: [PATCH 1/4] macvlan: Precise RX stats accounting
+
+With multi queue devices, its possible that several cpus call
+macvlan RX routines simultaneously for the same macvlan device.
+
+We update RX stats counter without any locking, so we can
+get slightly wrong counters.
+
+One possible fix is to use percpu counters, to get precise
+accounting and also get guarantee of no cache line ping pongs
+between cpus.
+
+Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu
+data per macvlan device.
+
+Signed-off-by: Eric Dumazet <eric.dumazet at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/macvlan.c |   76 ++++++++++++++++++++++++++++++++++++++++++------
+ 1 files changed, 66 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index 271aa7e..ae2b5c7 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -38,12 +38,27 @@ struct macvlan_port {
+ 	struct list_head	vlans;
+ };
+ 
++/**
++ *	struct macvlan_rx_stats - MACVLAN percpu rx stats
++ *	@rx_packets: number of received packets
++ *	@rx_bytes: number of received bytes
++ *	@multicast: number of received multicast packets
++ *	@rx_errors: number of errors
++ */
++struct macvlan_rx_stats {
++	unsigned long rx_packets;
++	unsigned long rx_bytes;
++	unsigned long multicast;
++	unsigned long rx_errors;
++};
++
+ struct macvlan_dev {
+ 	struct net_device	*dev;
+ 	struct list_head	list;
+ 	struct hlist_node	hlist;
+ 	struct macvlan_port	*port;
+ 	struct net_device	*lowerdev;
++	struct macvlan_rx_stats *rx_stats;
+ };
+ 
+ 
+@@ -110,6 +125,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
+ 	struct net_device *dev;
+ 	struct sk_buff *nskb;
+ 	unsigned int i;
++	struct macvlan_rx_stats *rx_stats;
+ 
+ 	if (skb->protocol == htons(ETH_P_PAUSE))
+ 		return;
+@@ -117,17 +133,17 @@ static void macvlan_broadcast(struct sk_buff *skb,
+ 	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
+ 		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
+ 			dev = vlan->dev;
++			rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
+ 
+ 			nskb = skb_clone(skb, GFP_ATOMIC);
+ 			if (nskb == NULL) {
+-				dev->stats.rx_errors++;
+-				dev->stats.rx_dropped++;
++				rx_stats->rx_errors++;
+ 				continue;
+ 			}
+ 
+-			dev->stats.rx_bytes += skb->len + ETH_HLEN;
+-			dev->stats.rx_packets++;
+-			dev->stats.multicast++;
++			rx_stats->rx_bytes += skb->len + ETH_HLEN;
++			rx_stats->rx_packets++;
++			rx_stats->multicast++;
+ 
+ 			nskb->dev = dev;
+ 			if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
+@@ -147,6 +163,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 	const struct macvlan_port *port;
+ 	const struct macvlan_dev *vlan;
+ 	struct net_device *dev;
++	struct macvlan_rx_stats *rx_stats;
+ 
+ 	port = rcu_dereference(skb->dev->macvlan_port);
+ 	if (port == NULL)
+@@ -166,16 +183,15 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 		kfree_skb(skb);
+ 		return NULL;
+ 	}
+-
++	rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
+ 	skb = skb_share_check(skb, GFP_ATOMIC);
+ 	if (skb == NULL) {
+-		dev->stats.rx_errors++;
+-		dev->stats.rx_dropped++;
++		rx_stats->rx_errors++;
+ 		return NULL;
+ 	}
+ 
+-	dev->stats.rx_bytes += skb->len + ETH_HLEN;
+-	dev->stats.rx_packets++;
++	rx_stats->rx_bytes += skb->len + ETH_HLEN;
++	rx_stats->rx_packets++;
+ 
+ 	skb->dev = dev;
+ 	skb->pkt_type = PACKET_HOST;
+@@ -365,9 +381,47 @@ static int macvlan_init(struct net_device *dev)
+ 
+ 	macvlan_set_lockdep_class(dev);
+ 
++	vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats);
++	if (!vlan->rx_stats)
++		return -ENOMEM;
++
+ 	return 0;
+ }
+ 
++static void macvlan_uninit(struct net_device *dev)
++{
++	struct macvlan_dev *vlan = netdev_priv(dev);
++
++	free_percpu(vlan->rx_stats);
++}
++
++static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev)
++{
++	struct net_device_stats *stats = &dev->stats;
++	struct macvlan_dev *vlan = netdev_priv(dev);
++
++	dev_txq_stats_fold(dev, stats);
++
++	if (vlan->rx_stats) {
++		struct macvlan_rx_stats *p, rx = {0};
++		int i;
++
++		for_each_possible_cpu(i) {
++			p = per_cpu_ptr(vlan->rx_stats, i);
++			rx.rx_packets += p->rx_packets;
++			rx.rx_bytes   += p->rx_bytes;
++			rx.rx_errors  += p->rx_errors;
++			rx.multicast  += p->multicast;
++		}
++		stats->rx_packets = rx.rx_packets;
++		stats->rx_bytes   = rx.rx_bytes;
++		stats->rx_errors  = rx.rx_errors;
++		stats->rx_dropped = rx.rx_errors;
++		stats->multicast  = rx.multicast;
++	}
++	return stats;
++}
++
+ static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
+ 					struct ethtool_drvinfo *drvinfo)
+ {
+@@ -404,6 +458,7 @@ static const struct ethtool_ops macvlan_ethtool_ops = {
+ 
+ static const struct net_device_ops macvlan_netdev_ops = {
+ 	.ndo_init		= macvlan_init,
++	.ndo_uninit		= macvlan_uninit,
+ 	.ndo_open		= macvlan_open,
+ 	.ndo_stop		= macvlan_stop,
+ 	.ndo_start_xmit		= macvlan_start_xmit,
+@@ -411,6 +466,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
+ 	.ndo_change_rx_flags	= macvlan_change_rx_flags,
+ 	.ndo_set_mac_address	= macvlan_set_mac_address,
+ 	.ndo_set_multicast_list	= macvlan_set_multicast_list,
++	.ndo_get_stats		= macvlan_dev_get_stats,
+ 	.ndo_validate_addr	= eth_validate_addr,
+ };
+ 
+-- 
+1.6.6.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/all/macvlan-cleanup-rx-statistics.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/macvlan-cleanup-rx-statistics.patch	Tue Feb 16 03:10:04 2010	(r15162)
@@ -0,0 +1,134 @@
+From a1e514c5d0397b5581721aad9b303f7df83b103d Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd at arndb.de>
+Date: Thu, 26 Nov 2009 06:07:09 +0000
+Subject: [PATCH 2/4] macvlan: cleanup rx statistics
+
+We have very similar code for rx statistics in
+two places in the macvlan driver, with a third
+one being added in the next patch.
+
+Consolidate them into one function to improve
+overall readability of the driver.
+
+Signed-off-by: Arnd Bergmann <arnd at arndb.de>
+Acked-by: Patrick McHardy <kaber at trash.net>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/macvlan.c |   70 ++++++++++++++++++++++++++++--------------------
+ 1 files changed, 41 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index ae2b5c7..1e7faf9 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -116,42 +116,58 @@ static int macvlan_addr_busy(const struct macvlan_port *port,
+ 	return 0;
+ }
+ 
++static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
++				    unsigned int len, bool success,
++				    bool multicast)
++{
++	struct macvlan_rx_stats *rx_stats;
++
++	rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
++	if (likely(success)) {
++		rx_stats->rx_packets++;;
++		rx_stats->rx_bytes += len;
++		if (multicast)
++			rx_stats->multicast++;
++	} else {
++		rx_stats->rx_errors++;
++	}
++}
++
++static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev,
++				 const struct ethhdr *eth)
++{
++	if (!skb)
++		return NET_RX_DROP;
++
++	skb->dev = dev;
++	if (!compare_ether_addr_64bits(eth->h_dest,
++				       dev->broadcast))
++		skb->pkt_type = PACKET_BROADCAST;
++	else
++		skb->pkt_type = PACKET_MULTICAST;
++
++	return netif_rx(skb);
++}
++
+ static void macvlan_broadcast(struct sk_buff *skb,
+ 			      const struct macvlan_port *port)
+ {
+ 	const struct ethhdr *eth = eth_hdr(skb);
+ 	const struct macvlan_dev *vlan;
+ 	struct hlist_node *n;
+-	struct net_device *dev;
+ 	struct sk_buff *nskb;
+ 	unsigned int i;
+-	struct macvlan_rx_stats *rx_stats;
++	int err;
+ 
+ 	if (skb->protocol == htons(ETH_P_PAUSE))
+ 		return;
+ 
+ 	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
+ 		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
+-			dev = vlan->dev;
+-			rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
+-
+ 			nskb = skb_clone(skb, GFP_ATOMIC);
+-			if (nskb == NULL) {
+-				rx_stats->rx_errors++;
+-				continue;
+-			}
+-
+-			rx_stats->rx_bytes += skb->len + ETH_HLEN;
+-			rx_stats->rx_packets++;
+-			rx_stats->multicast++;
+-
+-			nskb->dev = dev;
+-			if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
+-				nskb->pkt_type = PACKET_BROADCAST;
+-			else
+-				nskb->pkt_type = PACKET_MULTICAST;
+-
+-			netif_rx(nskb);
++			err = macvlan_broadcast_one(nskb, vlan->dev, eth);
++			macvlan_count_rx(vlan, skb->len + ETH_HLEN,
++					 err == NET_RX_SUCCESS, 1);
+ 		}
+ 	}
+ }
+@@ -163,7 +179,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 	const struct macvlan_port *port;
+ 	const struct macvlan_dev *vlan;
+ 	struct net_device *dev;
+-	struct macvlan_rx_stats *rx_stats;
++	unsigned int len;
+ 
+ 	port = rcu_dereference(skb->dev->macvlan_port);
+ 	if (port == NULL)
+@@ -183,15 +199,11 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 		kfree_skb(skb);
+ 		return NULL;
+ 	}
+-	rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
++	len = skb->len + ETH_HLEN;
+ 	skb = skb_share_check(skb, GFP_ATOMIC);
+-	if (skb == NULL) {
+-		rx_stats->rx_errors++;
++	macvlan_count_rx(vlan, len, skb != NULL, 0);
++	if (!skb)
+ 		return NULL;
+-	}
+-
+-	rx_stats->rx_bytes += skb->len + ETH_HLEN;
+-	rx_stats->rx_packets++;
+ 
+ 	skb->dev = dev;
+ 	skb->pkt_type = PACKET_HOST;
+-- 
+1.6.6.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch	Tue Feb 16 03:10:04 2010	(r15162)
@@ -0,0 +1,143 @@
+From 27c0b1a850cdea6298f573d835782f3337be913c Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd at arndb.de>
+Date: Thu, 26 Nov 2009 06:07:11 +0000
+Subject: [PATCH 4/4] macvlan: export macvlan mode through netlink
+
+In order to support all three modes of macvlan at
+runtime, extend the existing netlink protocol
+to allow choosing the mode per macvlan slave
+interface.
+
+This depends on a matching patch to iproute2
+in order to become accessible in user land.
+
+Signed-off-by: Arnd Bergmann <arnd at arndb.de>
+Acked-by: Patrick McHardy <kaber at trash.net>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/macvlan.c   |   56 +++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/if_link.h |   15 ++++++++++++
+ 2 files changed, 65 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index d6bd843..322112c 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -33,12 +33,6 @@
+ 
+ #define MACVLAN_HASH_SIZE	(1 << BITS_PER_BYTE)
+ 
+-enum macvlan_mode {
+-	MACVLAN_MODE_PRIVATE	= 1,
+-	MACVLAN_MODE_VEPA	= 2,
+-	MACVLAN_MODE_BRIDGE	= 4,
+-};
+-
+ struct macvlan_port {
+ 	struct net_device	*dev;
+ 	struct hlist_head	vlan_hash[MACVLAN_HASH_SIZE];
+@@ -614,6 +608,17 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
+ 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ 			return -EADDRNOTAVAIL;
+ 	}
++
++	if (data && data[IFLA_MACVLAN_MODE]) {
++		switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) {
++		case MACVLAN_MODE_PRIVATE:
++		case MACVLAN_MODE_VEPA:
++		case MACVLAN_MODE_BRIDGE:
++			break;
++		default:
++			return -EINVAL;
++		}
++	}
+ 	return 0;
+ }
+ 
+@@ -678,6 +683,10 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev,
+ 	vlan->dev      = dev;
+ 	vlan->port     = port;
+ 
++	vlan->mode     = MACVLAN_MODE_VEPA;
++	if (data && data[IFLA_MACVLAN_MODE])
++		vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
++
+ 	err = register_netdevice(dev);
+ 	if (err < 0)
+ 		return err;
+@@ -699,6 +708,36 @@ static void macvlan_dellink(struct net_device *dev, struct list_head *head)
+ 		macvlan_port_destroy(port->dev);
+ }
+ 
++static int macvlan_changelink(struct net_device *dev,
++		struct nlattr *tb[], struct nlattr *data[])
++{
++	struct macvlan_dev *vlan = netdev_priv(dev);
++	if (data && data[IFLA_MACVLAN_MODE])
++		vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
++	return 0;
++}
++
++static size_t macvlan_get_size(const struct net_device *dev)
++{
++	return nla_total_size(4);
++}
++
++static int macvlan_fill_info(struct sk_buff *skb,
++				const struct net_device *dev)
++{
++	struct macvlan_dev *vlan = netdev_priv(dev);
++
++	NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode);
++	return 0;
++
++nla_put_failure:
++	return -EMSGSIZE;
++}
++
++static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
++	[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
++};
++
+ static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
+ 	.kind		= "macvlan",
+ 	.priv_size	= sizeof(struct macvlan_dev),
+@@ -707,6 +746,11 @@ static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
+ 	.validate	= macvlan_validate,
+ 	.newlink	= macvlan_newlink,
+ 	.dellink	= macvlan_dellink,
++	.maxtype	= IFLA_MACVLAN_MAX,
++	.policy		= macvlan_policy,
++	.changelink	= macvlan_changelink,
++	.get_size	= macvlan_get_size,
++	.fill_info	= macvlan_fill_info,
+ };
+ 
+ static int macvlan_device_event(struct notifier_block *unused,
+diff --git a/include/linux/if_link.h b/include/linux/if_link.h
+index 1d3b242..6674791 100644
+--- a/include/linux/if_link.h
++++ b/include/linux/if_link.h
+@@ -181,4 +181,19 @@ struct ifla_vlan_qos_mapping {
+ 	__u32 to;
+ };
+ 
++/* MACVLAN section */
++enum {
++	IFLA_MACVLAN_UNSPEC,
++	IFLA_MACVLAN_MODE,
++	__IFLA_MACVLAN_MAX,
++};
++
++#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
++
++enum macvlan_mode {
++	MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
++	MACVLAN_MODE_VEPA    = 2, /* talk to other ports through ext bridge */
++	MACVLAN_MODE_BRIDGE  = 4, /* talk to bridge ports directly */
++};
++
+ #endif /* _LINUX_IF_LINK_H */
+-- 
+1.6.6.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch	Tue Feb 16 03:10:04 2010	(r15162)
@@ -0,0 +1,206 @@
+From 618e1b7482f7a8a4c6c6e8ccbe140e4c331df4e9 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd at arndb.de>
+Date: Thu, 26 Nov 2009 06:07:10 +0000
+Subject: [PATCH 3/4] macvlan: implement bridge, VEPA and private mode
+
+This allows each macvlan slave device to be in one
+of three modes, depending on the use case:
+
+MACVLAN_PRIVATE:
+  The device never communicates with any other device
+  on the same upper_dev. This even includes frames
+  coming back from a reflective relay, where supported
+  by the adjacent bridge.
+
+MACVLAN_VEPA:
+  The new Virtual Ethernet Port Aggregator (VEPA) mode,
+  we assume that the adjacent bridge returns all frames
+  where both source and destination are local to the
+  macvlan port, i.e. the bridge is set up as a reflective
+  relay.
+  Broadcast frames coming in from the upper_dev get
+  flooded to all macvlan interfaces in VEPA mode.
+  We never deliver any frames locally.
+
+MACVLAN_BRIDGE:
+  We provide the behavior of a simple bridge between
+  different macvlan interfaces on the same port. Frames
+  from one interface to another one get delivered directly
+  and are not sent out externally. Broadcast frames get
+  flooded to all other bridge ports and to the external
+  interface, but when they come back from a reflective
+  relay, we don't deliver them again.
+  Since we know all the MAC addresses, the macvlan bridge
+  mode does not require learning or STP like the bridge
+  module does.
+
+Based on an earlier patch "macvlan: Reflect macvlan packets
+meant for other macvlan devices" by Eric Biederman.
+
+Signed-off-by: Arnd Bergmann <arnd at arndb.de>
+Acked-by: Patrick McHardy <kaber at trash.net>
+Cc: Eric Biederman <ebiederm at xmission.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ drivers/net/macvlan.c |   80 ++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 files changed, 72 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
+index 1e7faf9..d6bd843 100644
+--- a/drivers/net/macvlan.c
++++ b/drivers/net/macvlan.c
+@@ -29,9 +29,16 @@
+ #include <linux/if_link.h>
+ #include <linux/if_macvlan.h>
+ #include <net/rtnetlink.h>
++#include <net/xfrm.h>
+ 
+ #define MACVLAN_HASH_SIZE	(1 << BITS_PER_BYTE)
+ 
++enum macvlan_mode {
++	MACVLAN_MODE_PRIVATE	= 1,
++	MACVLAN_MODE_VEPA	= 2,
++	MACVLAN_MODE_BRIDGE	= 4,
++};
++
+ struct macvlan_port {
+ 	struct net_device	*dev;
+ 	struct hlist_head	vlan_hash[MACVLAN_HASH_SIZE];
+@@ -59,6 +66,7 @@ struct macvlan_dev {
+ 	struct macvlan_port	*port;
+ 	struct net_device	*lowerdev;
+ 	struct macvlan_rx_stats *rx_stats;
++	enum macvlan_mode	mode;
+ };
+ 
+ 
+@@ -134,11 +142,14 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
+ }
+ 
+ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev,
+-				 const struct ethhdr *eth)
++				 const struct ethhdr *eth, bool local)
+ {
+ 	if (!skb)
+ 		return NET_RX_DROP;
+ 
++	if (local)
++		return dev_forward_skb(dev, skb);
++
+ 	skb->dev = dev;
+ 	if (!compare_ether_addr_64bits(eth->h_dest,
+ 				       dev->broadcast))
+@@ -150,7 +161,9 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev,
+ }
+ 
+ static void macvlan_broadcast(struct sk_buff *skb,
+-			      const struct macvlan_port *port)
++			      const struct macvlan_port *port,
++			      struct net_device *src,
++			      enum macvlan_mode mode)
+ {
+ 	const struct ethhdr *eth = eth_hdr(skb);
+ 	const struct macvlan_dev *vlan;
+@@ -164,8 +177,12 @@ static void macvlan_broadcast(struct sk_buff *skb,
+ 
+ 	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
+ 		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
++			if (vlan->dev == src || !(vlan->mode & mode))
++				continue;
++
+ 			nskb = skb_clone(skb, GFP_ATOMIC);
+-			err = macvlan_broadcast_one(nskb, vlan->dev, eth);
++			err = macvlan_broadcast_one(nskb, vlan->dev, eth,
++					 mode == MACVLAN_MODE_BRIDGE);
+ 			macvlan_count_rx(vlan, skb->len + ETH_HLEN,
+ 					 err == NET_RX_SUCCESS, 1);
+ 		}
+@@ -178,6 +195,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 	const struct ethhdr *eth = eth_hdr(skb);
+ 	const struct macvlan_port *port;
+ 	const struct macvlan_dev *vlan;
++	const struct macvlan_dev *src;
+ 	struct net_device *dev;
+ 	unsigned int len;
+ 
+@@ -186,7 +204,25 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 		return skb;
+ 
+ 	if (is_multicast_ether_addr(eth->h_dest)) {
+-		macvlan_broadcast(skb, port);
++		src = macvlan_hash_lookup(port, eth->h_source);
++		if (!src)
++			/* frame comes from an external address */
++			macvlan_broadcast(skb, port, NULL,
++					  MACVLAN_MODE_PRIVATE |
++					  MACVLAN_MODE_VEPA    |
++					  MACVLAN_MODE_BRIDGE);
++		else if (src->mode == MACVLAN_MODE_VEPA)
++			/* flood to everyone except source */
++			macvlan_broadcast(skb, port, src->dev,
++					  MACVLAN_MODE_VEPA |
++					  MACVLAN_MODE_BRIDGE);
++		else if (src->mode == MACVLAN_MODE_BRIDGE)
++			/*
++			 * flood only to VEPA ports, bridge ports
++			 * already saw the frame on the way out.
++			 */
++			macvlan_broadcast(skb, port, src->dev,
++					  MACVLAN_MODE_VEPA);
+ 		return skb;
+ 	}
+ 
+@@ -212,18 +248,46 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+ 	return NULL;
+ }
+ 
++static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	const struct macvlan_dev *vlan = netdev_priv(dev);
++	const struct macvlan_port *port = vlan->port;
++	const struct macvlan_dev *dest;
++
++	if (vlan->mode == MACVLAN_MODE_BRIDGE) {
++		const struct ethhdr *eth = (void *)skb->data;
++
++		/* send to other bridge ports directly */
++		if (is_multicast_ether_addr(eth->h_dest)) {
++			macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE);
++			goto xmit_world;
++		}
++
++		dest = macvlan_hash_lookup(port, eth->h_dest);
++		if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
++			unsigned int length = skb->len + ETH_HLEN;
++			int ret = dev_forward_skb(dest->dev, skb);
++			macvlan_count_rx(dest, length,
++					 ret == NET_RX_SUCCESS, 0);
++
++			return NET_XMIT_SUCCESS;
++		}
++	}
++
++xmit_world:
++	skb->dev = vlan->lowerdev;
++	return dev_queue_xmit(skb);
++}
++
+ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
+ 				      struct net_device *dev)
+ {
+ 	int i = skb_get_queue_mapping(skb);
+ 	struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
+-	const struct macvlan_dev *vlan = netdev_priv(dev);
+ 	unsigned int len = skb->len;
+ 	int ret;
+ 
+-	skb->dev = vlan->lowerdev;
+-	ret = dev_queue_xmit(skb);
+-
++	ret = macvlan_queue_xmit(skb, dev);
+ 	if (likely(ret == NET_XMIT_SUCCESS)) {
+ 		txq->tx_packets++;
+ 		txq->tx_bytes += len;
+-- 
+1.6.6.2
+

Modified: dists/trunk/linux-2.6/debian/patches/series/9
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/9	Tue Feb 16 02:42:05 2010	(r15161)
+++ dists/trunk/linux-2.6/debian/patches/series/9	Tue Feb 16 03:10:04 2010	(r15162)
@@ -1,2 +1,7 @@
 + bugfix/all/cxusb-dont-select-lgs8gl5.patch
 + debian/sysrq-mask.patch
++ features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch
++ features/all/macvlan-Precise-RX-stats-accounting.patch
++ features/all/macvlan-cleanup-rx-statistics.patch
++ features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch
++ features/all/macvlan-export-macvlan-mode-through-netlink.patch



More information about the Kernel-svn-changes mailing list