macvlan: Add bridge, VEPA and private modes (Closes: #568756)
svn path=/dists/trunk/linux-2.6/; revision=15162
This commit is contained in:
parent
50a54703bd
commit
f47edd511c
|
@ -5,6 +5,7 @@ linux-2.6 (2.6.32-9) UNRELEASED; urgency=low
|
|||
* [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)
|
||||
|
|
64
debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch
vendored
Normal file
64
debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
From 2b071e9effc16db91cd17577a35b0e61e9fcee9d Mon Sep 17 00:00:00 2001
|
||||
From: Ben Hutchings <ben@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
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
From fccaf71011b171883efee5bae321eac4760584d1 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Dumazet <eric.dumazet@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@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@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
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
From a1e514c5d0397b5581721aad9b303f7df83b103d Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@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@arndb.de>
|
||||
Acked-by: Patrick McHardy <kaber@trash.net>
|
||||
Signed-off-by: David S. Miller <davem@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
|
||||
|
143
debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch
vendored
Normal file
143
debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
From 27c0b1a850cdea6298f573d835782f3337be913c Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@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@arndb.de>
|
||||
Acked-by: Patrick McHardy <kaber@trash.net>
|
||||
Signed-off-by: David S. Miller <davem@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
|
||||
|
206
debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch
vendored
Normal file
206
debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch
vendored
Normal file
|
@ -0,0 +1,206 @@
|
|||
From 618e1b7482f7a8a4c6c6e8ccbe140e4c331df4e9 Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@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@arndb.de>
|
||||
Acked-by: Patrick McHardy <kaber@trash.net>
|
||||
Cc: Eric Biederman <ebiederm@xmission.com>
|
||||
Signed-off-by: David S. Miller <davem@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
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue