network: Adds IPVLAN support

Example usage:

	lxc.net[i].type=ipvlan
	lxc.net[i].ipvlan.mode=[l3|l3s|l2] (defaults to l3)
	lxc.net[i].ipvlan.flags=[bridge|private|vepa] (defaults to bridge)
	lxc.net[i].link=eth0
	lxc.net[i].flags=up

Signed-off-by: tomponline <thomas.parrott@canonical.com>
This commit is contained in:
tomponline 2019-04-26 11:26:45 +01:00
parent 8d539bc9a8
commit c9f5238291
10 changed files with 545 additions and 15 deletions

View File

@ -51,3 +51,17 @@ The caller can read this message, inspect the syscalls including its arguments.
This introduces the `lxc.net.[i].veth.ipv4.route` and `lxc.net.[i].veth.ipv6.route` properties
on `veth` type network interfaces. This allows adding static routes on host to the container's
network interface.
## network\_ipvlan
This introduces the `ipvlan` network type.
Example usage:
```
lxc.net[i].type=ipvlan
lxc.net[i].ipvlan.mode=[l3|l3s|l2] (defaults to l3)
lxc.net[i].ipvlan.isolation=[bridge|private|vepa] (defaults to bridge)
lxc.net[i].link=eth0
lxc.net[i].flags=up
```

View File

@ -485,7 +485,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
different macvlan on the same upper device. The accepted
modes are <option>private</option>, <option>vepa</option>,
<option>bridge</option> and <option>passthru</option>.
In <option>private</option> mode, the device never
In <option>private</option> mode, the device never
communicates with any other device on the same upper_dev (default).
In <option>vepa</option> mode, the new Virtual Ethernet Port
Aggregator (VEPA) mode, it assumes that the adjacent
@ -510,6 +510,41 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
mode is possible for one physical interface.
</para>
<para>
<option>ipvlan:</option> an ipvlan interface is linked
with the interface specified by
the <option>lxc.net.[i].link</option> and assigned to
the container.
<option>lxc.net.[i].ipvlan.mode</option> specifies the
mode the ipvlan will use to communicate between
different ipvlan on the same upper device. The accepted
modes are <option>l3</option>, <option>l3s</option> and
<option>l2</option>. It defaults to <option>l3</option> mode.
In <option>l3</option> mode TX processing up to L3 happens on the stack instance
attached to the slave device and packets are switched to the stack instance of the
master device for the L2 processing and routing from that instance will be
used before packets are queued on the outbound device. In this mode the slaves
will not receive nor can send multicast / broadcast traffic.
In <option>l3s</option> mode TX processing is very similar to the L3 mode except that
iptables (conn-tracking) works in this mode and hence it is L3-symmetric (L3s).
This will have slightly less performance but that shouldn't matter since you are
choosing this mode over plain-L3 mode to make conn-tracking work.
In <option>l2</option> mode TX processing happens on the stack instance attached to
the slave device and packets are switched and queued to the master device to send
out. In this mode the slaves will RX/TX multicast and broadcast (if applicable) as well.
<option>lxc.net.[i].ipvlan.isolation</option> specifies the isolation mode.
The accepted isolation values are <option>bridge</option>,
<option>private</option> and <option>vepa</option>.
It defaults to <option>bridge</option>.
In <option>bridge</option> isolation mode slaves can cross-talk among themselves
apart from talking through the master device.
In <option>private</option> isolation mode the port is set in private mode.
i.e. port won't allow cross communication between slaves.
In <option>vepa</option> isolation mode the port is set in VEPA mode.
i.e. port will offload switching functionality to the external entity as
described in 802.1Qbg.
</para>
<para>
<option>phys:</option> an already existing interface
specified by the <option>lxc.net.[i].link</option> is
@ -610,8 +645,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
interface (as specified by the
<option>lxc.net.[i].link</option> option) and use that as
the gateway. <option>auto</option> is only available when
using the <option>veth</option> and
<option>macvlan</option> network types.
using the <option>veth</option>,
<option>macvlan</option> and <option>ipvlan</option> network types.
</para>
</listitem>
</varlistentry>
@ -644,8 +679,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
interface (as specified by the
<option>lxc.net.[i].link</option> option) and use that as
the gateway. <option>auto</option> is only available when
using the <option>veth</option> and
<option>macvlan</option> network types.
using the <option>veth</option>,
<option>macvlan</option> and <option>ipvlan</option> network types.
</para>
</listitem>
</varlistentry>
@ -680,7 +715,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<listitem>
<para>
LXC_NET_TYPE: the network type. This is one of the valid
network types listed here (e.g. 'macvlan', 'veth').
network types listed here (e.g. 'vlan', 'macvlan', 'ipvlan', 'veth').
</para>
</listitem>
@ -746,7 +781,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<listitem>
<para>
LXC_NET_TYPE: the network type. This is one of the valid
network types listed here (e.g. 'macvlan', 'veth').
network types listed here (e.g. 'vlan', 'macvlan', 'ipvlan', 'veth').
</para>
</listitem>

View File

@ -45,6 +45,7 @@ static char *api_extensions[] = {
"seccomp_allow_nesting",
"seccomp_notify",
"network_veth_routes",
"network_ipvlan",
};
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);

View File

@ -130,6 +130,8 @@ lxc_config_define(net_ipv6_address);
lxc_config_define(net_ipv6_gateway);
lxc_config_define(net_link);
lxc_config_define(net_macvlan_mode);
lxc_config_define(net_ipvlan_mode);
lxc_config_define(net_ipvlan_isolation);
lxc_config_define(net_mtu);
lxc_config_define(net_name);
lxc_config_define(net_nic);
@ -221,6 +223,8 @@ static struct lxc_config_t config_jump_table[] = {
{ "lxc.net.ipv6.gateway", set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
{ "lxc.net.link", set_config_net_link, get_config_net_link, clr_config_net_link, },
{ "lxc.net.macvlan.mode", set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
{ "lxc.net.ipvlan.mode", set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
{ "lxc.net.ipvlan.isolation", set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
{ "lxc.net.mtu", set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
{ "lxc.net.name", set_config_net_name, get_config_net_name, clr_config_net_name, },
{ "lxc.net.script.down", set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
@ -291,21 +295,24 @@ static int set_config_net_type(const char *key, const char *value,
if (!netdev)
return -1;
if (!strcmp(value, "veth")) {
if (strcmp(value, "veth") == 0) {
netdev->type = LXC_NET_VETH;
lxc_list_init(&netdev->priv.veth_attr.ipv4_routes);
lxc_list_init(&netdev->priv.veth_attr.ipv6_routes);
} else if (!strcmp(value, "macvlan")) {
} else if (strcmp(value, "macvlan") == 0) {
netdev->type = LXC_NET_MACVLAN;
lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode,
"private");
} else if (!strcmp(value, "vlan")) {
lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
} else if (strcmp(value, "ipvlan") == 0) {
netdev->type = LXC_NET_IPVLAN;
lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, "l3");
lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, "bridge");
} else if (strcmp(value, "vlan") == 0) {
netdev->type = LXC_NET_VLAN;
} else if (!strcmp(value, "phys")) {
} else if (strcmp(value, "phys") == 0) {
netdev->type = LXC_NET_PHYS;
} else if (!strcmp(value, "empty")) {
} else if (strcmp(value, "empty") == 0) {
netdev->type = LXC_NET_EMPTY;
} else if (!strcmp(value, "none")) {
} else if (strcmp(value, "none") == 0) {
netdev->type = LXC_NET_NONE;
} else {
ERROR("Invalid network type %s", value);
@ -438,6 +445,44 @@ static int set_config_net_macvlan_mode(const char *key, const char *value,
return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
}
static int set_config_net_ipvlan_mode(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
struct lxc_netdev *netdev = data;
if (lxc_config_value_empty(value))
return clr_config_net_ipvlan_mode(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
if (netdev->type != LXC_NET_IPVLAN) {
SYSERROR("Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value);
return minus_one_set_errno(EINVAL);
}
return lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, value);
}
static int set_config_net_ipvlan_isolation(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
struct lxc_netdev *netdev = data;
if (lxc_config_value_empty(value))
return clr_config_net_ipvlan_isolation(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
if (netdev->type != LXC_NET_IPVLAN) {
SYSERROR("Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value);
return minus_one_set_errno(EINVAL);
}
return lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, value);
}
static int set_config_net_hwaddr(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
@ -4931,6 +4976,38 @@ static int clr_config_net_macvlan_mode(const char *key,
return 0;
}
static int clr_config_net_ipvlan_mode(const char *key,
struct lxc_conf *lxc_conf, void *data)
{
struct lxc_netdev *netdev = data;
if (!netdev)
return minus_one_set_errno(EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
netdev->priv.ipvlan_attr.mode = -1;
return 0;
}
static int clr_config_net_ipvlan_isolation(const char *key,
struct lxc_conf *lxc_conf, void *data)
{
struct lxc_netdev *netdev = data;
if (!netdev)
return minus_one_set_errno(EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
netdev->priv.ipvlan_attr.isolation = -1;
return 0;
}
static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
void *data)
{
@ -5268,6 +5345,84 @@ static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
return fulllen;
}
static int get_config_net_ipvlan_mode(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
int len;
int fulllen = 0;
const char *mode;
struct lxc_netdev *netdev = data;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
switch (netdev->priv.ipvlan_attr.mode) {
case IPVLAN_MODE_L3:
mode = "l3";
break;
case IPVLAN_MODE_L3S:
mode = "l3s";
break;
case IPVLAN_MODE_L2:
mode = "l2";
break;
default:
mode = "(invalid)";
break;
}
strprint(retv, inlen, "%s", mode);
return fulllen;
}
static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
int len;
int fulllen = 0;
const char *mode;
struct lxc_netdev *netdev = data;
if (!retv)
inlen = 0;
else
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
switch (netdev->priv.ipvlan_attr.isolation) {
case IPVLAN_ISOLATION_BRIDGE:
mode = "bridge";
break;
case IPVLAN_ISOLATION_PRIVATE:
mode = "private";
break;
case IPVLAN_ISOLATION_VEPA:
mode = "vepa";
break;
default:
mode = "(invalid)";
break;
}
strprint(retv, inlen, "%s", mode);
return fulllen;
}
static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
@ -5718,6 +5873,10 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
case LXC_NET_MACVLAN:
strprint(retv, inlen, "macvlan.mode\n");
break;
case LXC_NET_IPVLAN:
strprint(retv, inlen, "ipvlan.mode\n");
strprint(retv, inlen, "ipvlan.isolation\n");
break;
case LXC_NET_VLAN:
strprint(retv, inlen, "vlan.id\n");
break;

View File

@ -299,6 +299,17 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
mode ? mode : "(invalid mode)");
}
break;
case LXC_NET_IPVLAN:
TRACE("type: ipvlan");
char *mode;
mode = lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode);
TRACE("ipvlan mode: %s", mode ? mode : "(invalid mode)");
char *isolation;
isolation = lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation);
TRACE("ipvlan isolation: %s", isolation ? isolation : "(invalid isolation)");
break;
case LXC_NET_VLAN:
TRACE("type: vlan");
TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
@ -519,6 +530,74 @@ char *lxc_macvlan_flag_to_mode(int mode)
return NULL;
}
static struct lxc_ipvlan_mode {
char *name;
int mode;
} ipvlan_mode[] = {
{ "l3", IPVLAN_MODE_L3 },
{ "l3s", IPVLAN_MODE_L3S },
{ "l2", IPVLAN_MODE_L2 },
};
int lxc_ipvlan_mode_to_flag(int *mode, const char *value)
{
for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
if (strcmp(ipvlan_mode[i].name, value) != 0)
continue;
*mode = ipvlan_mode[i].mode;
return 0;
}
return -1;
}
char *lxc_ipvlan_flag_to_mode(int mode)
{
for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
if (ipvlan_mode[i].mode != mode)
continue;
return ipvlan_mode[i].name;
}
return NULL;
}
static struct lxc_ipvlan_isolation {
char *name;
int flag;
} ipvlan_isolation[] = {
{ "bridge", IPVLAN_ISOLATION_BRIDGE },
{ "private", IPVLAN_ISOLATION_PRIVATE },
{ "vepa", IPVLAN_ISOLATION_VEPA },
};
int lxc_ipvlan_isolation_to_flag(int *flag, const char *value)
{
for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
if (strcmp(ipvlan_isolation[i].name, value) != 0)
continue;
*flag = ipvlan_isolation[i].flag;
return 0;
}
return -1;
}
char *lxc_ipvlan_flag_to_isolation(int flag)
{
for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
if (ipvlan_isolation[i].flag != flag)
continue;
return ipvlan_isolation[i].name;
}
return NULL;
}
int set_config_string_item(char **conf_item, const char *value)
{
char *new_value;

View File

@ -58,6 +58,10 @@ extern bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx);
extern void lxc_free_networks(struct lxc_list *networks);
extern int lxc_macvlan_mode_to_flag(int *mode, const char *value);
extern char *lxc_macvlan_flag_to_mode(int mode);
extern int lxc_ipvlan_mode_to_flag(int *mode, const char *value);
extern char *lxc_ipvlan_flag_to_mode(int mode);
extern int lxc_ipvlan_isolation_to_flag(int *mode, const char *value);
extern char *lxc_ipvlan_flag_to_isolation(int mode);
extern int set_config_string_item(char **conf_item, const char *value);
extern int set_config_string_item_max(char **conf_item, const char *value,

View File

@ -280,6 +280,14 @@ extern int __build_bug_on_failed;
#define IFLA_MACVLAN_MODE 1
#endif
#ifndef IFLA_IPVLAN_MODE
#define IFLA_IPVLAN_MODE 1
#endif
#ifndef IFLA_IPVLAN_ISOLATION
#define IFLA_IPVLAN_ISOLATION 2
#endif
#ifndef IFLA_NEW_NETNSID
#define IFLA_NEW_NETNSID 45
#endif
@ -333,6 +341,30 @@ extern int __build_bug_on_failed;
#define MACVLAN_MODE_PASSTHRU 8
#endif
#ifndef IPVLAN_MODE_L2
#define IPVLAN_MODE_L2 0
#endif
#ifndef IPVLAN_MODE_L3
#define IPVLAN_MODE_L3 1
#endif
#ifndef IPVLAN_MODE_L3S
#define IPVLAN_MODE_L3S 2
#endif
#ifndef IPVLAN_ISOLATION_BRIDGE
#define IPVLAN_ISOLATION_BRIDGE 0
#endif
#ifndef IPVLAN_ISOLATION_PRIVATE
#define IPVLAN_ISOLATION_PRIVATE 1
#endif
#ifndef IPVLAN_ISOLATION_VEPA
#define IPVLAN_ISOLATION_VEPA 2
#endif
/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
enum {
__LXC_NETNSA_NONE,

View File

@ -376,6 +376,147 @@ on_error:
return -1;
}
static int lxc_ipvlan_create(const char *master, const char *name, int mode, int isolation)
{
int err, index, len;
struct ifinfomsg *ifi;
struct nl_handler nlh;
struct rtattr *nest, *nest2;
struct nlmsg *answer = NULL, *nlmsg = NULL;
len = strlen(master);
if (len == 1 || len >= IFNAMSIZ)
return minus_one_set_errno(EINVAL);
len = strlen(name);
if (len == 1 || len >= IFNAMSIZ)
return minus_one_set_errno(EINVAL);
index = if_nametoindex(master);
if (!index)
return minus_one_set_errno(EINVAL);
err = netlink_open(&nlh, NETLINK_ROUTE);
if (err)
return minus_one_set_errno(-err);
err = -ENOMEM;
nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
if (!nlmsg)
goto out;
answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
if (!answer)
goto out;
nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
if (!ifi) {
goto out;
}
ifi->ifi_family = AF_UNSPEC;
err = -EPROTO;
nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
if (!nest)
goto out;
if (nla_put_string(nlmsg, IFLA_INFO_KIND, "ipvlan"))
goto out;
if (mode) {
nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
if (!nest2)
goto out;
if (nla_put_u32(nlmsg, IFLA_IPVLAN_MODE, mode))
goto out;
/* if_link.h does not define the isolation flag value for bridge mode so we define it as 0
* and only send mode if mode >0 as default mode is bridge anyway according to ipvlan docs.
*/
if (isolation > 0) {
if (nla_put_u16(nlmsg, IFLA_IPVLAN_ISOLATION, isolation))
goto out;
}
nla_end_nested(nlmsg, nest2);
}
nla_end_nested(nlmsg, nest);
if (nla_put_u32(nlmsg, IFLA_LINK, index))
goto out;
if (nla_put_string(nlmsg, IFLA_IFNAME, name))
goto out;
err = netlink_transaction(&nlh, nlmsg, answer);
out:
netlink_close(&nlh);
nlmsg_free(answer);
nlmsg_free(nlmsg);
if (err < 0)
return minus_one_set_errno(-err);
return 0;
}
static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char peerbuf[IFNAMSIZ], *peer;
int err;
if (netdev->link[0] == '\0') {
ERROR("No link for ipvlan network device specified");
return -1;
}
err = snprintf(peerbuf, sizeof(peerbuf), "ipXXXXXX");
if (err < 0 || (size_t)err >= sizeof(peerbuf))
return -1;
peer = lxc_mkifname(peerbuf);
if (!peer)
return -1;
err = lxc_ipvlan_create(netdev->link, peer, netdev->priv.ipvlan_attr.mode, netdev->priv.ipvlan_attr.isolation);
if (err) {
SYSERROR("Failed to create ipvlan interface \"%s\" on \"%s\"", peer, netdev->link);
goto on_error;
}
netdev->ifindex = if_nametoindex(peer);
if (!netdev->ifindex) {
ERROR("Failed to retrieve ifindex for \"%s\"", peer);
goto on_error;
}
if (netdev->upscript) {
char *argv[] = {
"ipvlan",
netdev->link,
NULL,
};
err = run_script_argv(handler->name,
handler->conf->hooks_version, "net",
netdev->upscript, "up", argv);
if (err < 0)
goto on_error;
}
DEBUG("Instantiated ipvlan \"%s\" with ifindex is %d and mode %d",
peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
return 0;
on_error:
lxc_netdev_delete_by_name(peer);
return -1;
}
static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
char peer[IFNAMSIZ];
@ -518,6 +659,7 @@ static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netd
static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_VETH] = instantiate_veth,
[LXC_NET_MACVLAN] = instantiate_macvlan,
[LXC_NET_IPVLAN] = instantiate_ipvlan,
[LXC_NET_VLAN] = instantiate_vlan,
[LXC_NET_PHYS] = instantiate_phys,
[LXC_NET_EMPTY] = instantiate_empty,
@ -571,6 +713,26 @@ static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netd
return 0;
}
static int shutdown_ipvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
int ret;
char *argv[] = {
"ipvlan",
netdev->link,
NULL,
};
if (!netdev->downscript)
return 0;
ret = run_script_argv(handler->name, handler->conf->hooks_version,
"net", netdev->downscript, "down", argv);
if (ret < 0)
return -1;
return 0;
}
static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
{
int ret;
@ -638,6 +800,7 @@ static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
static instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_VETH] = shutdown_veth,
[LXC_NET_MACVLAN] = shutdown_macvlan,
[LXC_NET_IPVLAN] = shutdown_ipvlan,
[LXC_NET_VLAN] = shutdown_vlan,
[LXC_NET_PHYS] = shutdown_phys,
[LXC_NET_EMPTY] = shutdown_empty,
@ -2012,6 +2175,7 @@ static const char *const lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
[LXC_NET_EMPTY] = "empty",
[LXC_NET_VETH] = "veth",
[LXC_NET_MACVLAN] = "macvlan",
[LXC_NET_IPVLAN] = "ipvlan",
[LXC_NET_PHYS] = "phys",
[LXC_NET_VLAN] = "vlan",
[LXC_NET_NONE] = "none",

View File

@ -40,6 +40,7 @@ enum {
LXC_NET_EMPTY,
LXC_NET_VETH,
LXC_NET_MACVLAN,
LXC_NET_IPVLAN,
LXC_NET_PHYS,
LXC_NET_VLAN,
LXC_NET_NONE,
@ -110,6 +111,11 @@ struct ifla_macvlan {
int mode; /* private, vepa, bridge, passthru */
};
struct ifla_ipvlan {
int mode; /* l3, l3s, l2 */
int isolation; /* bridge, private, vepa */
};
/* Contains information about the physical network device as seen from the host.
* @ifindex : The ifindex of the physical network device in the host's network
* namespace.
@ -120,6 +126,7 @@ struct ifla_phys {
union netdev_p {
struct ifla_macvlan macvlan_attr;
struct ifla_ipvlan ipvlan_attr;
struct ifla_phys phys_attr;
struct ifla_veth veth_attr;
struct ifla_vlan vlan_attr;

View File

@ -666,6 +666,11 @@ int main(int argc, char *argv[])
goto non_test_error;
}
if (set_get_compare_clear_save_load(c, "lxc.net.0.type", "ipvlan", tmpf, true)) {
lxc_error("%s\n", "lxc.net.0.type");
goto non_test_error;
}
if (set_get_compare_clear_save_load(c, "lxc.net.1000.type", "phys", tmpf, true)) {
lxc_error("%s\n", "lxc.net.1000.type");
goto non_test_error;
@ -701,6 +706,36 @@ int main(int argc, char *argv[])
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.ipvlan.mode", "l3", tmpf, true, "ipvlan")) {
lxc_error("%s\n", "lxc.net.0.ipvlan.mode");
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.ipvlan.mode", "l3s", tmpf, true, "ipvlan")) {
lxc_error("%s\n", "lxc.net.0.ipvlan.mode");
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.ipvlan.mode", "l2", tmpf, true, "ipvlan")) {
lxc_error("%s\n", "lxc.net.0.ipvlan.mode");
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.ipvlan.isolation", "bridge", tmpf, true, "ipvlan")) {
lxc_error("%s\n", "lxc.net.0.ipvlan.isolation");
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.ipvlan.isolation", "private", tmpf, true, "ipvlan")) {
lxc_error("%s\n", "lxc.net.0.ipvlan.isolation");
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.ipvlan.isolation", "vepa", tmpf, true, "ipvlan")) {
lxc_error("%s\n", "lxc.net.0.ipvlan.isolation");
goto non_test_error;
}
if (set_get_compare_clear_save_load_network(c, "lxc.net.0.veth.pair", "clusterfuck", tmpf, true, "veth")) {
lxc_error("%s\n", "lxc.net.0.veth.pair");
goto non_test_error;