    Add VLAN support in config
    
    This adds ability to migrate vlan interfaces into namespaces
    by specifying them in a config
    
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Acked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>

---
 configure.ac                  |    1 
 doc/examples/Makefile.am      |    2 +
 doc/examples/lxc-vlan.conf.in |    9 ++++
 src/lxc/conf.c                |   31 ++++++++++++++++
 src/lxc/conf.h                |   10 +++++
 src/lxc/confile.c             |   20 ++++++++++
 src/lxc/lxc-checkconfig.in    |    1 
 src/lxc/network.c             |   78 ++++++++++++++++++++++++++++++++++++++++++
 src/lxc/network.h             |    5 ++
 9 files changed, 157 insertions(+)

Index: lxc/configure.ac
===================================================================
--- lxc.orig/configure.ac
+++ lxc/configure.ac
@@ -102,6 +102,7 @@ AC_CONFIG_FILES([
 
 	doc/examples/Makefile
 	doc/examples/lxc-macvlan.conf
+	doc/examples/lxc-vlan.conf
 	doc/examples/lxc-no-netns.conf
 	doc/examples/lxc-empty-netns.conf
 	doc/examples/lxc-phys.conf
Index: lxc/doc/examples/Makefile.am
===================================================================
--- lxc.orig/doc/examples/Makefile.am
+++ lxc/doc/examples/Makefile.am
@@ -5,6 +5,7 @@ pkgexamplesdir=$(docdir)/examples
 
 pkgexamples_DATA = \
 	lxc-macvlan.conf \
+	lxc-vlan.conf \
 	lxc-no-netns.conf \
 	lxc-empty-netns.conf \
 	lxc-phys.conf \
@@ -14,6 +15,7 @@ endif
 
 noinst_DATA = \
 	lxc-macvlan.conf.in \
+	lxc-vlan.conf.in \
 	lxc-empty-netns.conf.in \
 	lxc-no-netns.conf.in \
 	lxc-phys.conf.in \
Index: lxc/doc/examples/lxc-vlan.conf.in
===================================================================
--- /dev/null
+++ lxc/doc/examples/lxc-vlan.conf.in
@@ -0,0 +1,9 @@
+# Container with network virtualized using the vlan device driver
+lxc.utsname = alpha
+lxc.network.type = vlan
+lxc.network.vlan.id = 1234
+lxc.network.flags = up
+lxc.network.link = eth0
+lxc.network.hwaddr = 4a:49:43:49:79:bd
+lxc.network.ipv4 = 1.2.3.4/24
+lxc.network.ipv6 = 2003:db8:1:0:214:1234:fe0b:3596
Index: lxc/src/lxc/conf.c
===================================================================
--- lxc.orig/src/lxc/conf.c
+++ lxc/src/lxc/conf.c
@@ -75,12 +75,14 @@ struct mount_opt {
 
 static int instanciate_veth(struct lxc_netdev *);
 static int instanciate_macvlan(struct lxc_netdev *);
+static int instanciate_vlan(struct lxc_netdev *);
 static int instanciate_phys(struct lxc_netdev *);
 static int instanciate_empty(struct lxc_netdev *);
 
 static  instanciate_cb netdev_conf[MAXCONFTYPE + 1] = {
 	[VETH]    = instanciate_veth,
 	[MACVLAN] = instanciate_macvlan,
+	[VLAN]    = instanciate_vlan,
 	[PHYS]    = instanciate_phys,
 	[EMPTY]   = instanciate_empty,
 };
@@ -927,6 +929,35 @@ static int instanciate_macvlan(struct lx
 	return 0;
 }
 
+/* XXX: merge with instanciate_macvlan */
+static int instanciate_vlan(struct lxc_netdev *netdev)
+{
+	char peer[IFNAMSIZ];
+
+	if (!netdev->link) {
+		ERROR("no link specified for vlan netdev");
+		return -1;
+	}
+
+	snprintf(peer, sizeof(peer), "vlan%d",netdev->vlan_attr.vid);
+
+	if (lxc_vlan_create(netdev->link, peer, netdev->vlan_attr.vid)) {
+		ERROR("failed to create vlan interface '%s' on '%s'",
+		      peer, netdev->link);
+		return -1;
+	}
+
+	netdev->ifindex = if_nametoindex(peer);
+	if (!netdev->ifindex) {
+		ERROR("failed to retrieve the ifindex for %s", peer);
+		lxc_device_delete(peer);
+		return -1;
+	}
+
+	DEBUG("instanciated vlan '%s', ifindex is '%d'", "vlan1000", netdev->ifindex);
+	return 0;
+}
+
 static int instanciate_phys(struct lxc_netdev *netdev)
 {
 	netdev->ifindex = if_nametoindex(netdev->link);
Index: lxc/src/lxc/conf.h
===================================================================
--- lxc.orig/src/lxc/conf.h
+++ lxc/src/lxc/conf.h
@@ -33,6 +33,7 @@ enum {
 	VETH,
 	MACVLAN,
 	PHYS,
+	VLAN,
 	MAXCONFTYPE,
 };
 
@@ -69,6 +70,14 @@ struct lxc_inet6dev {
 struct lxc_route6 {
 	struct in6_addr addr;
 };
+
+struct ifla_vlan {
+	uint   flags;
+	uint   fmask;
+	ushort   vid;
+	ushort   pad;
+};
+
 /*
  * Defines a structure to configure a network device
  * @link   : lxc.network.link, name of bridge or host iface to attach if any
@@ -87,6 +96,7 @@ struct lxc_netdev {
 	char *pair;
 	char *hwaddr;
 	char *mtu;
+	struct ifla_vlan vlan_attr;
 	struct lxc_list ipv4;
 	struct lxc_list ipv6;
 };
Index: lxc/src/lxc/confile.c
===================================================================
--- lxc.orig/src/lxc/confile.c
+++ lxc/src/lxc/confile.c
@@ -33,6 +33,7 @@
 #include <net/if.h>
 
 #include "parse.h"
+#include "utils.h"
 
 #include <lxc/log.h>
 #include <lxc/conf.h>
@@ -51,6 +52,7 @@ static int config_network_link(const cha
 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_hwaddr(const char *, char *, struct lxc_conf *);
+static int config_network_vlanid(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 *);
@@ -77,6 +79,7 @@ static struct config config[] = {
 	{ "lxc.network.pair",   config_network_pair   },
 	{ "lxc.network.hwaddr", config_network_hwaddr },
 	{ "lxc.network.mtu",    config_network_mtu    },
+	{ "lxc.network.vlanid", config_network_vlanid },
 	{ "lxc.network.ipv4",   config_network_ipv4   },
 	{ "lxc.network.ipv6",   config_network_ipv6   },
 };
@@ -125,6 +128,8 @@ static int config_network_type(const cha
 		netdev->type = VETH;
 	else if (!strcmp(value, "macvlan"))
 		netdev->type = MACVLAN;
+	else if (!strcmp(value, "vlan"))
+		netdev->type = VLAN;
 	else if (!strcmp(value, "phys"))
 		netdev->type = PHYS;
 	else if (!strcmp(value, "empty"))
@@ -253,6 +258,21 @@ static int config_network_hwaddr(const c
 	return 0;
 }
 
+static int config_network_vlanid(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;
+
+	if (get_u16(&netdev->vlan_attr.vid, value, 0))
+		return -1;
+
+	return 0;
+}
+
 static int config_network_mtu(const char *key, char *value,
 			      struct lxc_conf *lxc_conf)
 {
Index: lxc/src/lxc/lxc-checkconfig.in
===================================================================
--- lxc.orig/src/lxc/lxc-checkconfig.in
+++ lxc/src/lxc/lxc-checkconfig.in
@@ -65,4 +65,5 @@ echo
 echo "--- Misc ---"
 echo -n "Veth pair device: " && is_enabled CONFIG_VETH
 echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
+echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
 echo -n "File capabilities: " && is_enabled CONFIG_SECURITY_FILE_CAPABILITIES
Index: lxc/src/lxc/network.c
===================================================================
--- lxc.orig/src/lxc/network.c
+++ lxc/src/lxc/network.c
@@ -63,6 +63,10 @@
 # define IFLA_INFO_KIND 1
 #endif
 
+#ifndef IFLA_VLAN_ID
+# define IFLA_VLAN_ID 1
+#endif
+
 #ifndef IFLA_INFO_DATA
 #  define IFLA_INFO_DATA 2
 #endif
@@ -392,6 +396,80 @@ out:
 	return err;
 }
 
+/* XXX: merge with lxc_macvlan_create */
+int lxc_vlan_create(const char *master, const char *name, ushort vlanid)
+{
+	struct nl_handler nlh;
+	struct nlmsg *nlmsg = NULL, *answer = NULL;
+	struct link_req *link_req;
+	struct rtattr *nest, *nest2;
+	int lindex, len, err = -1;
+
+	if (netlink_open(&nlh, NETLINK_ROUTE))
+		return -1;
+
+	len = strlen(master);
+	if (len == 1 || len > IFNAMSIZ)
+		goto err3;
+
+	len = strlen(name);
+	if (len == 1 || len > IFNAMSIZ)
+		goto err3;
+
+	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!nlmsg)
+		goto err3;
+
+	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!answer)
+		goto err2;
+
+	lindex = if_nametoindex(master);
+	if (!lindex)
+		goto err1;
+
+	link_req = (struct link_req *)nlmsg;
+	link_req->ifinfomsg.ifi_family = AF_UNSPEC;
+	nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	nlmsg->nlmsghdr.nlmsg_flags =
+		NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
+	nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
+
+ 	nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
+	if (!nest)
+		goto err1;
+
+	if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan"))
+		goto err1;
+
+	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);
+
+	if (nla_put_u32(nlmsg, IFLA_LINK, lindex))
+		goto err1;
+
+	if (nla_put_string(nlmsg, IFLA_IFNAME, name))
+		goto err1;
+
+	if (netlink_transaction(&nlh, nlmsg, answer))
+		goto err1;
+
+	err = 0;
+err1:
+	nlmsg_free(answer);
+err2:
+	nlmsg_free(nlmsg);
+err3:
+	netlink_close(&nlh);
+	return err;
+}
+
 int lxc_macvlan_create(const char *master, const char *name)
 {
 	struct nl_handler nlh;
Index: lxc/src/lxc/network.h
===================================================================
--- lxc.orig/src/lxc/network.h
+++ lxc/src/lxc/network.h
@@ -68,6 +68,11 @@ extern int lxc_veth_create(const char *n
  */
 extern int lxc_macvlan_create(const char *master, const char *name);
 
+/*
+ * Create a vlan network device
+ */
+extern int lxc_vlan_create(const char *master, const char *name, ushort vid);
+
 /*
  * Activate forwarding
  */



