The future kernel 2.6.33 will incorporate the macvlan bridge
mode where all the macvlan will be able to communicate if they are
using the same physical interface. This is an interesting feature
to have containers to communicate together. If we are outside of the
container, we have to setup a macvlan on the same physical interface than
the containers and use it to communicate with them.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 configure.ac         |    2 -
 doc/lxc.conf.sgml.in |   51 ++++++++++++++++++++++----
 src/lxc/conf.c       |   16 +++++---
 src/lxc/conf.h       |   11 +++++
 src/lxc/confile.c    |  100 ++++++++++++++++++++++++++++++++++++++-------------
 src/lxc/network.c    |   21 +++++++++-
 src/lxc/network.h    |    2 -
 7 files changed, 162 insertions(+), 41 deletions(-)

Index: lxc/configure.ac
===================================================================
--- lxc.orig/configure.ac
+++ lxc/configure.ac
@@ -44,7 +44,7 @@ AS_AC_EXPAND(DOCDIR, $docdir)
 AC_ARG_WITH([config-path],
 	[AC_HELP_STRING(
 		[--with-config-path=dir],
-		[lxc configuration repository]
+		[lxc configuration repository path]
 	)], [], [with_config_path="${localstatedir}/lib/lxc"])
 
 AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)")
Index: lxc/src/lxc/conf.c
===================================================================
--- lxc.orig/src/lxc/conf.c
+++ lxc/src/lxc/conf.c
@@ -834,8 +834,8 @@ static int instanciate_veth(struct lxc_n
 	char veth1buf[IFNAMSIZ], *veth1;
 	char veth2[IFNAMSIZ];
 
-	if (netdev->priv.pair)
-		veth1 = netdev->priv.pair;
+	if (netdev->priv.veth_attr.pair)
+		veth1 = netdev->priv.veth_attr.pair;
 	else {
 		snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
 		mktemp(veth1buf);
@@ -911,7 +911,8 @@ static int instanciate_macvlan(struct lx
 		return -1;
 	}
 
-	if (lxc_macvlan_create(netdev->link, peer)) {
+	if (lxc_macvlan_create(netdev->link, peer,
+			       netdev->priv.macvlan_attr.mode)) {
 		ERROR("failed to create macvlan interface '%s' on '%s'",
 		      peer, netdev->link);
 		return -1;
@@ -924,7 +925,8 @@ static int instanciate_macvlan(struct lx
 		return -1;
 	}
 
-	DEBUG("instanciated macvlan '%s', index is '%d'", peer, netdev->ifindex);
+	DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
+	      peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
 
 	return 0;
 }
@@ -939,7 +941,7 @@ static int instanciate_vlan(struct lxc_n
 		return -1;
 	}
 
-	snprintf(peer, sizeof(peer), "vlan%d",netdev->priv.vlan_attr.vid);
+	snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid);
 
 	if (lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid)) {
 		ERROR("failed to create vlan interface '%s' on '%s'",
@@ -954,7 +956,9 @@ static int instanciate_vlan(struct lxc_n
 		return -1;
 	}
 
-	DEBUG("instanciated vlan '%s', ifindex is '%d'", "vlan1000", netdev->ifindex);
+	DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
+	      netdev->ifindex);
+
 	return 0;
 }
 
Index: lxc/src/lxc/conf.h
===================================================================
--- lxc.orig/src/lxc/conf.h
+++ lxc/src/lxc/conf.h
@@ -71,6 +71,10 @@ struct lxc_route6 {
 	struct in6_addr addr;
 };
 
+struct ifla_veth {
+	char *pair; /* pair name */
+};
+
 struct ifla_vlan {
 	uint   flags;
 	uint   fmask;
@@ -78,9 +82,14 @@ struct ifla_vlan {
 	ushort   pad;
 };
 
+struct ifla_macvlan {
+	int mode; /* private, vepa, bridge */
+};
+
 union netdev_p {
-	char *pair;
+	struct ifla_veth veth_attr;
 	struct ifla_vlan vlan_attr;
+	struct ifla_macvlan macvlan_attr;
 };
 
 /*
Index: lxc/src/lxc/confile.c
===================================================================
--- lxc.orig/src/lxc/confile.c
+++ lxc/src/lxc/confile.c
@@ -50,9 +50,10 @@ static int config_network_type(const cha
 static int config_network_flags(const char *, char *, struct lxc_conf *);
 static int config_network_link(const char *, char *, struct lxc_conf *);
 static int config_network_name(const char *, char *, struct lxc_conf *);
-static int config_network_pair(const char *, char *, struct lxc_conf *);
+static int config_network_veth_pair(const char *, char *, struct lxc_conf *);
+static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *);
 static int config_network_hwaddr(const char *, char *, struct lxc_conf *);
-static int config_network_vlanid(const char *, char *, struct lxc_conf *);
+static int config_network_vlan_id(const char *, char *, struct lxc_conf *);
 static int config_network_mtu(const char *, char *, struct lxc_conf *);
 static int config_network_ipv4(const char *, char *, struct lxc_conf *);
 static int config_network_ipv6(const char *, char *, struct lxc_conf *);
@@ -66,22 +67,23 @@ struct config {
 
 static struct config config[] = {
 
-	{ "lxc.pts",            config_pts            },
-	{ "lxc.tty",            config_tty            },
-	{ "lxc.cgroup",         config_cgroup         },
-	{ "lxc.mount",          config_mount          },
-	{ "lxc.rootfs",         config_rootfs         },
-	{ "lxc.utsname",        config_utsname        },
-	{ "lxc.network.type",   config_network_type   },
-	{ "lxc.network.flags",  config_network_flags  },
-	{ "lxc.network.link",   config_network_link   },
-	{ "lxc.network.name",   config_network_name   },
-	{ "lxc.network.veth.pair",   config_network_pair   },
-	{ "lxc.network.hwaddr", config_network_hwaddr },
-	{ "lxc.network.mtu",    config_network_mtu    },
-	{ "lxc.network.vlan.id", config_network_vlanid },
-	{ "lxc.network.ipv4",   config_network_ipv4   },
-	{ "lxc.network.ipv6",   config_network_ipv6   },
+	{ "lxc.pts",                  config_pts                  },
+	{ "lxc.tty",                  config_tty                  },
+	{ "lxc.cgroup",               config_cgroup               },
+	{ "lxc.mount",                config_mount                },
+	{ "lxc.rootfs",               config_rootfs               },
+	{ "lxc.utsname",              config_utsname              },
+	{ "lxc.network.type",         config_network_type         },
+	{ "lxc.network.flags",        config_network_flags        },
+	{ "lxc.network.link",         config_network_link         },
+	{ "lxc.network.name",         config_network_name         },
+	{ "lxc.network.macvlan.mode", config_network_macvlan_mode },
+	{ "lxc.network.veth.pair",    config_network_veth_pair    },
+	{ "lxc.network.hwaddr",       config_network_hwaddr       },
+	{ "lxc.network.mtu",          config_network_mtu          },
+	{ "lxc.network.vlan.id",      config_network_vlan_id      },
+	{ "lxc.network.ipv4",         config_network_ipv4         },
+	{ "lxc.network.ipv6",         config_network_ipv6         },
 };
 
 static const size_t config_size = sizeof(config)/sizeof(struct config);
@@ -97,7 +99,8 @@ static struct config *getconfig(const ch
 	return NULL;
 }
 
-static int config_network_type(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_network_type(const char *key, char *value,
+			       struct lxc_conf *lxc_conf)
 {
 	struct lxc_list *network = &lxc_conf->network;
 	struct lxc_netdev *netdev;
@@ -190,6 +193,42 @@ static int network_ifname(char **valuep,
 	return 0;
 }
 
+#ifndef MACVLAN_MODE_PRIVATE
+#  define MACVLAN_MODE_PRIVATE 1
+#endif
+
+#ifndef MACVLAN_MODE_VEPA
+#  define MACVLAN_MODE_VEPA 2
+#endif
+
+#ifndef MACVLAN_MODE_BRIDGE
+#  define MACVLAN_MODE_BRIDGE 4
+#endif
+
+static int macvlan_mode(int *valuep, char *value)
+{
+	struct mc_mode {
+		char *name;
+		int mode;
+	} m[] = {
+		{ "private", MACVLAN_MODE_PRIVATE },
+		{ "vepa", MACVLAN_MODE_VEPA },
+		{ "bridge", MACVLAN_MODE_BRIDGE },
+	};
+
+	int i;
+
+	for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
+		if (strcmp(m[i].name, value))
+			continue;
+
+		*valuep = m[i].mode;
+		return 0;
+	}
+
+	return -1;
+}
+
 static int config_network_flags(const char *key, char *value,
 				struct lxc_conf *lxc_conf)
 {
@@ -228,8 +267,8 @@ static int config_network_name(const cha
 	return network_ifname(&netdev->name, value);
 }
 
-static int config_network_pair(const char *key, char *value,
-			       struct lxc_conf *lxc_conf)
+static int config_network_veth_pair(const char *key, char *value,
+				    struct lxc_conf *lxc_conf)
 {
 	struct lxc_netdev *netdev;
 
@@ -237,7 +276,19 @@ static int config_network_pair(const cha
 	if (!netdev)
 		return -1;
 
-	return network_ifname(&netdev->priv.pair, value);
+	return network_ifname(&netdev->priv.veth_attr.pair, value);
+}
+
+static int config_network_macvlan_mode(const char *key, char *value,
+				       struct lxc_conf *lxc_conf)
+{
+	struct lxc_netdev *netdev;
+
+	netdev = network_netdev(key, value, &lxc_conf->network);
+	if (!netdev)
+		return -1;
+
+	return macvlan_mode(&netdev->priv.macvlan_attr.mode, value);
 }
 
 static int config_network_hwaddr(const char *key, char *value,
@@ -258,7 +309,7 @@ static int config_network_hwaddr(const c
 	return 0;
 }
 
-static int config_network_vlanid(const char *key, char *value,
+static int config_network_vlan_id(const char *key, char *value,
 			       struct lxc_conf *lxc_conf)
 {
 	struct lxc_netdev *netdev;
@@ -359,7 +410,8 @@ static int config_network_ipv4(const cha
 	return 0;
 }
 
-static int config_network_ipv6(const char *key, char *value, struct lxc_conf *lxc_conf)
+static int config_network_ipv6(const char *key, char *value,
+			       struct lxc_conf *lxc_conf)
 {
 	struct lxc_netdev *netdev;
 	struct lxc_inet6dev *inet6dev;
Index: lxc/src/lxc/network.c
===================================================================
--- lxc.orig/src/lxc/network.c
+++ lxc/src/lxc/network.c
@@ -75,6 +75,10 @@
 # define VETH_INFO_PEER 1
 #endif
 
+#ifndef IFLA_MACVLAN_MODE
+# define IFLA_MACVLAN_MODE 1
+#endif
+
 struct link_req {
 	struct nlmsg nlmsg;
 	struct ifinfomsg ifinfomsg;
@@ -445,8 +449,10 @@ int lxc_vlan_create(const char *master, 
 	nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
 	if (!nest2)
 		goto err1;
+
 	if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid))
 		goto err1;
+
 	nla_end_nested(nlmsg, nest2);
 
 	nla_end_nested(nlmsg, nest);
@@ -470,12 +476,12 @@ err3:
 	return err;
 }
 
-int lxc_macvlan_create(const char *master, const char *name)
+int lxc_macvlan_create(const char *master, const char *name, int mode)
 {
 	struct nl_handler nlh;
 	struct nlmsg *nlmsg = NULL, *answer = NULL;
 	struct link_req *link_req;
-	struct rtattr *nest;
+	struct rtattr *nest, *nest2;
 	int index, len, err = -1;
 
 	if (netlink_open(&nlh, NETLINK_ROUTE))
@@ -515,6 +521,17 @@ int lxc_macvlan_create(const char *maste
 	if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan"))
 		goto out;
 
+	if (mode) {
+		nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
+		if (!nest2)
+			goto out;
+
+		if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode))
+			goto out;
+
+		nla_end_nested(nlmsg, nest2);
+	}
+
 	nla_end_nested(nlmsg, nest);
 
 	if (nla_put_u32(nlmsg, IFLA_LINK, index))
Index: lxc/src/lxc/network.h
===================================================================
--- lxc.orig/src/lxc/network.h
+++ lxc/src/lxc/network.h
@@ -66,7 +66,7 @@ extern int lxc_veth_create(const char *n
 /* 
  * Create a macvlan network device
  */
-extern int lxc_macvlan_create(const char *master, const char *name);
+extern int lxc_macvlan_create(const char *master, const char *name, int mode);
 
 /*
  * Create a vlan network device
Index: lxc/doc/lxc.conf.sgml.in
===================================================================
--- lxc.orig/doc/lxc.conf.sgml.in
+++ lxc/doc/lxc.conf.sgml.in
@@ -134,11 +134,28 @@ Foundation, Inc., 59 Temple Place, Suite
 	    <para>
 	      <option>veth:</option> a new network stack is created, a
 	      peer network device is created with one side assigned to
-	      the container and the other side attached to a bridge
-	      specified by the <option>lxc.network.link</option>. The
-	      bridge has to be setup before on the
-	      system, <command>lxc</command> won't handle
-	      configuration outside of the container.
+	      the container and the other side is attached to a bridge
+	      specified by the <option>lxc.network.link</option>. If
+	      the bridge is not specified, then the veth pair device
+	      will be created but not attached to any
+	      bridge. Otherwise, the bridge has to be setup before on
+	      the system, <command>lxc</command> won't handle
+	      any configuration outside of the container.  By
+	      default <command>lxc</command> choose a name for the
+	      network device belonging to the outside of the
+	      container, this name is handled
+	      by <command>lxc</command>, but if you wish to handle
+	      this name yourself, you can tell <command>lxc</command>
+	      to set a specific name with
+	      the <option>lxc.network.veth.pair</option> option.
+	    </para>
+
+	    <para>
+	      <option>vlan:</option> a new network stack is created, a
+	      vlan interface is linked with the interface specified by
+	      the <option>lxc.network.link</option> and assigned to
+	      the container. The vlan identifier is specified with the
+	      option <option>lxc.network.vlan.id</option>.
 	    </para>
 
 	    <para>
@@ -147,11 +164,33 @@ Foundation, Inc., 59 Temple Place, Suite
 	      interface specified by
 	      the <option>lxc.network.link</option> and assigned to
 	      the container.
+	      <option>lxc.network.macvlan.mode</option> specifies the
+	      mode the macvlan will use to communicate between
+	      different macvlan on the same upper device. The accepted
+	      modes are <option>private</option>, the device never
+	      communicates with any other device on the same upper_dev (default),
+	      <option>vepa</option>, the new Virtual Ethernet Port
+	      Aggregator (VEPA) mode, it assumes 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, local frames are not
+	      delivered locallay, or <option>bridge</option>, it
+	      provides 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.
 	    </para>
 
 	    <para>
 	      <option>phys:</option> a new network stack is created
-	      and the interface specified by
+	      and an already existing interface specified by
 	      the <option>lxc.network.link</option> is assigned to the
 	      container.
 	    </para>



