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
+```
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
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
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>
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>
<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>
<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>
"seccomp_allow_nesting",
"seccomp_notify",
"network_veth_routes",
+ "network_ipvlan",
};
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
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);
{ "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, },
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);
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)
{
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)
{
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)
{
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;
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);
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;
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,
#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
#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,
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];
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,
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;
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,
[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",
LXC_NET_EMPTY,
LXC_NET_VETH,
LXC_NET_MACVLAN,
+ LXC_NET_IPVLAN,
LXC_NET_PHYS,
LXC_NET_VLAN,
LXC_NET_NONE,
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.
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;
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;
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;