Unverified Commit 677c9967 by Christian Brauner Committed by GitHub

Merge pull request #3439 from tomponline/tp-nic-veth-vlan-ovs

NIC: Veth OVS bridge VLAN support
parents bdf46165 38790036
...@@ -474,6 +474,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -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. <option>lxc.net.[i].veth.ipv6.route</option> options.
Several lines specify several routes. Several lines specify several routes.
The route is in format x.y.z.t/m, eg. 192.168.1.0/24. 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>
<para> <para>
......
...@@ -40,6 +40,7 @@ static char *api_extensions[] = { ...@@ -40,6 +40,7 @@ static char *api_extensions[] = {
"cgroup2", "cgroup2",
"pidfd", "pidfd",
"cgroup_advanced_isolation", "cgroup_advanced_isolation",
"network_bridge_vlan",
}; };
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions); static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "../include/netns_ifaddrs.h" #include "../include/netns_ifaddrs.h"
#include "log.h" #include "log.h"
#include "lxcseccomp.h" #include "lxcseccomp.h"
#include "macro.h"
#include "memory_utils.h" #include "memory_utils.h"
#include "network.h" #include "network.h"
#include "parse.h" #include "parse.h"
...@@ -126,6 +127,8 @@ lxc_config_define(net_veth_mode); ...@@ -126,6 +127,8 @@ lxc_config_define(net_veth_mode);
lxc_config_define(net_veth_pair); lxc_config_define(net_veth_pair);
lxc_config_define(net_veth_ipv4_route); lxc_config_define(net_veth_ipv4_route);
lxc_config_define(net_veth_ipv6_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(net_vlan_id);
lxc_config_define(no_new_privs); lxc_config_define(no_new_privs);
lxc_config_define(personality); lxc_config_define(personality);
...@@ -239,6 +242,8 @@ static struct lxc_config_t config_jump_table[] = { ...@@ -239,6 +242,8 @@ 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.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.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.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_nic, get_config_net_nic, clr_config_net_nic, },
{ "lxc.net", set_config_net, get_config_net, clr_config_net, }, { "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, }, { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
...@@ -306,6 +311,7 @@ static int set_config_net_type(const char *key, const char *value, ...@@ -306,6 +311,7 @@ static int set_config_net_type(const char *key, const char *value,
netdev->type = LXC_NET_VETH; netdev->type = LXC_NET_VETH;
lxc_list_init(&netdev->priv.veth_attr.ipv4_routes); 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.ipv6_routes);
lxc_list_init(&netdev->priv.veth_attr.vlan_tagged_ids);
if (!lxc_veth_flag_to_mode(netdev->priv.veth_attr.mode)) if (!lxc_veth_flag_to_mode(netdev->priv.veth_attr.mode))
lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge"); lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge");
} else if (strcmp(value, "macvlan") == 0) { } else if (strcmp(value, "macvlan") == 0) {
...@@ -487,6 +493,69 @@ static int set_config_net_veth_pair(const char *key, const char *value, ...@@ -487,6 +493,69 @@ 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)); 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 (!netdev)
return ret_errno(EINVAL);
if (lxc_config_value_empty(value))
return clr_config_net_veth_vlan_id(key, lxc_conf, data);
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 ret_errno(EINVAL);
if (vlan_id > BRIDGE_VLAN_ID_MAX)
return 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_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 (!netdev)
return ret_errno(EINVAL);
if (lxc_config_value_empty(value))
return clr_config_net_veth_vlan_tagged_id(key, lxc_conf, data);
ret = get_u16(&vlan_id, value, 0);
if (ret < 0)
ret_errno(EINVAL);
if (vlan_id > BRIDGE_VLAN_ID_MAX)
ret_errno(EINVAL);
list = malloc(sizeof(*list));
if (!list)
return ret_errno(ENOMEM);
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, static int set_config_net_macvlan_mode(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data) struct lxc_conf *lxc_conf, void *data)
{ {
...@@ -5301,6 +5370,38 @@ static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf, ...@@ -5301,6 +5370,38 @@ static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
return 0; 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 ret_errno(EINVAL);
netdev->priv.veth_attr.vlan_id = 0;
netdev->priv.veth_attr.vlan_id_set = false;
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 ret_errno(EINVAL);
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, static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
void *data) void *data)
{ {
...@@ -5772,6 +5873,60 @@ static int get_config_net_veth_pair(const char *key, char *retv, int inlen, ...@@ -5772,6 +5873,60 @@ static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
return fulllen; 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 (!netdev)
return ret_errno(EINVAL);
if (netdev->type != LXC_NET_VETH)
return 0;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
strprint(retv, inlen, "%d", netdev->priv.veth_attr.vlan_id);
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, static int get_config_net_script_up(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data) struct lxc_conf *c, void *data)
{ {
...@@ -6200,6 +6355,7 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen) ...@@ -6200,6 +6355,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.pair\n");
strprint(retv, inlen, "veth.ipv4.route\n"); strprint(retv, inlen, "veth.ipv4.route\n");
strprint(retv, inlen, "veth.ipv6.route\n"); strprint(retv, inlen, "veth.ipv6.route\n");
strprint(retv, inlen, "veth.vlan.id\n");
break; break;
case LXC_NET_MACVLAN: case LXC_NET_MACVLAN:
strprint(retv, inlen, "macvlan.mode\n"); strprint(retv, inlen, "macvlan.mode\n");
......
...@@ -257,6 +257,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf) ...@@ -257,6 +257,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
switch (netdev->type) { switch (netdev->type) {
case LXC_NET_VETH: case LXC_NET_VETH:
TRACE("type: veth"); TRACE("type: veth");
TRACE("veth mode: %d", netdev->priv.veth_attr.mode);
if (netdev->priv.veth_attr.pair[0] != '\0') if (netdev->priv.veth_attr.pair[0] != '\0')
TRACE("veth pair: %s", TRACE("veth pair: %s",
...@@ -269,6 +270,15 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf) ...@@ -269,6 +270,15 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
if (netdev->priv.veth_attr.ifindex > 0) if (netdev->priv.veth_attr.ifindex > 0)
TRACE("host side ifindex for veth device: %d", TRACE("host side ifindex for veth device: %d",
netdev->priv.veth_attr.ifindex); netdev->priv.veth_attr.ifindex);
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; break;
case LXC_NET_MACVLAN: case LXC_NET_MACVLAN:
TRACE("type: macvlan"); TRACE("type: macvlan");
...@@ -439,6 +449,11 @@ static void lxc_free_netdev(struct lxc_netdev *netdev) ...@@ -439,6 +449,11 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
free(cur->elem); free(cur->elem);
free(cur); free(cur);
} }
lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
lxc_list_del(cur);
free(cur);
}
} }
free(netdev); free(netdev);
......
...@@ -380,6 +380,34 @@ extern int __build_bug_on_failed; ...@@ -380,6 +380,34 @@ extern int __build_bug_on_failed;
#define IPVLAN_ISOLATION_VEPA 2 #define IPVLAN_ISOLATION_VEPA 2
#endif #endif
#ifndef BRIDGE_VLAN_NONE
#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
#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 */ /* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
enum { enum {
__LXC_NETNSA_NONE, __LXC_NETNSA_NONE,
...@@ -433,6 +461,9 @@ enum { ...@@ -433,6 +461,9 @@ enum {
#define PTR_TO_UINT64(p) ((uint64_t)((intptr_t)(p))) #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_UID ((uid_t)-1)
#define LXC_INVALID_GID ((gid_t)-1) #define LXC_INVALID_GID ((gid_t)-1)
......
...@@ -79,6 +79,9 @@ struct ifla_veth { ...@@ -79,6 +79,9 @@ struct ifla_veth {
struct lxc_list ipv4_routes; struct lxc_list ipv4_routes;
struct lxc_list ipv6_routes; struct lxc_list ipv6_routes;
int mode; /* bridge, router */ int mode; /* bridge, router */
short vlan_id;
bool vlan_id_set;
struct lxc_list vlan_tagged_ids;
}; };
struct ifla_vlan { struct ifla_vlan {
......
...@@ -776,6 +776,21 @@ int main(int argc, char *argv[]) ...@@ -776,6 +776,21 @@ int main(int argc, char *argv[])
return -1; 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;
}
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)) { 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"); lxc_error("%s\n", "lxc.net.0.script.up");
goto non_test_error; goto non_test_error;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment