Unverified Commit 8b4aaf8b by Christian Brauner Committed by GitHub

Merge pull request #2921 from tomponline/tp-2019-03-26/routedveth

Adds veth router mode
parents bc554fdf 3e5c2e69
...@@ -96,3 +96,12 @@ This is primarily intended for use with layer 3 networking devices, such as IPVL ...@@ -96,3 +96,12 @@ This is primarily intended for use with layer 3 networking devices, such as IPVL
This introduces the ability to specify a custom MTU for `phys` and `macvlan` devices using the This introduces the ability to specify a custom MTU for `phys` and `macvlan` devices using the
`lxc.net.[i].mtu` property. `lxc.net.[i].mtu` property.
# network\_veth\_router
This introduces the ability to specify a `lxc.net.[i].veth.mode` setting, which takes a value of
"bridge" or "router". This defaults to "bridge".
In "router" mode static routes are created on the host for the container's IP addresses pointing to
the host side veth interface. In addition to the routes, a static IP neighbour proxy is added to
the host side veth interface for the IPv4 and IPv6 gateway IPs.
...@@ -443,14 +443,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ...@@ -443,14 +443,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<para> <para>
<option>veth:</option> a virtual ethernet pair <option>veth:</option> a virtual ethernet pair
device is created with one side assigned to the container device is created with one side assigned to the container
and the other side attached to a bridge specified by and the other side on the host.
<option>lxc.net.[i].veth.mode</option> specifies the
mode the veth parent will use on the host.
The accepted modes are <option>bridge</option> and <option>router</option>.
The mode defaults to bridge if not specified.
In <option>bridge</option> mode the host side is attached to a bridge specified by
the <option>lxc.net.[i].link</option> option. the <option>lxc.net.[i].link</option> option.
If the bridge is not specified, then the veth pair device If the bridge link is not specified, then the veth pair device
will be created but not attached to any bridge. will be created but not attached to any bridge.
Otherwise, the bridge has to be created on the system Otherwise, the bridge has to be created on the system
before starting the container. before starting the container.
<command>lxc</command> won't handle any <command>lxc</command> won't handle any
configuration outside of the container. configuration outside of the container.
In <option>router</option> mode static routes are created on the host for the
container's IP addresses pointing to the host side veth interface.
Additionally Proxy ARP and Proxy NDP entries are added on the host side veth interface
for the gateway IPs defined in the container to allow the container to reach the host.
By default, <command>lxc</command> chooses a name for the By default, <command>lxc</command> chooses a name for the
network device belonging to the outside of the network device belonging to the outside of the
container, but if you wish to handle container, but if you wish to handle
......
...@@ -49,6 +49,7 @@ static char *api_extensions[] = { ...@@ -49,6 +49,7 @@ static char *api_extensions[] = {
"network_l2proxy", "network_l2proxy",
"network_gateway_device_route", "network_gateway_device_route",
"network_phys_macvlan_mtu", "network_phys_macvlan_mtu",
"network_veth_router",
}; };
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions); static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
......
...@@ -139,6 +139,7 @@ lxc_config_define(net_nic); ...@@ -139,6 +139,7 @@ lxc_config_define(net_nic);
lxc_config_define(net_script_down); lxc_config_define(net_script_down);
lxc_config_define(net_script_up); lxc_config_define(net_script_up);
lxc_config_define(net_type); lxc_config_define(net_type);
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);
...@@ -234,6 +235,7 @@ static struct lxc_config_t config_jump_table[] = { ...@@ -234,6 +235,7 @@ static struct lxc_config_t config_jump_table[] = {
{ "lxc.net.script.up", set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, }, { "lxc.net.script.up", set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
{ "lxc.net.type", set_config_net_type, get_config_net_type, clr_config_net_type, }, { "lxc.net.type", set_config_net_type, get_config_net_type, clr_config_net_type, },
{ "lxc.net.vlan.id", set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, }, { "lxc.net.vlan.id", set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
{ "lxc.net.veth.mode", set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
{ "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, },
...@@ -303,6 +305,7 @@ static int set_config_net_type(const char *key, const char *value, ...@@ -303,6 +305,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_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge");
} else if (strcmp(value, "macvlan") == 0) { } else if (strcmp(value, "macvlan") == 0) {
netdev->type = LXC_NET_MACVLAN; netdev->type = LXC_NET_MACVLAN;
lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private"); lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
...@@ -450,6 +453,21 @@ static int set_config_net_name(const char *key, const char *value, ...@@ -450,6 +453,21 @@ static int set_config_net_name(const char *key, const char *value,
return network_ifname(netdev->name, value, sizeof(netdev->name)); return network_ifname(netdev->name, value, sizeof(netdev->name));
} }
static int set_config_net_veth_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_veth_mode(key, lxc_conf, data);
if (!netdev)
return -1;
return lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, value);
}
static int set_config_net_veth_pair(const char *key, const char *value, static int set_config_net_veth_pair(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data) struct lxc_conf *lxc_conf, void *data)
{ {
...@@ -5094,6 +5112,22 @@ static int clr_config_net_ipvlan_isolation(const char *key, ...@@ -5094,6 +5112,22 @@ static int clr_config_net_ipvlan_isolation(const char *key,
return 0; return 0;
} }
static int clr_config_net_veth_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_VETH)
return 0;
netdev->priv.veth_attr.mode = -1;
return 0;
}
static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf, static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
void *data) void *data)
{ {
...@@ -5516,6 +5550,42 @@ static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inle ...@@ -5516,6 +5550,42 @@ static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inle
return fulllen; return fulllen;
} }
static int get_config_net_veth_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_VETH)
return 0;
switch (netdev->priv.veth_attr.mode) {
case VETH_MODE_BRIDGE:
mode = "bridge";
break;
case VETH_MODE_ROUTER:
mode = "router";
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, static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data) struct lxc_conf *c, void *data)
{ {
......
...@@ -501,6 +501,28 @@ void lxc_free_networks(struct lxc_list *networks) ...@@ -501,6 +501,28 @@ void lxc_free_networks(struct lxc_list *networks)
lxc_list_init(networks); lxc_list_init(networks);
} }
static struct lxc_veth_mode {
char *name;
int mode;
} veth_mode[] = {
{ "bridge", VETH_MODE_BRIDGE },
{ "router", VETH_MODE_ROUTER },
};
int lxc_veth_mode_to_flag(int *mode, const char *value)
{
for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
if (strcmp(veth_mode[i].name, value) != 0)
continue;
*mode = veth_mode[i].mode;
return 0;
}
return minus_one_set_errno(EINVAL);
}
static struct lxc_macvlan_mode { static struct lxc_macvlan_mode {
char *name; char *name;
int mode; int mode;
......
...@@ -56,6 +56,7 @@ lxc_get_netdev_by_idx(struct lxc_conf *conf, unsigned int idx, bool allocate); ...@@ -56,6 +56,7 @@ lxc_get_netdev_by_idx(struct lxc_conf *conf, unsigned int idx, bool allocate);
extern void lxc_log_configured_netdevs(const struct lxc_conf *conf); extern void lxc_log_configured_netdevs(const struct lxc_conf *conf);
extern bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx); extern bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx);
extern void lxc_free_networks(struct lxc_list *networks); extern void lxc_free_networks(struct lxc_list *networks);
extern int lxc_veth_mode_to_flag(int *mode, const char *value);
extern int lxc_macvlan_mode_to_flag(int *mode, const char *value); extern int lxc_macvlan_mode_to_flag(int *mode, const char *value);
extern char *lxc_macvlan_flag_to_mode(int mode); extern char *lxc_macvlan_flag_to_mode(int mode);
extern int lxc_ipvlan_mode_to_flag(int *mode, const char *value); extern int lxc_ipvlan_mode_to_flag(int *mode, const char *value);
......
...@@ -505,6 +505,13 @@ ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \ ...@@ -505,6 +505,13 @@ ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
} while (0) } while (0)
#endif #endif
#define error_log_errno(__errno__, format, ...) \
({ \
errno = __errno__; \
SYSERROR(format, ##__VA_ARGS__); \
-1; \
})
extern int lxc_log_fd; extern int lxc_log_fd;
extern int lxc_log_syslog(int facility); extern int lxc_log_syslog(int facility);
......
...@@ -281,6 +281,14 @@ extern int __build_bug_on_failed; ...@@ -281,6 +281,14 @@ extern int __build_bug_on_failed;
#define VETH_INFO_PEER 1 #define VETH_INFO_PEER 1
#endif #endif
#ifndef VETH_MODE_BRIDGE
#define VETH_MODE_BRIDGE 1
#endif
#ifndef VETH_MODE_ROUTER
#define VETH_MODE_ROUTER 2
#endif
#ifndef IFLA_MACVLAN_MODE #ifndef IFLA_MACVLAN_MODE
#define IFLA_MACVLAN_MODE 1 #define IFLA_MACVLAN_MODE 1
#endif #endif
......
...@@ -178,6 +178,118 @@ static int lxc_setup_ipv6_routes(struct lxc_list *ip, int ifindex) ...@@ -178,6 +178,118 @@ static int lxc_setup_ipv6_routes(struct lxc_list *ip, int ifindex)
return 0; return 0;
} }
static int setup_ipv4_addr_routes(struct lxc_list *ip, int ifindex)
{
struct lxc_list *iterator;
int err;
lxc_list_for_each(iterator, ip) {
struct lxc_inetdev *inetdev = iterator->elem;
err = lxc_ipv4_dest_add(ifindex, &inetdev->addr, 32);
if (err)
return error_log_errno(err,
"Failed to setup ipv4 address route for network device with eifindex %d",
ifindex);
}
return 0;
}
static int setup_ipv6_addr_routes(struct lxc_list *ip, int ifindex)
{
struct lxc_list *iterator;
int err;
lxc_list_for_each(iterator, ip) {
struct lxc_inet6dev *inet6dev = iterator->elem;
err = lxc_ipv6_dest_add(ifindex, &inet6dev->addr, 128);
if (err)
return error_log_errno(err,
"Failed to setup ipv6 address route for network device with eifindex %d",
ifindex);
}
return 0;
}
struct ip_proxy_args {
const char *ip;
const char *dev;
};
static int lxc_add_ip_neigh_proxy_exec_wrapper(void *data)
{
struct ip_proxy_args *args = data;
execlp("ip", "ip", "neigh", "add", "proxy", args->ip, "dev", args->dev, (char *)NULL);
return -1;
}
static int lxc_del_ip_neigh_proxy_exec_wrapper(void *data)
{
struct ip_proxy_args *args = data;
execlp("ip", "ip", "neigh", "flush", "proxy", args->ip, "dev", args->dev, (char *)NULL);
return -1;
}
static int lxc_add_ip_neigh_proxy(const char *ip, const char *dev)
{
int ret;
char cmd_output[PATH_MAX] = {0};
struct ip_proxy_args args = {
.ip = ip,
.dev = dev,
};
ret = run_command(cmd_output, sizeof(cmd_output), lxc_add_ip_neigh_proxy_exec_wrapper, &args);
if (ret < 0) {
ERROR("Failed to add ip proxy \"%s\" to dev \"%s\": %s", ip, dev, cmd_output);
return -1;
}
return 0;
}
static int lxc_del_ip_neigh_proxy(const char *ip, const char *dev)
{
int ret;
char cmd_output[PATH_MAX] = {0};
struct ip_proxy_args args = {
.ip = ip,
.dev = dev,
};
ret = run_command(cmd_output, sizeof(cmd_output), lxc_del_ip_neigh_proxy_exec_wrapper, &args);
if (ret < 0) {
ERROR("Failed to delete ip proxy \"%s\" to dev \"%s\": %s", ip, dev, cmd_output);
return -1;
}
return 0;
}
static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
{
int ret;
char path[PATH_MAX];
char buf[1] = "";
if (family != AF_INET && family != AF_INET6)
return minus_one_set_errno(EINVAL);
ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
family == AF_INET ? "ipv4" : "ipv6", ifname,
"forwarding");
if (ret < 0 || (size_t)ret >= PATH_MAX)
return minus_one_set_errno(E2BIG);
return lxc_read_file_expect(path, buf, 1, "1");
}
static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
{ {
int bridge_index, err; int bridge_index, err;
...@@ -276,7 +388,7 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -276,7 +388,7 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
} }
} }
if (netdev->link[0] != '\0') { if (netdev->link[0] != '\0' && netdev->priv.veth_attr.mode == VETH_MODE_BRIDGE) {
err = lxc_bridge_attach(netdev->link, veth1); err = lxc_bridge_attach(netdev->link, veth1);
if (err) { if (err) {
errno = -err; errno = -err;
...@@ -306,6 +418,78 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd ...@@ -306,6 +418,78 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
goto out_delete; goto out_delete;
} }
if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTER) {
if (netdev->ipv4_gateway) {
char bufinet4[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4))) {
error_log_errno(-errno, "Failed to convert gateway ipv4 address on \"%s\"", veth1);
goto out_delete;
}
err = lxc_ip_forwarding_on(veth1, AF_INET);
if (err) {
error_log_errno(err, "Failed to activate ipv4 forwarding on \"%s\"", veth1);
goto out_delete;
}
err = lxc_add_ip_neigh_proxy(bufinet4, veth1);
if (err) {
error_log_errno(err, "Failed to add gateway ipv4 proxy on \"%s\"", veth1);
goto out_delete;
}
}
if (netdev->ipv6_gateway) {
char bufinet6[INET6_ADDRSTRLEN];
if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6))) {
error_log_errno(-errno, "Failed to convert gateway ipv6 address on \"%s\"", veth1);
goto out_delete;
}
/* Check for sysctl net.ipv6.conf.all.forwarding=1
Kernel requires this to route any packets for IPv6.
*/
err = lxc_is_ip_forwarding_enabled("all", AF_INET6);
if (err) {
error_log_errno(err, "Requires sysctl net.ipv6.conf.all.forwarding=1");
goto out_delete;
}
err = lxc_ip_forwarding_on(veth1, AF_INET6);
if (err) {
error_log_errno(err, "Failed to activate ipv6 forwarding on \"%s\"", veth1);
goto out_delete;
}
err = lxc_neigh_proxy_on(veth1, AF_INET6);
if (err) {
error_log_errno(err, "Failed to activate proxy ndp on \"%s\"", veth1);
goto out_delete;
}
err = lxc_add_ip_neigh_proxy(bufinet6, veth1);
if (err) {
error_log_errno(err, "Failed to add gateway ipv6 proxy on \"%s\"", veth1);
goto out_delete;
}
}
/* setup ipv4 address routes on the host interface */
err = setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex);
if (err) {
error_log_errno(err, "Failed to setup ip address routes for network device \"%s\"", veth1);
goto out_delete;
}
/* setup ipv6 address routes on the host interface */
err = setup_ipv6_addr_routes(&netdev->ipv6, netdev->priv.veth_attr.ifindex);
if (err) {
error_log_errno(err, "Failed to setup ip address routes for network device \"%s\"", veth1);
goto out_delete;
}
}
if (netdev->upscript) { if (netdev->upscript) {
char *argv[] = { char *argv[] = {
"veth", "veth",
...@@ -1798,22 +1982,30 @@ static int proc_sys_net_write(const char *path, const char *value) ...@@ -1798,22 +1982,30 @@ static int proc_sys_net_write(const char *path, const char *value)
return err; return err;
} }
static int lxc_is_ip_forwarding_enabled(const char *ifname, int family) static int ip_forwarding_set(const char *ifname, int family, int flag)
{ {
int ret; int ret;
char path[PATH_MAX]; char path[PATH_MAX];
char buf[1] = "";
if (family != AF_INET && family != AF_INET6) if (family != AF_INET && family != AF_INET6)
return minus_one_set_errno(EINVAL); return -EINVAL;
ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s", ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
family == AF_INET ? "ipv4" : "ipv6", ifname, family == AF_INET ? "ipv4" : "ipv6", ifname, "forwarding");
"forwarding");
if (ret < 0 || (size_t)ret >= PATH_MAX) if (ret < 0 || (size_t)ret >= PATH_MAX)
return minus_one_set_errno(E2BIG); return -E2BIG;
return lxc_read_file_expect(path, buf, 1, "1"); return proc_sys_net_write(path, flag ? "1" : "0");
}
int lxc_ip_forwarding_on(const char *name, int family)
{
return ip_forwarding_set(name, family, 1);
}
int lxc_ip_forwarding_off(const char *name, int family)
{
return ip_forwarding_set(name, family, 0);
} }
static int neigh_proxy_set(const char *ifname, int family, int flag) static int neigh_proxy_set(const char *ifname, int family, int flag)
...@@ -2867,63 +3059,6 @@ clear_ifindices: ...@@ -2867,63 +3059,6 @@ clear_ifindices:
return true; return true;
} }
struct ip_proxy_args {
const char *ip;
const char *dev;
};
static int lxc_add_ip_neigh_proxy_exec_wrapper(void *data)
{
struct ip_proxy_args *args = data;
execlp("ip", "ip", "neigh", "add", "proxy", args->ip, "dev", args->dev, (char *)NULL);
return -1;
}
static int lxc_del_ip_neigh_proxy_exec_wrapper(void *data)
{
struct ip_proxy_args *args = data;
execlp("ip", "ip", "neigh", "flush", "proxy", args->ip, "dev", args->dev, (char *)NULL);
return -1;
}
static int lxc_add_ip_neigh_proxy(const char *ip, const char *dev)
{
int ret;
char cmd_output[PATH_MAX];
struct ip_proxy_args args = {
.ip = ip,
.dev = dev,
};
ret = run_command(cmd_output, sizeof(cmd_output), lxc_add_ip_neigh_proxy_exec_wrapper, &args);
if (ret < 0) {
ERROR("Failed to add ip proxy \"%s\" to dev \"%s\": %s", ip, dev, cmd_output);
return -1;
}
return 0;
}
static int lxc_del_ip_neigh_proxy(const char *ip, const char *dev)
{
int ret;
char cmd_output[PATH_MAX];
struct ip_proxy_args args = {
.ip = ip,
.dev = dev,
};
ret = run_command(cmd_output, sizeof(cmd_output), lxc_del_ip_neigh_proxy_exec_wrapper, &args);
if (ret < 0) {
ERROR("Failed to delete ip proxy \"%s\" to dev \"%s\": %s", ip, dev, cmd_output);
return -1;
}
return 0;
}
static int lxc_setup_l2proxy(struct lxc_netdev *netdev) { static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
struct lxc_list *cur, *next; struct lxc_list *cur, *next;
struct lxc_inetdev *inet4dev; struct lxc_inetdev *inet4dev;
......
...@@ -98,6 +98,7 @@ struct ifla_veth { ...@@ -98,6 +98,7 @@ struct ifla_veth {
int ifindex; int ifindex;
struct lxc_list ipv4_routes; struct lxc_list ipv4_routes;
struct lxc_list ipv6_routes; struct lxc_list ipv6_routes;
int mode; /* bridge, router */
}; };
struct ifla_vlan { struct ifla_vlan {
...@@ -263,6 +264,12 @@ extern int lxc_neigh_proxy_on(const char *name, int family); ...@@ -263,6 +264,12 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
/* Disable neighbor proxying. */ /* Disable neighbor proxying. */
extern int lxc_neigh_proxy_off(const char *name, int family); extern int lxc_neigh_proxy_off(const char *name, int family);
/* Activate IP forwarding. */
extern int lxc_ip_forwarding_on(const char *name, int family);
/* Disable IP forwarding. */
extern int lxc_ip_forwarding_off(const char *name, int family);
/* Generate a new unique network interface name. /* Generate a new unique network interface name.
* Allocated memory must be freed by caller. * Allocated memory must be freed by caller.
*/ */
......
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