[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