[lxc-devel] [lxc/master] NIC: Veth bridge VLAN support

tomponline on Github lxc-bot at linuxcontainers.org
Wed Jun 3 16:58:21 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 759 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200603/77c562e0/attachment.bin>
-------------- next part --------------
From c6243b4c35f8259abf1a2f9bd547a3df2d64c05b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 11:06:49 +0100
Subject: [PATCH 01/12] confile: Adds validation for lxc.net.veth.vlan.id

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/confile.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 13ebdd059a..5d3a55b924 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -126,6 +126,7 @@ lxc_config_define(net_veth_mode);
 lxc_config_define(net_veth_pair);
 lxc_config_define(net_veth_ipv4_route);
 lxc_config_define(net_veth_ipv6_route);
+lxc_config_define(net_veth_vlan_id);
 lxc_config_define(net_vlan_id);
 lxc_config_define(no_new_privs);
 lxc_config_define(personality);
@@ -239,6 +240,7 @@ static struct lxc_config_t config_jump_table[] = {
 	{ "lxc.net.veth.pair",             set_config_net_veth_pair,               get_config_net_veth_pair,               clr_config_net_veth_pair,             },
 	{ "lxc.net.veth.ipv4.route",       set_config_net_veth_ipv4_route,         get_config_net_veth_ipv4_route,         clr_config_net_veth_ipv4_route,       },
 	{ "lxc.net.veth.ipv6.route",       set_config_net_veth_ipv6_route,         get_config_net_veth_ipv6_route,         clr_config_net_veth_ipv6_route,       },
+	{ "lxc.net.veth.vlan.id",          set_config_net_veth_vlan_id,            get_config_net_veth_vlan_id,            clr_config_net_veth_vlan_id,          },
 	{ "lxc.net.",                      set_config_net_nic,                     get_config_net_nic,                     clr_config_net_nic,                   },
 	{ "lxc.net",                       set_config_net,                         get_config_net,                         clr_config_net,                       },
 	{ "lxc.no_new_privs",	           set_config_no_new_privs,                get_config_no_new_privs,                clr_config_no_new_privs,              },
@@ -487,6 +489,25 @@ static int set_config_net_veth_pair(const char *key, const char *value,
 	return network_ifname(netdev->priv.veth_attr.pair, value, sizeof(netdev->priv.veth_attr.pair));
 }
 
+static int set_config_net_veth_vlan_id(const char *key, const char *value,
+				  struct lxc_conf *lxc_conf, void *data)
+{
+	int ret;
+	struct lxc_netdev *netdev = data;
+
+	if (lxc_config_value_empty(value))
+		return clr_config_net_veth_vlan_id(key, lxc_conf, data);
+
+	if (!netdev)
+		return -1;
+
+	ret = get_u16(&netdev->priv.veth_attr.vlan_id, value, 0);
+	if (ret < 0)
+		return -1;
+
+	return 0;
+}
+
 static int set_config_net_macvlan_mode(const char *key, const char *value,
 				       struct lxc_conf *lxc_conf, void *data)
 {
@@ -5301,6 +5322,19 @@ static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
 	return 0;
 }
 
+static int clr_config_net_veth_vlan_id(const char *key, struct lxc_conf *lxc_conf,
+				  void *data)
+{
+	struct lxc_netdev *netdev = data;
+
+	if (!netdev)
+		return -1;
+
+	netdev->priv.veth_attr.vlan_id = 0;
+
+	return 0;
+}
+
 static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
 				    void *data)
 {
@@ -5772,6 +5806,29 @@ static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
 	return fulllen;
 }
 
+static int get_config_net_veth_vlan_id(const char *key, char *retv, int inlen,
+				  struct lxc_conf *c, void *data)
+{
+	int len;
+	int fulllen = 0;
+	struct lxc_netdev *netdev = data;
+
+	if (!retv)
+		inlen = 0;
+	else
+		memset(retv, 0, inlen);
+
+	if (!netdev)
+		return -1;
+
+	if (netdev->type != LXC_NET_VETH)
+		return 0;
+
+	strprint(retv, inlen, "%d", netdev->priv.veth_attr.vlan_id);
+
+	return fulllen;
+}
+
 static int get_config_net_script_up(const char *key, char *retv, int inlen,
 				    struct lxc_conf *c, void *data)
 {
@@ -6200,6 +6257,7 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
 		strprint(retv, inlen, "veth.pair\n");
 		strprint(retv, inlen, "veth.ipv4.route\n");
 		strprint(retv, inlen, "veth.ipv6.route\n");
+		strprint(retv, inlen, "veth.vlan.id\n");
 		break;
 	case LXC_NET_MACVLAN:
 		strprint(retv, inlen, "macvlan.mode\n");

From b6793e3a4bb6b94d8946c84cf3c586bdbc486b06 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 11:07:15 +0100
Subject: [PATCH 02/12] confile/utils: Adds veth mode and vlan ID tracing to
 lxc_log_configured_netdevs

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/confile_utils.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c
index 05dadf9ec6..f88f00881e 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -257,6 +257,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
 		switch (netdev->type) {
 		case LXC_NET_VETH:
 			TRACE("type: veth");
+			TRACE("veth mode: %d", netdev->priv.veth_attr.mode);
 
 			if (netdev->priv.veth_attr.pair[0] != '\0')
 				TRACE("veth pair: %s",
@@ -269,6 +270,10 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
 			if (netdev->priv.veth_attr.ifindex > 0)
 				TRACE("host side ifindex for veth device: %d",
 				      netdev->priv.veth_attr.ifindex);
+
+			if (netdev->priv.veth_attr.vlan_id > 0)
+				TRACE("veth vlan id: %d", netdev->priv.veth_attr.vlan_id);
+
 			break;
 		case LXC_NET_MACVLAN:
 			TRACE("type: macvlan");

From 37fb4dea64b9d714bea657a6a136e44ede149e2f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 11:08:19 +0100
Subject: [PATCH 03/12] network: Adds veth vlan_id

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/network.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/lxc/network.h b/src/lxc/network.h
index 696380c900..c285babef4 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -79,6 +79,7 @@ struct ifla_veth {
 	struct lxc_list ipv4_routes;
 	struct lxc_list ipv6_routes;
 	int mode; /* bridge, router */
+	unsigned short vlan_id;
 };
 
 struct ifla_vlan {

From 499c5af0514466a5a0894b7e79404b612b4e19d6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 11:08:41 +0100
Subject: [PATCH 04/12] tests: Adds test for lxc.net.0.veth.vlan.id config key

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/tests/parse_config_file.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/tests/parse_config_file.c b/src/tests/parse_config_file.c
index 9adbdd6a67..5b69fb6749 100644
--- a/src/tests/parse_config_file.c
+++ b/src/tests/parse_config_file.c
@@ -776,6 +776,11 @@ int main(int argc, char *argv[])
 		return -1;
 	}
 
+	if (set_get_compare_clear_save_load_network(c, "lxc.net.0.veth.vlan.id", "2", tmpf, true, "veth")) {
+		lxc_error("%s\n", "lxc.net.0.veth.vlan.id");
+		return -1;
+	}
+
 	if (set_get_compare_clear_save_load(c, "lxc.net.0.script.up", "/some/up/path", tmpf, true)) {
 		lxc_error("%s\n", "lxc.net.0.script.up");
 		goto non_test_error;

From b2e5b5b82b214adccdd88ca44a5a5ff1c013c0fd Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 11:15:06 +0100
Subject: [PATCH 05/12] network: Adds vlan.id usage validation to
 instantiate_veth

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/network.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index da09141dd6..e14280aa1f 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -252,6 +252,12 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 	char *veth1, *veth2;
 	char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
 
+	/* Check that veth.vlan.id isn't being used in non bridge veth.mode. */
+	if ((netdev->priv.veth_attr.mode != VETH_MODE_BRIDGE || is_empty_string(netdev->link)) && netdev->priv.veth_attr.vlan_id > 0) {
+		SYSERROR("Cannot use veth vlan.id when not in bridge mode or no bridge link specified");
+		return -1;
+	}
+
 	if (!is_empty_string(netdev->priv.veth_attr.pair)) {
 		veth1 = netdev->priv.veth_attr.pair;
 		if (handler->conf->reboot)

From 68a342924afdd51565d12f6902c2bdc7086aa81e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 11:26:35 +0100
Subject: [PATCH 06/12] network: Adds check for bridge link interface existence
 in instantiate_veth

To avoid misleading errors about openvswitch when non-existent bridge link interface specified.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/network.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index e14280aa1f..d2f93f31a5 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -330,11 +330,15 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 	}
 
 	if (!is_empty_string(netdev->link) && netdev->priv.veth_attr.mode == VETH_MODE_BRIDGE) {
+		if (!lxc_nic_exists(netdev->link)) {
+			SYSERROR("Failed to attach \"%s\" to bridge \"%s\", bridge interface doesn't exist", veth1, netdev->link);
+			goto out_delete;
+		}
+
 		err = lxc_bridge_attach(netdev->link, veth1);
 		if (err) {
 			errno = -err;
-			SYSERROR("Failed to attach \"%s\" to bridge \"%s\"",
-			         veth1, netdev->link);
+			SYSERROR("Failed to attach \"%s\" to bridge \"%s\"", veth1, netdev->link);
 			goto out_delete;
 		}
 		INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);

From 7a0e612f38f7f0b2e87e44076b743a9335d7acdd Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 17:44:13 +0100
Subject: [PATCH 07/12] confile: Adds validation for
 lxc.net.veth.vlan.tagged.id

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/confile.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 5d3a55b924..3bd21c172a 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -127,6 +127,7 @@ lxc_config_define(net_veth_pair);
 lxc_config_define(net_veth_ipv4_route);
 lxc_config_define(net_veth_ipv6_route);
 lxc_config_define(net_veth_vlan_id);
+lxc_config_define(net_veth_vlan_tagged_id);
 lxc_config_define(net_vlan_id);
 lxc_config_define(no_new_privs);
 lxc_config_define(personality);
@@ -241,6 +242,7 @@ static struct lxc_config_t config_jump_table[] = {
 	{ "lxc.net.veth.ipv4.route",       set_config_net_veth_ipv4_route,         get_config_net_veth_ipv4_route,         clr_config_net_veth_ipv4_route,       },
 	{ "lxc.net.veth.ipv6.route",       set_config_net_veth_ipv6_route,         get_config_net_veth_ipv6_route,         clr_config_net_veth_ipv6_route,       },
 	{ "lxc.net.veth.vlan.id",          set_config_net_veth_vlan_id,            get_config_net_veth_vlan_id,            clr_config_net_veth_vlan_id,          },
+	{ "lxc.net.veth.vlan.tagged.id",   set_config_net_veth_vlan_tagged_id,     get_config_net_veth_vlan_tagged_id,     clr_config_net_veth_vlan_tagged_id,   },
 	{ "lxc.net.",                      set_config_net_nic,                     get_config_net_nic,                     clr_config_net_nic,                   },
 	{ "lxc.net",                       set_config_net,                         get_config_net,                         clr_config_net,                       },
 	{ "lxc.no_new_privs",	           set_config_no_new_privs,                get_config_no_new_privs,                clr_config_no_new_privs,              },
@@ -308,6 +310,7 @@ static int set_config_net_type(const char *key, const char *value,
 		netdev->type = LXC_NET_VETH;
 		lxc_list_init(&netdev->priv.veth_attr.ipv4_routes);
 		lxc_list_init(&netdev->priv.veth_attr.ipv6_routes);
+		lxc_list_init(&netdev->priv.veth_attr.vlan_tagged_ids);
 		if (!lxc_veth_flag_to_mode(netdev->priv.veth_attr.mode))
 			lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge");
 	} else if (strcmp(value, "macvlan") == 0) {
@@ -508,6 +511,43 @@ static int set_config_net_veth_vlan_id(const char *key, const char *value,
 	return 0;
 }
 
+static int set_config_net_veth_vlan_tagged_id(const char *key, const char *value,
+				       struct lxc_conf *lxc_conf, void *data)
+{
+	__do_free unsigned short *vlan_id = NULL;
+	__do_free struct lxc_list *list = NULL;
+	int ret;
+	char *netmask, *slash;
+	struct lxc_netdev *netdev = data;
+
+	if (lxc_config_value_empty(value))
+		return clr_config_net_veth_vlan_tagged_id(key, lxc_conf, data);
+
+	if (!netdev)
+		return ret_set_errno(-1, EINVAL);
+
+	vlan_id = malloc(sizeof(*vlan_id));
+	if (!vlan_id)
+		return -1;
+
+	ret = get_u16(vlan_id, value, 0);
+	if (ret < 0)
+		return -1;
+
+	list = malloc(sizeof(*list));
+	if (!list)
+		return -1;
+
+	lxc_list_init(list);
+	list->elem = vlan_id;
+
+	lxc_list_add_tail(&netdev->priv.veth_attr.vlan_tagged_ids, list);
+	move_ptr(vlan_id);
+	move_ptr(list);
+
+	return 0;
+}
+
 static int set_config_net_macvlan_mode(const char *key, const char *value,
 				       struct lxc_conf *lxc_conf, void *data)
 {
@@ -5335,6 +5375,25 @@ static int clr_config_net_veth_vlan_id(const char *key, struct lxc_conf *lxc_con
 	return 0;
 }
 
+static int clr_config_net_veth_vlan_tagged_id(const char *key,
+				       struct lxc_conf *lxc_conf, void *data)
+{
+	struct lxc_netdev *netdev = data;
+	struct lxc_list *cur, *next;
+
+	if (!netdev)
+		return -1;
+
+	lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
+		lxc_list_del(cur);
+		free(cur->elem);
+		free(cur);
+	}
+
+	return 0;
+}
+
+
 static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
 				    void *data)
 {
@@ -5829,6 +5888,37 @@ static int get_config_net_veth_vlan_id(const char *key, char *retv, int inlen,
 	return fulllen;
 }
 
+static int get_config_net_veth_vlan_tagged_id(const char *key, char *retv, int inlen,
+				       struct lxc_conf *c, void *data)
+{
+	int len;
+	size_t listlen;
+	struct lxc_list *it;
+	int fulllen = 0;
+	struct lxc_netdev *netdev = data;
+
+	if (!retv)
+		inlen = 0;
+	else
+		memset(retv, 0, inlen);
+
+	if (!netdev)
+		return ret_set_errno(-1, EINVAL);
+
+	if (netdev->type != LXC_NET_VETH)
+		return 0;
+
+	listlen = lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids);
+
+	lxc_list_for_each(it, &netdev->priv.veth_attr.vlan_tagged_ids) {
+		unsigned short *i = it->elem;
+		strprint(retv, inlen, "%u%s", *i,
+			 (listlen-- > 1) ? "\n" : "");
+	}
+
+	return fulllen;
+}
+
 static int get_config_net_script_up(const char *key, char *retv, int inlen,
 				    struct lxc_conf *c, void *data)
 {

From 02e509d0cd4d0d73987b5e792fe3d002d85ec0c2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 17:44:34 +0100
Subject: [PATCH 08/12] confile/utils: Adds freeing of
 priv.veth_attr.vlan_tagged_ids

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/confile_utils.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c
index f88f00881e..e7f6ee4f18 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -444,6 +444,12 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
 			free(cur->elem);
 			free(cur);
 		}
+
+		lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
+			lxc_list_del(cur);
+			free(cur->elem);
+			free(cur);
+		}
 	}
 
 	free(netdev);

From 93e74a7477e873bd0804a5eff9d3e8278d56dbcf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 17:44:55 +0100
Subject: [PATCH 09/12] macro: Adds bridge VLAN constants

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/macro.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index 3a5bb07464..9a6db1873d 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -380,6 +380,26 @@ extern int __build_bug_on_failed;
 #define IPVLAN_ISOLATION_VEPA 2
 #endif
 
+#ifndef BRIDGE_FLAGS_MASTER
+#define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_PVID
+#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_UNTAGGED
+#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */
+#endif
+
+#ifndef IFLA_BRIDGE_FLAGS
+#define IFLA_BRIDGE_FLAGS 0
+#endif
+
+#ifndef IFLA_BRIDGE_VLAN_INFO
+#define IFLA_BRIDGE_VLAN_INFO 2
+#endif
+
 /* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
 enum {
 	__LXC_NETNSA_NONE,

From a3e5eead7209caeacd5e581b2075c219c1682a6f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 17:45:30 +0100
Subject: [PATCH 10/12] network: Adds bridge vlan management functions

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/network.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index d2f93f31a5..5a5944964d 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -245,6 +245,90 @@ static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
 	return lxc_read_file_expect(path, buf, 1, "1");
 }
 
+struct bridge_vlan_info {
+	__u16 flags;
+	__u16 vid;
+};
+
+static int lxc_bridge_vlan(unsigned int ifindex, unsigned short operation, unsigned short vlan_id, bool tagged)
+{
+	call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
+	struct nl_handler nlh;
+	call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
+	int err, len;
+	struct ifinfomsg *ifi;
+	struct rtattr *nest, *nest2;
+	unsigned short bridge_flags;
+	struct bridge_vlan_info vlan_info;
+
+	err = netlink_open(nlh_ptr, NETLINK_ROUTE);
+	if (err)
+		return ret_errno(-err);
+
+	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!nlmsg)
+		return ret_errno(ENOMEM);
+
+	answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
+	if (!answer)
+		return ret_errno(ENOMEM);
+
+	nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+	nlmsg->nlmsghdr->nlmsg_type = operation;
+
+	ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
+	if (!ifi)
+		return ret_errno(ENOMEM);
+	ifi->ifi_family = AF_BRIDGE;
+	ifi->ifi_index = ifindex;
+
+	nest = nla_begin_nested(nlmsg, IFLA_AF_SPEC);
+	if (!nest)
+		return ret_errno(ENOMEM);
+
+	bridge_flags |= BRIDGE_FLAGS_MASTER;
+	if (nla_put_u16(nlmsg, IFLA_BRIDGE_FLAGS, bridge_flags))
+		return ret_errno(ENOMEM);
+
+	vlan_info.vid = vlan_id;
+	vlan_info.flags = 0;
+	if (!tagged)
+		vlan_info.flags = BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED;
+
+	if (nla_put_buffer(nlmsg, IFLA_BRIDGE_VLAN_INFO, &vlan_info, sizeof(struct bridge_vlan_info)))
+		return ret_errno(ENOMEM);
+
+	nla_end_nested(nlmsg, nest);
+
+	return netlink_transaction(nlh_ptr, nlmsg, answer);
+}
+
+static int lxc_bridge_vlan_add(unsigned int ifindex, unsigned short vlan_id, bool tagged)
+{
+	return lxc_bridge_vlan(ifindex, RTM_SETLINK, vlan_id, tagged);
+}
+
+static int lxc_bridge_vlan_del(unsigned int ifindex, unsigned short vlan_id)
+{
+	return lxc_bridge_vlan(ifindex, RTM_DELLINK, vlan_id, false);
+}
+
+static int lxc_bridge_vlan_add_tagged(unsigned int ifindex, struct lxc_list *vlan_ids)
+{
+	struct lxc_list *iterator;
+	int err;
+
+	lxc_list_for_each(iterator, vlan_ids) {
+		unsigned short *vlan_id = iterator->elem;
+
+		err = lxc_bridge_vlan_add(ifindex, *vlan_id, true);
+		if (err)
+			return log_error_errno(-1, -err, "Failed to add tagged vlan \"%u\" to ifindex \"%d\"", *vlan_id, ifindex);
+	}
+
+	return 0;
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
 {
 	int err;

From 88be094c0174b048d4e09aa4b92d51528a7f005c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 17:45:47 +0100
Subject: [PATCH 11/12] network: Updates instantiate_veth to set bridge vlan
 settings

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/network.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index 5a5944964d..2ac4f5fdc0 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -426,6 +426,27 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 			goto out_delete;
 		}
 		INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
+
+		int veth1index = if_nametoindex(veth1);
+		if (!index)
+			return ret_errno(EINVAL);
+
+		/* Configure VLAN settings on bridge port if specified. */
+		if (netdev->priv.veth_attr.vlan_id > 0) {
+			err = lxc_bridge_vlan_add(veth1index, netdev->priv.veth_attr.vlan_id, false);
+			if (err != 0) {
+				errno = -err;
+				SYSERROR("Failed to add untagged vlan \"%u\" on \"%s\"", netdev->priv.veth_attr.vlan_id, veth1);
+				goto out_delete;
+			}
+		}
+
+		err = lxc_bridge_vlan_add_tagged(veth1index, &netdev->priv.veth_attr.vlan_tagged_ids);
+		if (err != 0) {
+			errno = -err;
+			SYSERROR("Failed to add tagged vlans on \"%s\"", veth1);
+			goto out_delete;
+		}
 	}
 
 	err = lxc_netdev_up(veth1);

From 894c3cf4cce6b1877d78399ac2c86dc571897553 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Wed, 3 Jun 2020 17:46:09 +0100
Subject: [PATCH 12/12] network: Adds vlan_tagged_ids

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 src/lxc/network.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/lxc/network.h b/src/lxc/network.h
index c285babef4..953c015123 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -80,6 +80,7 @@ struct ifla_veth {
 	struct lxc_list ipv6_routes;
 	int mode; /* bridge, router */
 	unsigned short vlan_id;
+	struct lxc_list vlan_tagged_ids;
 };
 
 struct ifla_vlan {


More information about the lxc-devel mailing list