The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/3439

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Includes https://github.com/lxc/lxc/pull/3435

Adds openvswitch VLAN support.
From 372adece8bf59c24696462a211b53ace3c93c0e8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 8 Jun 2020 13:24:08 +0100
Subject: [PATCH 01/20] macro: Adds UINT_TO_PTR and PTR_TO_USHORT helpers

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

diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index 3a5bb07464..7b2ad79edd 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -433,6 +433,9 @@ enum {
 
 #define PTR_TO_UINT64(p) ((uint64_t)((intptr_t)(p)))
 
+#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+#define PTR_TO_USHORT(p) ((unsigned short)((uintptr_t)(p)))
+
 #define LXC_INVALID_UID ((uid_t)-1)
 #define LXC_INVALID_GID ((gid_t)-1)
 

From 26da53c3acc51d5a93476c47836508e1661c6505 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 11:26:35 +0100
Subject: [PATCH 02/20] 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.parr...@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 da09141dd6..15c362fb69 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -324,11 +324,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 d80ff1fac7c74a8e0b9f7910ad9f83da81b29cfa Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 14:16:09 +0100
Subject: [PATCH 03/20] api/extensions: Adds network_bridge_vlan API extension

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

diff --git a/src/lxc/api_extensions.h b/src/lxc/api_extensions.h
index b69467f262..2bbdc5e43a 100644
--- a/src/lxc/api_extensions.h
+++ b/src/lxc/api_extensions.h
@@ -40,6 +40,7 @@ static char *api_extensions[] = {
        "cgroup2",
        "pidfd",
        "cgroup_advanced_isolation",
+       "network_bridge_vlan",
 };
 
 static size_t nr_api_extensions = sizeof(api_extensions) / 
sizeof(*api_extensions);

From 59315a06819e42f0e7f29c294ce0625ed4a616c6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 17:44:55 +0100
Subject: [PATCH 04/20] macro: Adds bridge VLAN constants

Signed-off-by: Thomas Parrott <thomas.parr...@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 7b2ad79edd..50cbb34341 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 53a9ba7ff4e9b968b7d2e1f88413946a553cf4eb Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 15:27:20 +0100
Subject: [PATCH 05/20] macro: Adds constant for BRIDGE_VLAN_NONE mode

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

diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index 50cbb34341..7ff0b77acd 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -380,6 +380,10 @@ extern int __build_bug_on_failed;
 #define IPVLAN_ISOLATION_VEPA 2
 #endif
 
+#ifndef BRIDGE_VLAN_NONE
+#define BRIDGE_VLAN_NONE -1 /* Bridge VLAN option set to "none". */
+#endif
+
 #ifndef BRIDGE_FLAGS_MASTER
 #define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */
 #endif

From 2abd5206d769e4867794bb200d6b43a8f4d0a702 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 17:02:03 +0100
Subject: [PATCH 06/20] macro: Adds BRIDGE_VLAN_ID_MAX constant

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

diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index 7ff0b77acd..a3cb538d14 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -384,6 +384,10 @@ extern int __build_bug_on_failed;
 #define BRIDGE_VLAN_NONE -1 /* Bridge VLAN option set to "none". */
 #endif
 
+#ifndef BRIDGE_VLAN_ID_MAX
+#define BRIDGE_VLAN_ID_MAX 4094 /* Bridge VLAN MAX VLAN ID. */
+#endif
+
 #ifndef BRIDGE_FLAGS_MASTER
 #define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */
 #endif

From c96a27f7393fe12f50c8e1c71cc59242e85b085f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 11:08:19 +0100
Subject: [PATCH 07/20] network: Adds veth vlan_id, vlan_id_set and
 vlan_tagged_ids

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 src/lxc/network.h | 3 +++
 1 file changed, 3 insertions(+)

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

From e0ef0c6c58518803feabc98982d3b8594e1111be Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 11:06:49 +0100
Subject: [PATCH 08/20] confile: Adds validation for lxc.net.veth.vlan.id

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

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 13ebdd059a..69cb12e97f 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -32,6 +32,7 @@
 #include "../include/netns_ifaddrs.h"
 #include "log.h"
 #include "lxcseccomp.h"
+#include "macro.h"
 #include "memory_utils.h"
 #include "network.h"
 #include "parse.h"
@@ -126,6 +127,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 +241,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 +490,36 @@ 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;
+
+       if (strcmp(value, "none") == 0) {
+               netdev->priv.veth_attr.vlan_id = BRIDGE_VLAN_NONE;
+       } else {
+               unsigned short vlan_id;
+               ret = get_u16(&vlan_id, value, 0);
+               if (ret < 0)
+                       return -1;
+
+               if (vlan_id > BRIDGE_VLAN_ID_MAX)
+                       ret_errno(EINVAL);
+
+               netdev->priv.veth_attr.vlan_id = vlan_id;
+       }
+
+       netdev->priv.veth_attr.vlan_id_set = true;
+       return 0;
+}
+
 static int set_config_net_macvlan_mode(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf, void *data)
 {
@@ -5301,6 +5334,20 @@ 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;
+       netdev->priv.veth_attr.vlan_id_set = false;
+
+       return 0;
+}
+
 static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
                                    void *data)
 {
@@ -5772,6 +5819,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 +6270,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 dbc69fd06a85bd955d1d2590acad8d602e8a62d8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 17:44:13 +0100
Subject: [PATCH 09/20] confile: Adds validation for
 lxc.net.veth.vlan.tagged.id

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

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 69cb12e97f..f4cb780632 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -128,6 +128,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);
@@ -242,6 +243,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,             
 },
@@ -309,6 +311,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) {
@@ -520,6 +523,39 @@ 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 struct lxc_list *list = NULL;
+       int ret;
+       unsigned short vlan_id;
+       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);
+
+       ret = get_u16(&vlan_id, value, 0);
+       if (ret < 0)
+               return -1;
+
+       if (vlan_id > BRIDGE_VLAN_ID_MAX)
+               return -1;
+
+       list = malloc(sizeof(*list));
+       if (!list)
+               return -1;
+
+       lxc_list_init(list);
+       list->elem = UINT_TO_PTR(vlan_id);
+
+       lxc_list_add_tail(&netdev->priv.veth_attr.vlan_tagged_ids, 
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)
 {
@@ -5348,6 +5384,24 @@ 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);
+       }
+
+       return 0;
+}
+
+
 static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
                                    void *data)
 {
@@ -5842,6 +5896,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 (!netdev)
+               ret_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH)
+               return 0;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       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 = PTR_TO_USHORT(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 014a4b4783f4c268e24be031e3c5bbee8a640aa9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 11:07:15 +0100
Subject: [PATCH 10/20] confile/utils: Adds veth mode and vlan ID tracing to
 lxc_log_configured_netdevs

Signed-off-by: Thomas Parrott <thomas.parr...@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..f8dcf2ae56 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_set)
+                               TRACE("veth vlan id: %d", 
netdev->priv.veth_attr.vlan_id);
+
                        break;
                case LXC_NET_MACVLAN:
                        TRACE("type: macvlan");

From 0a638a51a1f4d1ed99a9ec864b4f8d62fbc95d75 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 15:30:34 +0100
Subject: [PATCH 11/20] confile/utils: Adds veth vlan tagged ID tracing to
 lxc_log_configured_netdevs

Signed-off-by: Thomas Parrott <thomas.parr...@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 f8dcf2ae56..89fc555bc0 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -274,6 +274,11 @@ void lxc_log_configured_netdevs(const struct lxc_conf 
*conf)
                        if (netdev->priv.veth_attr.vlan_id_set)
                                TRACE("veth vlan id: %d", 
netdev->priv.veth_attr.vlan_id);
 
+                       lxc_list_for_each_safe(cur, 
&netdev->priv.veth_attr.vlan_tagged_ids, next) {
+                               unsigned short vlan_tagged_id = 
PTR_TO_USHORT(cur->elem);
+                               TRACE("veth vlan tagged id: %u", 
vlan_tagged_id);
+                       }
+
                        break;
                case LXC_NET_MACVLAN:
                        TRACE("type: macvlan");

From 120606e9080fb512662e59aba961e1d7833cd708 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 17:44:34 +0100
Subject: [PATCH 12/20] confile/utils: Adds freeing of
 priv.veth_attr.vlan_tagged_ids

Signed-off-by: Thomas Parrott <thomas.parr...@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 89fc555bc0..06e9f6b193 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -449,6 +449,11 @@ 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);
+               }
        }
 
        free(netdev);

From 5a5faa55141e06723fbe79540d38b160a97cb520 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 11:08:41 +0100
Subject: [PATCH 13/20] tests: Adds test for lxc.net.0.veth.vlan.id config key

Signed-off-by: Thomas Parrott <thomas.parr...@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 49fcc6369d4b01d132919c54e0a0f751184761fe Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 15:27:48 +0100
Subject: [PATCH 14/20] tests: Adds test for bridge vlan "none" value

Signed-off-by: Thomas Parrott <thomas.parr...@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 5b69fb6749..51dc1c0a59 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", "none", tmpf, false, "veth")) {
+               lxc_error("%s\n", "lxc.net.0.veth.vlan.id");
+               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;

From 62ee8930fc033a674cce27aee47d3ec6e8727e70 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 14:14:43 +0100
Subject: [PATCH 15/20] tests: Adds test for lxc.net.0.veth.vlan.tagged.id
 config key

Signed-off-by: Thomas Parrott <thomas.parr...@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 51dc1c0a59..6d0e88805d 100644
--- a/src/tests/parse_config_file.c
+++ b/src/tests/parse_config_file.c
@@ -786,6 +786,11 @@ int main(int argc, char *argv[])
                return -1;
        }
 
+       if (set_get_compare_clear_save_load_network(c, 
"lxc.net.0.veth.vlan.tagged.id", "2", tmpf, true, "veth")) {
+               lxc_error("%s\n", "lxc.net.0.veth.vlan.tagged.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 acbd9ecd8a2422d30e72e775c0f3ff0af263e7ac Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 17:45:30 +0100
Subject: [PATCH 16/20] network: Adds bridge vlan management functions

Signed-off-by: Thomas Parrott <thomas.parr...@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 15c362fb69..888f1829c0 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;
+       struct ifinfomsg *ifi;
+       struct rtattr *nest;
+       unsigned short bridge_flags = 0;
+       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 715a4793d29558b35fd76093b03b4aa25fc7478c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Wed, 3 Jun 2020 17:45:47 +0100
Subject: [PATCH 17/20] network: Updates instantiate_veth to set bridge vlan
 settings

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 src/lxc/network.c | 111 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 108 insertions(+), 3 deletions(-)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index 888f1829c0..68b0265c5b 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -319,16 +319,109 @@ static int lxc_bridge_vlan_add_tagged(unsigned int 
ifindex, struct lxc_list *vla
        int err;
 
        lxc_list_for_each(iterator, vlan_ids) {
-               unsigned short *vlan_id = iterator->elem;
+               unsigned short vlan_id = PTR_TO_USHORT(iterator->elem);
 
-               err = lxc_bridge_vlan_add(ifindex, *vlan_id, true);
+               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 log_error_errno(-1, -err, "Failed to add tagged 
vlan \"%u\" to ifindex \"%d\"", vlan_id, ifindex);
        }
 
        return 0;
 }
 
+static int validate_veth(struct lxc_netdev *netdev)
+{
+       if (netdev->priv.veth_attr.mode != VETH_MODE_BRIDGE || 
is_empty_string(netdev->link)) {
+               /* Check that veth.vlan.id isn't being used in non bridge 
veth.mode. */
+               if (netdev->priv.veth_attr.vlan_id_set)
+                       return log_error_errno(-1, EINVAL, "Cannot use veth 
vlan.id when not in bridge mode or no bridge link specified");
+
+               /* Check that veth.vlan.tagged.id isn't being used in non 
bridge veth.mode. */
+               if (lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids) > 0)
+                       return log_error_errno(-1, EINVAL, "Cannot use veth 
vlan.id when not in bridge mode or no bridge link specified");
+       }
+
+       if (netdev->priv.veth_attr.vlan_id_set) {
+               struct lxc_list *it;
+               lxc_list_for_each(it, &netdev->priv.veth_attr.vlan_tagged_ids) {
+                       unsigned short i = PTR_TO_USHORT(it->elem);
+                       if (i == netdev->priv.veth_attr.vlan_id)
+                               return log_error_errno(-1, EINVAL, "Cannot use 
same veth vlan.id \"%u\" in vlan.tagged.id", netdev->priv.veth_attr.vlan_id);
+               }
+       }
+
+       return 0;
+}
+
+static int setup_veth_native_bridge_vlan(char *veth1, struct lxc_netdev 
*netdev)
+{
+       /* Skip setup if no VLAN options are specified. */
+       if (!netdev->priv.veth_attr.vlan_id_set && 
lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids) <= 0)
+               return 0;
+
+       int err, rc, veth1index;
+       char path[PATH_MAX];
+       char buf[5]; // Sufficient size to fit max VLAN ID (4094) and null char.
+
+       /* Check vlan filtering is enabled on parent bridge. */
+       rc = snprintf(path, sizeof(path), 
"/sys/class/net/%s/bridge/vlan_filtering", netdev->link);
+       if (rc < 0 || (size_t)rc >= sizeof(path))
+               return -1;
+
+       rc = lxc_read_from_file(path, buf, sizeof(buf));
+       if (rc < 0)
+               return log_error_errno(rc, errno, "Failed reading from \"%s\"", 
path);
+
+       buf[rc - 1] = '\0';
+
+       if (strcmp(buf, "1") != 0)
+               return log_error_errno(-1, EPERM, "vlan_filtering is not 
enabled on \"%s\"", netdev->link);
+
+       /* Get veth1 ifindex for use with netlink. */
+       veth1index = if_nametoindex(veth1);
+       if (!veth1index)
+               return log_error_errno(-1, errno, "Failed getting ifindex of 
\"%s\"", netdev->link);
+
+       /* Configure untagged VLAN settings on bridge port if specified. */
+       if (netdev->priv.veth_attr.vlan_id_set) {
+               unsigned short default_pvid;
+
+               /* Get the bridge's default VLAN PVID. */
+               rc = snprintf(path, sizeof(path), 
"/sys/class/net/%s/bridge/default_pvid", netdev->link);
+               if (rc < 0 || (size_t)rc >= sizeof(path))
+                       return -1;
+
+               rc = lxc_read_from_file(path, buf, sizeof(buf));
+               if (rc < 0)
+                       return log_error_errno(rc, errno, "Failed reading from 
\"%s\"", path);
+
+               buf[rc - 1] = '\0';
+               err = get_u16(&default_pvid, buf, 0);
+               if (err != 0)
+                       return log_error_errno(-1, EINVAL, "Failed parsing 
default_pvid of \"%s\"", netdev->link);
+
+               /* If the default PVID on the port is not the specified 
untagged VLAN, then delete it. */
+               if (default_pvid != netdev->priv.veth_attr.vlan_id) {
+                       err = lxc_bridge_vlan_del(veth1index, default_pvid);
+                       if (err != 0)
+                               return log_error_errno(err, errno, "Failed to 
delete default untagged vlan \"%u\" on \"%s\"", default_pvid, veth1);
+               }
+
+               if (netdev->priv.veth_attr.vlan_id > BRIDGE_VLAN_NONE) {
+                       err = lxc_bridge_vlan_add(veth1index, 
netdev->priv.veth_attr.vlan_id, false);
+                       if (err != 0)
+                               return log_error_errno(err, errno, "Failed to 
add untagged vlan \"%u\" on \"%s\"", netdev->priv.veth_attr.vlan_id, veth1);
+               }
+       }
+
+       /* Configure tagged VLAN settings on bridge port if specified. */
+       err = lxc_bridge_vlan_add_tagged(veth1index, 
&netdev->priv.veth_attr.vlan_tagged_ids);
+       if (err != 0)
+               return log_error_errno(err, errno, "Failed to add tagged vlans 
on \"%s\"", veth1);
+
+       return 0;
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev 
*netdev)
 {
        int err;
@@ -336,6 +429,10 @@ static int instantiate_veth(struct lxc_handler *handler, 
struct lxc_netdev *netd
        char *veth1, *veth2;
        char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
 
+       err = validate_veth(netdev);
+       if (err != 0)
+               return err;
+
        if (!is_empty_string(netdev->priv.veth_attr.pair)) {
                veth1 = netdev->priv.veth_attr.pair;
                if (handler->conf->reboot)
@@ -420,6 +517,14 @@ static int instantiate_veth(struct lxc_handler *handler, 
struct lxc_netdev *netd
                        goto out_delete;
                }
                INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
+
+               if (!is_ovs_bridge(netdev->link)) {
+                       err = setup_veth_native_bridge_vlan(veth1, netdev);
+                       if (err != 0) {
+                               SYSERROR("Failed to setup native bridge vlan on 
\"%s\"", veth1);
+                               goto out_delete;
+                       }
+               }
        }
 
        err = lxc_netdev_up(veth1);

From 2490e1f8711dbffd904a66d0c57f5de52f8c7cc9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 4 Jun 2020 15:59:58 +0100
Subject: [PATCH 18/20] doc: Adds documentation for veth vlan bridge options

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 doc/lxc.container.conf.sgml.in | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 97f88995bb..7b0099d3af 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -474,6 +474,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
MA 02110-1301 USA
               <option>lxc.net.[i].veth.ipv6.route</option> options.
               Several lines specify several routes.
               The route is in format x.y.z.t/m, eg. 192.168.1.0/24.
+
+              In <option>bridge</option> mode untagged VLAN membership can be 
set with the
+              <option>lxc.net.[i].veth.vlan.id</option> option. It accepts a 
special value of 'none' indicating
+              that the container port should be removed from the bridge's 
default untagged VLAN.
+              The <option>lxc.net.[i].veth.vlan.tagged.id</option> option can 
be specified multiple times to set
+              the container's bridge port membership to one or more tagged 
VLANs.
             </para>
 
             <para>

From b75d38f02b0b5b42a1a96e1ceabec9318fb9b9fa Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 8 Jun 2020 11:34:27 +0100
Subject: [PATCH 19/20] network: Adds OVS VLAN setup functions

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

diff --git a/src/lxc/network.c b/src/lxc/network.c
index 68b0265c5b..a40c9a5b70 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -422,6 +422,104 @@ static int setup_veth_native_bridge_vlan(char *veth1, 
struct lxc_netdev *netdev)
        return 0;
 }
 
+struct ovs_veth_vlan_args {
+       const char *nic;
+       const char *vlan_mode;  // Port VLAN mode.
+       short vlan_id;          // PVID VLAN ID.
+       const char *trunks;     // Comma delimited list of tagged VLAN IDs.
+};
+
+
+static int lxc_ovs_setup_bridge_vlan_exec(void *data)
+{
+       struct ovs_veth_vlan_args *args = data;
+       const char *vlan_mode = "", *tag = "", *trunks = "";
+
+       vlan_mode = must_concat(NULL, "vlan_mode=", args->vlan_mode, (char *)0);
+
+       if (args->vlan_id >= 0) {
+               char buf[5];
+               int rc = snprintf(buf, sizeof(buf), "%u", args->vlan_id);
+               if (rc < 0 || (size_t)rc >= sizeof(buf))
+                       return log_error_errno(-1, EINVAL, "Failed to parse ovs 
bridge vlan \"%u\"", args->vlan_id);
+
+               tag = must_concat(NULL, "tag=", buf, (char *)0);
+       }
+
+
+       if (strcmp(args->trunks, "") != 0) {
+               trunks = must_concat(NULL, "trunks=", args->trunks, (char *)0);
+       }
+
+       /* Detect the combination of vlan_id and trunks specified and convert 
to ovs-vsctl command. */
+       if (strcmp(tag, "") != 0 && strcmp(trunks, "") != 0)
+               execlp("ovs-vsctl", "ovs-vsctl", "set", "port", args->nic, 
vlan_mode, tag, trunks, (char *)NULL);
+       else if (strcmp(tag, "") != 0)
+               execlp("ovs-vsctl", "ovs-vsctl", "set", "port", args->nic, 
vlan_mode, tag, (char *)NULL);
+       else if (strcmp(trunks, "") != 0)
+               execlp("ovs-vsctl", "ovs-vsctl", "set", "port", args->nic, 
vlan_mode, trunks, (char *)NULL);
+
+       return -1;
+}
+
+static int setup_veth_ovs_bridge_vlan(char *veth1, struct lxc_netdev *netdev)
+{
+       int taggedLength = 
lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids);
+       struct ovs_veth_vlan_args args;
+       args.nic = veth1;
+       args.vlan_mode = "";
+       args.vlan_id = -1;
+       args.trunks = "";
+
+       /* Skip setup if no VLAN options are specified. */
+       if (!netdev->priv.veth_attr.vlan_id_set && taggedLength <= 0)
+               return 0;
+
+       /* Configure untagged VLAN settings on bridge port if specified. */
+       if (netdev->priv.veth_attr.vlan_id_set) {
+               if (netdev->priv.veth_attr.vlan_id == BRIDGE_VLAN_NONE && 
taggedLength <= 0)
+                       return log_error_errno(-1, EINVAL, "Cannot use 
vlan.id=none with openvswitch bridges when not using vlan.tagged.id");
+
+               // Configure the untagged 'native' membership settings of the 
port if VLAN ID specified.
+               // Also set the vlan_mode=access, which will drop any tagged 
frames.
+               // Order is important here, as vlan_mode is set to "access", 
assuming that vlan.tagged.id is not
+               // used. If vlan.tagged.id is specified, then we expect it to 
also change the vlan_mode as needed.
+               if (netdev->priv.veth_attr.vlan_id > BRIDGE_VLAN_NONE) {
+                       args.vlan_mode = "access";
+                       args.vlan_id = netdev->priv.veth_attr.vlan_id;
+               }
+       }
+
+       if (taggedLength > 0) {
+               args.vlan_mode = "trunk"; // Default to only allowing tagged 
frames (drop untagged frames).
+
+               if (netdev->priv.veth_attr.vlan_id > BRIDGE_VLAN_NONE) {
+                       // If untagged vlan mode isn't "none" then allow 
untagged frames for port's 'native' VLAN.
+                       args.vlan_mode  = "native-untagged";
+               }
+
+               struct lxc_list *iterator;
+               lxc_list_for_each(iterator, 
&netdev->priv.veth_attr.vlan_tagged_ids) {
+                       char buf[5]; // Sufficient size to fit max VLAN ID 
(4094) null char.
+                       unsigned short vlan_id = PTR_TO_USHORT(iterator->elem);
+                       int rc = snprintf(buf, sizeof(buf), "%u", vlan_id);
+                       if (rc < 0 || (size_t)rc >= sizeof(buf))
+                               return log_error_errno(-1, EINVAL, "Failed to 
parse tagged vlan \"%u\" for interface \"%s\"", vlan_id, veth1);
+
+                       args.trunks = must_concat(NULL, args.trunks, buf, ",", 
(char *)0);
+               }
+       }
+
+       if (strcmp(args.vlan_mode, "") != 0) {
+               char cmd_output[PATH_MAX];
+               int ret = run_command(cmd_output, sizeof(cmd_output), 
lxc_ovs_setup_bridge_vlan_exec, (void *)&args);
+               if (ret < 0)
+                       return log_error_errno(-1, ret, "Failed to setup 
openvswitch vlan on port \"%s\": %s", args.nic, cmd_output);
+       }
+
+       return 0;
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev 
*netdev)
 {
        int err;

From 7a3e4a6d6b99ddb91e2cc6b35d9279042b8c78c0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 8 Jun 2020 11:34:43 +0100
Subject: [PATCH 20/20] network: Updates instantiate_veth to support OVS VLAN
 setup

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 src/lxc/network.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index a40c9a5b70..2218928ff1 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -616,7 +616,14 @@ static int instantiate_veth(struct lxc_handler *handler, 
struct lxc_netdev *netd
                }
                INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
 
-               if (!is_ovs_bridge(netdev->link)) {
+               if (is_ovs_bridge(netdev->link)) {
+                       err = setup_veth_ovs_bridge_vlan(veth1, netdev);
+                       if (err != 0) {
+                               SYSERROR("Failed to setup openvswitch bridge 
vlan on \"%s\"", veth1);
+                               lxc_ovs_delete_port(netdev->link, veth1);
+                               goto out_delete;
+                       }
+               } else {
                        err = setup_veth_native_bridge_vlan(veth1, netdev);
                        if (err != 0) {
                                SYSERROR("Failed to setup native bridge vlan on 
\"%s\"", veth1);
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to