mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-25 20:25:27 +00:00
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:
parent
8d539bc9a8
commit
c9f5238291
@ -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
|
||||
```
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user