netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [NET 00/02]: MACVLAN driver
@ 2007-06-19 13:08 Patrick McHardy
  2007-06-19 13:08 ` [ETHERNET 01/02]: Validate new address in eth_mac_addr Patrick McHardy
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Patrick McHardy @ 2007-06-19 13:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, Patrick McHardy

These patches add a rewritten version of Ben's macvlan driver, which
allows to create virtual ethernet devices. The underlying device is
put in promiscous mode and packets are demuxed based on MAC address.
It behaves similar to bridge devices in that packets are visible on
the real device before delivery to the macvlan driver. The driver
supports all features of the underlying device except VLAN
acceleration, this is currently very hard to support. I might look
into this in the future.

The main downside of this driver is that it adds another hook in
netif_receive_skb, unfortunately that is unavoidable. When not
compiled in the hook vanishes of course.

Usage is simple:

# ip link add link eth0 type macvlan

Will create a macvlan0 device with a random MAC address on top of
eth0. No iproute patches are required.


Please apply, thanks.


 MAINTAINERS                |    6 +
 drivers/net/Kconfig        |   10 +
 drivers/net/Makefile       |    1 +
 drivers/net/macvlan.c      |  468 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/if_macvlan.h |    9 +
 include/linux/netdevice.h  |    2 +
 net/core/dev.c             |   26 +++
 net/ethernet/eth.c         |    3 +
 8 files changed, 525 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/macvlan.c
 create mode 100644 include/linux/if_macvlan.h

Patrick McHardy (2):
      [ETHERNET]: Validate new address in eth_mac_addr
      [NET]: Add MACVLAN driver

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ETHERNET 01/02]: Validate new address in eth_mac_addr
  2007-06-19 13:08 [NET 00/02]: MACVLAN driver Patrick McHardy
@ 2007-06-19 13:08 ` Patrick McHardy
  2007-06-19 13:08 ` [NET 02/02]: Add MACVLAN driver Patrick McHardy
  2007-06-19 16:00 ` [NET 00/02]: " Stephen Hemminger
  2 siblings, 0 replies; 13+ messages in thread
From: Patrick McHardy @ 2007-06-19 13:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, Patrick McHardy

[ETHERNET]: Validate new address in eth_mac_addr

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit c92ac42cd3badaf120e97223ac4798abf5226424
tree 824d080a4748fcd6f025bbe7b9466feee46e3303
parent 45da27ba265dba3c740c45d47f584c30d7066f82
author Patrick McHardy <kaber@trash.net> Mon, 18 Jun 2007 16:15:32 +0200
committer Patrick McHardy <kaber@trash.net> Mon, 18 Jun 2007 16:15:32 +0200

 net/ethernet/eth.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 0ac2524..9298a2c 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -266,8 +266,11 @@ void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev,
 static int eth_mac_addr(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
+
 	if (netif_running(dev))
 		return -EBUSY;
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [NET 02/02]: Add MACVLAN driver
  2007-06-19 13:08 [NET 00/02]: MACVLAN driver Patrick McHardy
  2007-06-19 13:08 ` [ETHERNET 01/02]: Validate new address in eth_mac_addr Patrick McHardy
@ 2007-06-19 13:08 ` Patrick McHardy
  2007-06-19 16:00 ` [NET 00/02]: " Stephen Hemminger
  2 siblings, 0 replies; 13+ messages in thread
From: Patrick McHardy @ 2007-06-19 13:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, Patrick McHardy

[NET]: Add MACVLAN driver

Add macvlan driver, which allows to create virtual ethernet devices
based on MAC address.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 890e2ae4ef5599ee34f280af4882f97c2dcfcb7b
tree a41a8564a8add18a2095a18d4a3f1a2ce0c25997
parent c92ac42cd3badaf120e97223ac4798abf5226424
author Patrick McHardy <kaber@trash.net> Tue, 19 Jun 2007 15:01:06 +0200
committer Patrick McHardy <kaber@trash.net> Tue, 19 Jun 2007 15:01:06 +0200

 MAINTAINERS                |    6 +
 drivers/net/Kconfig        |   10 +
 drivers/net/Makefile       |    1 
 drivers/net/macvlan.c      |  468 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/if_macvlan.h |    9 +
 include/linux/netdevice.h  |    2 
 net/core/dev.c             |   26 ++
 7 files changed, 522 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4c715a7..7d61360 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2320,6 +2320,12 @@ W:	http://linuxwireless.org/
 T:	git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git
 S:	Maintained
 
+MACVLAN DRIVER
+P:	Patrick McHardy
+M:	kaber@trash.net
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 MARVELL YUKON / SYSKONNECT DRIVER
 P:	Mirko Lindner
 M: 	mlindner@syskonnect.de
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 7d57f4a..6c3c1f0 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -77,6 +77,16 @@ config BONDING
 	  To compile this driver as a module, choose M here: the module
 	  will be called bonding.
 
+config MACVLAN
+	tristate "MAC-VLAN support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	---help---
+	  This allows one to create virtual interfaces that map packets to
+	  or from specific MAC addresses to a particular interface.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called macvlan.
+
 config EQUALIZER
 	tristate "EQL (serial line load balancing) support"
 	---help---
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a77affa..fc10e37 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_SLHC) += slhc.o
 
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_IFB) += ifb.o
+obj-$(CONFIG_MACVLAN) += macvlan.o
 obj-$(CONFIG_DE600) += de600.o
 obj-$(CONFIG_DE620) += de620.o
 obj-$(CONFIG_LANCE) += lance.o
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
new file mode 100644
index 0000000..39ca0a2
--- /dev/null
+++ b/drivers/net/macvlan.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * The code this is based on carried the following copyright notice:
+ * ---
+ * (C) Copyright 2001-2006
+ * Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
+ * Re-worked by Ben Greear <greearb@candelatech.com>
+ * ---
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_arp.h>
+#include <linux/if_link.h>
+#include <linux/if_macvlan.h>
+#include <net/rtnetlink.h>
+
+#define MACVLAN_HASH_SIZE	(1 << BITS_PER_BYTE)
+
+struct macvlan_port {
+	struct list_head	list;
+	struct net_device	*dev;
+	struct hlist_head	vlan_hash[MACVLAN_HASH_SIZE];
+	struct list_head	vlans;
+};
+
+struct macvlan_dev {
+	struct net_device	*dev;
+	struct list_head	list;
+	struct hlist_node	hlist;
+	struct macvlan_port	*port;
+	struct net_device	*lowerdev;
+};
+
+
+static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
+					       const unsigned char *addr)
+{
+	struct macvlan_dev *vlan;
+	struct hlist_node *n;
+
+	hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) {
+		if (!compare_ether_addr(vlan->dev->dev_addr, addr))
+			return vlan;
+	}
+	return NULL;
+}
+
+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;
+
+	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
+		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
+			dev = vlan->dev;
+			if (unlikely(!(dev->flags & IFF_UP)))
+				continue;
+
+			nskb = skb_clone(skb, GFP_ATOMIC);
+			if (nskb == NULL) {
+				dev->stats.rx_errors++;
+				dev->stats.rx_dropped++;
+				continue;
+			}
+
+			dev->stats.rx_bytes += skb->len + ETH_HLEN;
+			dev->stats.rx_packets++;
+			dev->stats.multicast++;
+			dev->last_rx = jiffies;
+
+			nskb->dev = dev;
+			if (!compare_ether_addr(eth->h_dest, dev->broadcast))
+				nskb->pkt_type = PACKET_BROADCAST;
+			else
+				nskb->pkt_type = PACKET_MULTICAST;
+
+			netif_rx(nskb);
+		}
+	}
+}
+
+/* called under rcu_read_lock() from netif_receive_skb() */
+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;
+	struct net_device *dev;
+
+	port = rcu_dereference(skb->dev->macvlan_port);
+	if (port == NULL)
+		return skb;
+
+	if (is_multicast_ether_addr(eth->h_dest)) {
+		macvlan_broadcast(skb, port);
+		return skb;
+	}
+
+	vlan = macvlan_hash_lookup(port, eth->h_dest);
+	if (vlan == NULL)
+		return skb;
+
+	dev = vlan->dev;
+	if (unlikely(!(dev->flags & IFF_UP))) {
+		kfree_skb(skb);
+		return NULL;
+	}
+
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (skb == NULL) {
+		dev->stats.rx_errors++;
+		dev->stats.rx_dropped++;
+		return NULL;
+	}
+
+	dev->stats.rx_bytes += skb->len + ETH_HLEN;
+	dev->stats.rx_packets++;
+	dev->last_rx = jiffies;
+
+	skb->dev = dev;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+	return NULL;
+}
+
+static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct macvlan_dev *vlan = netdev_priv(dev);
+	unsigned int len = skb->len;
+	int ret;
+
+	skb->dev = vlan->lowerdev;
+	ret = dev_queue_xmit(skb);
+
+	if (likely(ret == NET_XMIT_SUCCESS)) {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += len;
+	} else {
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
+	}
+	return NETDEV_TX_OK;
+}
+
+static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
+			       unsigned short type, void *daddr, void *saddr,
+			       unsigned len)
+{
+	const struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+
+	return lowerdev->hard_header(skb, lowerdev, type, daddr,
+				     saddr ? : dev->dev_addr, len);
+}
+
+static int macvlan_open(struct net_device *dev)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	struct macvlan_port *port = vlan->port;
+
+	hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
+	dev_set_promiscuity(vlan->lowerdev, 1);
+	return 0;
+}
+
+static int macvlan_stop(struct net_device *dev)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	dev_set_promiscuity(vlan->lowerdev, -1);
+	hlist_del_rcu(&vlan->hlist);
+	synchronize_rcu();
+	return 0;
+}
+
+static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	if (new_mtu < 68 || vlan->lowerdev->mtu < new_mtu)
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+/*
+ * macvlan network devices have devices nesting below it and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key macvlan_netdev_xmit_lock_key;
+
+#define MACVLAN_FEATURES \
+	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+	 NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
+	 NETIF_F_TSO_ECN | NETIF_F_TSO6)
+
+#define MACVLAN_STATE_MASK \
+	((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
+
+static int macvlan_init(struct net_device *dev)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+
+	dev->state		= (dev->state & ~MACVLAN_STATE_MASK) |
+				  (lowerdev->state & MACVLAN_STATE_MASK);
+	dev->features 		= lowerdev->features & MACVLAN_FEATURES;
+	dev->iflink		= lowerdev->ifindex;
+
+	lockdep_set_class(&dev->_xmit_lock, &macvlan_netdev_xmit_lock_key);
+	return 0;
+}
+
+static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
+					struct ethtool_drvinfo *drvinfo)
+{
+	snprintf(drvinfo->driver, 32, "macvlan");
+	snprintf(drvinfo->version, 32, "0.1");
+}
+
+static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
+{
+	const struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+
+	if (lowerdev->ethtool_ops->get_rx_csum == NULL)
+		return 0;
+	return lowerdev->ethtool_ops->get_rx_csum(lowerdev);
+}
+
+static const struct ethtool_ops macvlan_ethtool_ops = {
+	.get_link		= ethtool_op_get_link,
+	.get_rx_csum		= macvlan_ethtool_get_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.get_tso		= ethtool_op_get_tso,
+	.get_ufo		= ethtool_op_get_ufo,
+	.get_sg			= ethtool_op_get_sg,
+	.get_drvinfo		= macvlan_ethtool_get_drvinfo,
+};
+
+static void macvlan_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+
+	dev->init		= macvlan_init;
+	dev->open		= macvlan_open;
+	dev->stop		= macvlan_stop;
+	dev->change_mtu		= macvlan_change_mtu;
+	dev->hard_header	= macvlan_hard_header;
+	dev->hard_start_xmit	= macvlan_hard_start_xmit;
+	dev->destructor		= free_netdev;
+	dev->ethtool_ops	= &macvlan_ethtool_ops;
+	dev->tx_queue_len	= 0;
+
+	random_ether_addr(dev->dev_addr);
+}
+
+static LIST_HEAD(port_list);
+
+static int macvlan_port_create(struct net_device *dev)
+{
+	struct macvlan_port *port;
+	unsigned int i;
+
+	if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
+		return -EINVAL;
+
+	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	if (port == NULL)
+		return -ENOMEM;
+
+	port->dev = dev;
+	INIT_LIST_HEAD(&port->vlans);
+	for (i = 0; i < MACVLAN_HASH_SIZE; i++)
+		INIT_HLIST_HEAD(&port->vlan_hash[i]);
+	rcu_assign_pointer(dev->macvlan_port, port);
+
+	list_add_tail(&port->list, &port_list);
+	return 0;
+}
+
+static void macvlan_dellink(struct net_device *dev);
+
+static void macvlan_port_cleanup(struct net_device *dev)
+{
+	struct macvlan_port *port = dev->macvlan_port;
+	struct macvlan_dev *vlan, *next;
+
+	list_for_each_entry_safe(vlan, next, &port->vlans, list)
+		macvlan_dellink(vlan->dev);
+
+	rcu_assign_pointer(dev->macvlan_port, NULL);
+	synchronize_rcu();
+
+	list_del(&port->list);
+	kfree(port);
+}
+
+static void macvlan_transfer_operstate(struct net_device *dev)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	const struct net_device *lowerdev = vlan->lowerdev;
+
+	if (lowerdev->operstate == IF_OPER_DORMANT)
+		netif_dormant_on(dev);
+	else
+		netif_dormant_off(dev);
+
+	if (netif_carrier_ok(lowerdev)) {
+		if (!netif_carrier_ok(dev))
+			netif_carrier_on(dev);
+	} else {
+		if (netif_carrier_ok(lowerdev))
+			netif_carrier_off(dev);
+	}
+}
+
+static int macvlan_newlink(struct net_device *dev,
+			   struct nlattr *tb[], struct nlattr *data[])
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	struct macvlan_port *port;
+	struct net_device *lowerdev;
+	int err;
+
+	if (!tb[IFLA_LINK])
+		return -EINVAL;
+
+	lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+	if (lowerdev == NULL)
+		return -ENODEV;
+
+	if (!tb[IFLA_MTU])
+		dev->mtu = lowerdev->mtu;
+	else if (dev->mtu > lowerdev->mtu)
+		return -EINVAL;
+
+	if (lowerdev->macvlan_port == NULL) {
+		err = macvlan_port_create(lowerdev);
+		if (err < 0)
+			return err;
+	}
+	port = lowerdev->macvlan_port;
+
+	vlan->lowerdev = lowerdev;
+	vlan->dev      = dev;
+	vlan->port     = port;
+
+	err = register_netdevice(dev);
+	if (err < 0)
+		return err;
+
+	list_add_tail(&vlan->list, &port->vlans);
+	macvlan_transfer_operstate(dev);
+	return 0;
+}
+
+static void macvlan_dellink(struct net_device *dev)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	list_del(&vlan->list);
+	unregister_netdevice(dev);
+}
+
+static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
+	.kind		= "macvlan",
+	.priv_size	= sizeof(struct macvlan_dev),
+	.setup		= macvlan_setup,
+	.newlink	= macvlan_newlink,
+	.dellink	= macvlan_dellink,
+};
+
+static int macvlan_device_event(struct notifier_block *unused,
+				unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+	struct macvlan_dev *vlan;
+	struct macvlan_port *port;
+
+	port = dev->macvlan_port;
+	if (port == NULL)
+		goto out;
+
+	switch (event) {
+	case NETDEV_CHANGE:
+		list_for_each_entry(vlan, &port->vlans, list)
+			macvlan_transfer_operstate(vlan->dev);
+		break;
+	case NETDEV_FEAT_CHANGE:
+		list_for_each_entry(vlan, &port->vlans, list) {
+			vlan->dev->features = dev->features & MACVLAN_FEATURES;
+			netdev_features_change(vlan->dev);
+		}
+		break;
+	case NETDEV_UNREGISTER:
+		macvlan_port_cleanup(dev);
+		break;
+	}
+out:
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block macvlan_notifier_block __read_mostly = {
+	.notifier_call	= macvlan_device_event,
+};
+
+static int __init macvlan_init_module(void)
+{
+	int err;
+
+	register_netdevice_notifier(&macvlan_notifier_block);
+	macvlan_handle_frame_hook = macvlan_handle_frame;
+
+	err = rtnl_link_register(&macvlan_link_ops);
+	if (err < 0)
+		goto err1;
+	return 0;
+err1:
+	macvlan_handle_frame_hook = macvlan_handle_frame;
+	unregister_netdevice_notifier(&macvlan_notifier_block);
+	return err;
+}
+
+static void __exit macvlan_cleanup_module(void)
+{
+	struct macvlan_port *port, *next;
+
+	rtnl_lock();
+	list_for_each_entry_safe(port, next, &port_list, list)
+		macvlan_port_cleanup(port->dev);
+	__rtnl_link_unregister(&macvlan_link_ops);
+	rtnl_unlock();
+
+	macvlan_handle_frame_hook = NULL;
+	unregister_netdevice_notifier(&macvlan_notifier_block);
+}
+
+module_init(macvlan_init_module);
+module_exit(macvlan_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("Driver for MAC address based VLANs");
+MODULE_ALIAS_RTNL_LINK("macvlan");
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
new file mode 100644
index 0000000..0d9d7ea
--- /dev/null
+++ b/include/linux/if_macvlan.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_IF_MACVLAN_H
+#define _LINUX_IF_MACVLAN_H
+
+#ifdef __KERNEL__
+
+extern struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e7913ee..868140d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -535,6 +535,8 @@ struct net_device
 
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
+	/* macvlan */
+	struct macvlan_port	*macvlan_port;
 
 	/* class/net/name entry */
 	struct device		dev;
diff --git a/net/core/dev.c b/net/core/dev.c
index 2609062..5974e5b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -98,6 +98,7 @@
 #include <linux/seq_file.h>
 #include <linux/stat.h>
 #include <linux/if_bridge.h>
+#include <linux/if_macvlan.h>
 #include <net/dst.h>
 #include <net/pkt_sched.h>
 #include <net/checksum.h>
@@ -1793,6 +1794,28 @@ static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
 #define handle_bridge(skb, pt_prev, ret, orig_dev)	(skb)
 #endif
 
+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
+struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *skb) __read_mostly;
+EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
+
+static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
+					     struct packet_type **pt_prev,
+					     int *ret,
+					     struct net_device *orig_dev)
+{
+	if (skb->dev->macvlan_port == NULL)
+		return skb;
+
+	if (*pt_prev) {
+		*ret = deliver_skb(skb, *pt_prev, orig_dev);
+		*pt_prev = NULL;
+	}
+	return macvlan_handle_frame_hook(skb);
+}
+#else
+#define handle_macvlan(skb, pt_prev, ret, orig_dev)	(skb)
+#endif
+
 #ifdef CONFIG_NET_CLS_ACT
 /* TODO: Maybe we should just force sch_ingress to be compiled in
  * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -1900,6 +1923,9 @@ ncls:
 	skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
 	if (!skb)
 		goto out;
+	skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
+	if (!skb)
+		goto out;
 
 	type = skb->protocol;
 	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 13:08 [NET 00/02]: MACVLAN driver Patrick McHardy
  2007-06-19 13:08 ` [ETHERNET 01/02]: Validate new address in eth_mac_addr Patrick McHardy
  2007-06-19 13:08 ` [NET 02/02]: Add MACVLAN driver Patrick McHardy
@ 2007-06-19 16:00 ` Stephen Hemminger
  2007-06-19 19:53   ` Chris Leech
  2007-06-19 21:14   ` Patrick McHardy
  2 siblings, 2 replies; 13+ messages in thread
From: Stephen Hemminger @ 2007-06-19 16:00 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: davem, netdev, Patrick McHardy

On Tue, 19 Jun 2007 15:08:41 +0200 (MEST)
Patrick McHardy <kaber@trash.net> wrote:

> These patches add a rewritten version of Ben's macvlan driver, which
> allows to create virtual ethernet devices. The underlying device is
> put in promiscous mode and packets are demuxed based on MAC address.
> It behaves similar to bridge devices in that packets are visible on
> the real device before delivery to the macvlan driver. The driver
> supports all features of the underlying device except VLAN
> acceleration, this is currently very hard to support. I might look
> into this in the future.
> 
> The main downside of this driver is that it adds another hook in
> netif_receive_skb, unfortunately that is unavoidable. When not
> compiled in the hook vanishes of course.
> 
> Usage is simple:
> 
> # ip link add link eth0 type macvlan
> 
> Will create a macvlan0 device with a random MAC address on top of
> eth0. No iproute patches are required.
> 
> 
> Please apply, thanks.
> 

Looks good. I have some changes to allow devices with multiple MAC addresses
(never finished).  This device could use that.
-- 
Stephen Hemminger <shemminger@linux-foundation.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 16:00 ` [NET 00/02]: " Stephen Hemminger
@ 2007-06-19 19:53   ` Chris Leech
  2007-06-19 21:14   ` Patrick McHardy
  1 sibling, 0 replies; 13+ messages in thread
From: Chris Leech @ 2007-06-19 19:53 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

On 6/19/07, Stephen Hemminger <shemminger@linux-foundation.org> wrote:
> Looks good. I have some changes to allow devices with multiple MAC addresses
> (never finished).  This device could use that.

Stephen,

Is this patch available somewhere?  I'd be interested in taking a look at it.

- Chris

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 16:00 ` [NET 00/02]: " Stephen Hemminger
  2007-06-19 19:53   ` Chris Leech
@ 2007-06-19 21:14   ` Patrick McHardy
  2007-06-19 22:29     ` Stephen Hemminger
  2007-06-19 22:48     ` David Miller
  1 sibling, 2 replies; 13+ messages in thread
From: Patrick McHardy @ 2007-06-19 21:14 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: davem, netdev

Stephen Hemminger wrote:
> Looks good. I have some changes to allow devices with multiple MAC addresses
> (never finished).  This device could use that.


How would the driver do that? I was thinking about using dev_add_mc,
but wasn't sure if that would work with all drivers for non-multicast
addresses.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 21:14   ` Patrick McHardy
@ 2007-06-19 22:29     ` Stephen Hemminger
  2007-06-19 22:48     ` David Miller
  1 sibling, 0 replies; 13+ messages in thread
From: Stephen Hemminger @ 2007-06-19 22:29 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: davem, netdev

On Tue, 19 Jun 2007 23:14:21 +0200
Patrick McHardy <kaber@trash.net> wrote:

> Stephen Hemminger wrote:
> > Looks good. I have some changes to allow devices with multiple MAC addresses
> > (never finished).  This device could use that.
> 
> 
> How would the driver do that? I was thinking about using dev_add_mc,
> but wasn't sure if that would work with all drivers for non-multicast
> addresses.
> 

Basically, add a new dev_add_addr hook to netdevice.
Drivers that can do it, would add the hook. If driver didn't have hook,
then core would put device into promiscuous.  Most devices with multicast
allow non-multicast addresses, so it could be a simple extension.
Rather than doing it for all devices, wanted to go in one by one and test.

-- 
Stephen Hemminger <shemminger@linux-foundation.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 21:14   ` Patrick McHardy
  2007-06-19 22:29     ` Stephen Hemminger
@ 2007-06-19 22:48     ` David Miller
  2007-06-19 23:44       ` Patrick McHardy
  2007-06-20  6:34       ` Jeff Garzik
  1 sibling, 2 replies; 13+ messages in thread
From: David Miller @ 2007-06-19 22:48 UTC (permalink / raw)
  To: kaber; +Cc: shemminger, netdev

From: Patrick McHardy <kaber@trash.net>
Date: Tue, 19 Jun 2007 23:14:21 +0200

> Stephen Hemminger wrote:
> > Looks good. I have some changes to allow devices with multiple MAC addresses
> > (never finished).  This device could use that.
> 
> 
> How would the driver do that? I was thinking about using dev_add_mc,
> but wasn't sure if that would work with all drivers for non-multicast
> addresses.

This is actually a real issue for virtualization, and many
if not all current generation ethernet chips support
programming several unicast ethernet addresses in the MAC.

Networking switches in domain0 on virtualization hosts use
this feature to support seperate MACs per guest node,
and if the chip doesn't support this the chip is put into
promiscuous mode.

We don't have any clean interfaces by which to do this MAC
programming, and we do need something for it soon.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 22:48     ` David Miller
@ 2007-06-19 23:44       ` Patrick McHardy
  2007-06-20  6:34       ` Jeff Garzik
  1 sibling, 0 replies; 13+ messages in thread
From: Patrick McHardy @ 2007-06-19 23:44 UTC (permalink / raw)
  To: David Miller; +Cc: shemminger, netdev

David Miller wrote:
> From: Patrick McHardy <kaber@trash.net>
> Date: Tue, 19 Jun 2007 23:14:21 +0200
>
>   
>> Stephen Hemminger wrote:
>>     
>>> Looks good. I have some changes to allow devices with multiple MAC addresses
>>> (never finished).  This device could use that.
>>>       
>> How would the driver do that? I was thinking about using dev_add_mc,
>> but wasn't sure if that would work with all drivers for non-multicast
>> addresses.
>>     
>
> This is actually a real issue for virtualization, and many
> if not all current generation ethernet chips support
> programming several unicast ethernet addresses in the MAC.
>
> Networking switches in domain0 on virtualization hosts use
> this feature to support seperate MACs per guest node,
> and if the chip doesn't support this the chip is put into
> promiscuous mode.
>
> We don't have any clean interfaces by which to do this MAC
> programming, and we do need something for it soon.
>   

Stephen's suggestion sounds reasonable and easily implementable,
I'll see if I can come up with a patch.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-19 22:48     ` David Miller
  2007-06-19 23:44       ` Patrick McHardy
@ 2007-06-20  6:34       ` Jeff Garzik
  2007-06-20 19:35         ` Prafulla Deuskar
  1 sibling, 1 reply; 13+ messages in thread
From: Jeff Garzik @ 2007-06-20  6:34 UTC (permalink / raw)
  To: David Miller, kaber; +Cc: shemminger, netdev

David Miller wrote:
> This is actually a real issue for virtualization, and many
> if not all current generation ethernet chips support
> programming several unicast ethernet addresses in the MAC.
> 
> Networking switches in domain0 on virtualization hosts use
> this feature to support seperate MACs per guest node,
> and if the chip doesn't support this the chip is put into
> promiscuous mode.
> 
> We don't have any clean interfaces by which to do this MAC
> programming, and we do need something for it soon.


Yep, that's been on my long term wish list for a while, as well.

Overall I would like to see a more flexible way of allowing the net 
stack to learn each NIC's RX filter capabilities, and exploiting them. 
Plenty of NICs, even 100Mbps ones, support RX filter management that 
allows scanning for $hw_limit unicast addresses, before having to put 
the hardware into promisc mode.

	Jeff



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-20  6:34       ` Jeff Garzik
@ 2007-06-20 19:35         ` Prafulla Deuskar
  2007-06-21 14:57           ` Patrick McHardy
  0 siblings, 1 reply; 13+ messages in thread
From: Prafulla Deuskar @ 2007-06-20 19:35 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: David Miller, kaber, shemminger, netdev

On 6/19/07, Jeff Garzik <jeff@garzik.org> wrote:
> David Miller wrote:
> > This is actually a real issue for virtualization, and many
> > if not all current generation ethernet chips support
> > programming several unicast ethernet addresses in the MAC.
> >
> > Networking switches in domain0 on virtualization hosts use
> > this feature to support seperate MACs per guest node,
> > and if the chip doesn't support this the chip is put into
> > promiscuous mode.
> >
> > We don't have any clean interfaces by which to do this MAC
> > programming, and we do need something for it soon.
>
>
> Yep, that's been on my long term wish list for a while, as well.
>
> Overall I would like to see a more flexible way of allowing the net
> stack to learn each NIC's RX filter capabilities, and exploiting them.
> Plenty of NICs, even 100Mbps ones, support RX filter management that
> allows scanning for $hw_limit unicast addresses, before having to put
> the hardware into promisc mode.
>
>        Jeff

So how do we manage mac address to RX queue association?
Ideally we should extend ethtool to do that rather than inventing a
new tool - Is that acceptable?

-Prafulla

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
  2007-06-20 19:35         ` Prafulla Deuskar
@ 2007-06-21 14:57           ` Patrick McHardy
  0 siblings, 0 replies; 13+ messages in thread
From: Patrick McHardy @ 2007-06-21 14:57 UTC (permalink / raw)
  To: Prafulla Deuskar; +Cc: Jeff Garzik, David Miller, shemminger, netdev

Prafulla Deuskar wrote:
> On 6/19/07, Jeff Garzik <jeff@garzik.org> wrote:
>> David Miller wrote:
>> > This is actually a real issue for virtualization, and many
>> > if not all current generation ethernet chips support
>> > programming several unicast ethernet addresses in the MAC.
>> >
>> > Networking switches in domain0 on virtualization hosts use
>> > this feature to support seperate MACs per guest node,
>> > and if the chip doesn't support this the chip is put into
>> > promiscuous mode.
>> >
>> > We don't have any clean interfaces by which to do this MAC
>> > programming, and we do need something for it soon.
>>
>>
>> Yep, that's been on my long term wish list for a while, as well.
>>
>> Overall I would like to see a more flexible way of allowing the net
>> stack to learn each NIC's RX filter capabilities, and exploiting them.
>> Plenty of NICs, even 100Mbps ones, support RX filter management that
>> allows scanning for $hw_limit unicast addresses, before having to put
>> the hardware into promisc mode.
>>
>>        Jeff
>
> So how do we manage mac address to RX queue association? 


This is not about multiple RX queues but filtering multiple unicast
addresses without going to promiscous mode. The addresses are used
by something outside the driver, like macvlan.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [NET 00/02]: MACVLAN driver
@ 2007-06-24  4:52 Mark Smith
  0 siblings, 0 replies; 13+ messages in thread
From: Mark Smith @ 2007-06-24  4:52 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

(Applogies for not maintaining thread id, I'm not subscribed.)

>> We don't have any clean interfaces by which to do this MAC
>> programming, and we do need something for it soon.


>Yep, that's been on my long term wish list for a while, as well.

>Overall I would like to see a more flexible way of allowing the net 
>stack to learn each NIC's RX filter capabilities, and exploiting them. 
>Plenty of NICs, even 100Mbps ones, support RX filter management that 
>allows scanning for $hw_limit unicast addresses, before having to put 
>the hardware into promisc mode.
>

A thought I had when I discovered this ability in the
Natsemi/NS83815 chip was to use these RX filters for perfect multicast
DA matching until they ran out, and then reverting to the normal
Multicast DA matching mechanisms.

Another alternative use I thought of was to use these filters to filter
out different ethernet protocol types e.g. if an interface is only
going to be processing IPv4 packets, program these filters to only
accept frames with type 0800 for IP and 0806 for ARP, reverting to
non-filtering if there are too many protocol types, as per the way the
interfaces operate today.

I think it could be useful to expose the ability to have the NIC ignore
broadcast packets, or more generally, expose the three catagories of
address recognition that NICs seem to allow to be enabled / disabled -
unicast, multicast and broadcast.

If an interface then didn't need to have broadcast reception enabled
e.g. an IPv6 only interface (or Appletalk), then it wouldn't be,
preventing the host from having to process broadcasts it's going to
ignore anyway.

A future common scenario where this ability might be useful would be
LANs with a mix of IPv4 only, IPv4/IPv6 and IPv6-only nodes.

The ability to enable/disable unicast, multicast and broadcast address
recognition individually on a NIC seems to be widespread -  I've found
that the original early to mid 90s Ne2K chip, the NS8390D, the Netgear
FA311/FA312 chip, the NS83815 and the SMC Epic/100 chip all have
specific individual register values for those three types of addresses.

Regards,
Mark.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2007-06-24  5:44 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-19 13:08 [NET 00/02]: MACVLAN driver Patrick McHardy
2007-06-19 13:08 ` [ETHERNET 01/02]: Validate new address in eth_mac_addr Patrick McHardy
2007-06-19 13:08 ` [NET 02/02]: Add MACVLAN driver Patrick McHardy
2007-06-19 16:00 ` [NET 00/02]: " Stephen Hemminger
2007-06-19 19:53   ` Chris Leech
2007-06-19 21:14   ` Patrick McHardy
2007-06-19 22:29     ` Stephen Hemminger
2007-06-19 22:48     ` David Miller
2007-06-19 23:44       ` Patrick McHardy
2007-06-20  6:34       ` Jeff Garzik
2007-06-20 19:35         ` Prafulla Deuskar
2007-06-21 14:57           ` Patrick McHardy
  -- strict thread matches above, loose matches on Subject: below --
2007-06-24  4:52 Mark Smith

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).