Adds ability to specify "dev" as the gateway value, which will cause a device route to be set as default gateway.
Signed-off-by: tomponline <thomas.parrott@canonical.com>
net.ipv6.conf.[link].proxy_ndp=1
net.ipv6.conf.[link].forwarding=1
```
+
+## network\_gateway\_device\_route
+
+This introduces the ability to specify `lxc.net.[i].ipv4.gateway` and/or
+`lxc.net.[i].ipv6.gateway` with a value of `dev` which will cause the default gateway
+inside the container to be created as a device route without destination gateway IP needed.
+This is primarily intended for use with layer 3 networking devices, such as IPVLAN.
the gateway. <option>auto</option> is only available when
using the <option>veth</option>,
<option>macvlan</option> and <option>ipvlan</option> network types.
+ Can also have the special value of <option>dev</option>,
+ which means to set the default gateway as a device route.
+ This is primarily for use with layer 3 network modes, such as IPVLAN.
</para>
</listitem>
</varlistentry>
the gateway. <option>auto</option> is only available when
using the <option>veth</option>,
<option>macvlan</option> and <option>ipvlan</option> network types.
+ Can also have the special value of <option>dev</option>,
+ which means to set the default gateway as a device route.
+ This is primarily for use with layer 3 network modes, such as IPVLAN.
</para>
</listitem>
</varlistentry>
"network_veth_routes",
"network_ipvlan",
"network_l2proxy",
+ "network_gateway_device_route",
};
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
free(netdev->ipv4_gateway);
- if (!strcmp(value, "auto")) {
+ if (strcmp(value, "auto") == 0) {
netdev->ipv4_gateway = NULL;
netdev->ipv4_gateway_auto = true;
+ } else if (strcmp(value, "dev") == 0) {
+ netdev->ipv4_gateway = NULL;
+ netdev->ipv4_gateway_auto = false;
+ netdev->ipv4_gateway_dev = true;
} else {
int ret;
struct in_addr *gw;
free(netdev->ipv6_gateway);
- if (!strcmp(value, "auto")) {
+ if (strcmp(value, "auto") == 0) {
netdev->ipv6_gateway = NULL;
netdev->ipv6_gateway_auto = true;
+ } else if (strcmp(value, "dev") == 0) {
+ netdev->ipv6_gateway = NULL;
+ netdev->ipv6_gateway_auto = false;
+ netdev->ipv6_gateway_dev = true;
} else {
int ret;
struct in6_addr *gw;
if (netdev->ipv4_gateway_auto) {
strprint(retv, inlen, "auto");
+ } else if (netdev->ipv4_gateway_dev) {
+ strprint(retv, inlen, "dev");
} else if (netdev->ipv4_gateway) {
inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
strprint(retv, inlen, "%s", buf);
if (netdev->ipv6_gateway_auto) {
strprint(retv, inlen, "auto");
+ } else if (netdev->ipv6_gateway_dev) {
+ strprint(retv, inlen, "dev");
} else if (netdev->ipv6_gateway) {
inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
strprint(retv, inlen, "%s", buf);
TRACE("ipv4 gateway auto: %s",
netdev->ipv4_gateway_auto ? "true" : "false");
+ TRACE("ipv4 gateway dev: %s",
+ netdev->ipv4_gateway_dev ? "true" : "false");
+
if (netdev->ipv4_gateway) {
inet_ntop(AF_INET, netdev->ipv4_gateway,
bufinet4, sizeof(bufinet4));
TRACE("ipv6 gateway auto: %s",
netdev->ipv6_gateway_auto ? "true" : "false");
+ TRACE("ipv6 gateway dev: %s",
+ netdev->ipv6_gateway_dev ? "true" : "false");
+
if (netdev->ipv6_gateway) {
inet_ntop(AF_INET6, netdev->ipv6_gateway,
bufinet6, sizeof(bufinet6));
rt->rtm_dst_len = 0;
err = -EINVAL;
- if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
- goto out;
+
+ /* If gateway address not supplied, then a device route will be created instead */
+ if (gw != NULL) {
+ if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
+ goto out;
+ }
/* Adding the interface index enables the use of link-local
* addresses for the gateway.
}
/* We can only set up the default routes after bringing
- * up the interface, sine bringing up the interface adds
+ * up the interface, since bringing up the interface adds
* the link-local routes and we can't add a default
* route if the gateway is not reachable. */
/* setup ipv4 gateway on the interface */
- if (netdev->ipv4_gateway) {
+ if (netdev->ipv4_gateway || netdev->ipv4_gateway_dev) {
if (!(netdev->flags & IFF_UP)) {
ERROR("Cannot add ipv4 gateway for network device "
"\"%s\" when not bringing up the interface", ifname);
return -1;
}
- err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway, 32);
- if (err) {
- errno = -err;
- SYSERROR("Failed to add ipv4 dest for network device \"%s\"",
+ /* Setup device route if ipv4_gateway_dev is enabled */
+ if (netdev->ipv4_gateway_dev) {
+ err = lxc_ipv4_gateway_add(netdev->ifindex, NULL);
+ if (err < 0) {
+ SYSERROR("Failed to setup ipv4 gateway to network device \"%s\"",
ifname);
+ return minus_one_set_errno(-err);
}
-
+ } else {
err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
if (err) {
- errno = -err;
- SYSERROR("Failed to setup ipv4 gateway for network device \"%s\"",
- ifname);
+ err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway, 32);
+ if (err) {
+ errno = -err;
+ SYSERROR("Failed to add ipv4 dest for network device \"%s\"",
+ ifname);
+ }
+
+ err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+ if (err) {
+ errno = -err;
+ SYSERROR("Failed to setup ipv4 gateway for network device \"%s\"",
+ ifname);
- if (netdev->ipv4_gateway_auto) {
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
- ERROR("Tried to set autodetected ipv4 gateway \"%s\"", buf);
+ if (netdev->ipv4_gateway_auto) {
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
+ ERROR("Tried to set autodetected ipv4 gateway \"%s\"", buf);
+ }
+ return -1;
}
- return -1;
}
}
}
/* setup ipv6 gateway on the interface */
- if (netdev->ipv6_gateway) {
+ if (netdev->ipv6_gateway || netdev->ipv6_gateway_dev) {
if (!(netdev->flags & IFF_UP)) {
ERROR("Cannot add ipv6 gateway for network device "
"\"%s\" when not bringing up the interface", ifname);
return -1;
}
- err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway, 128);
- if (err) {
- errno = -err;
- SYSERROR("Failed to add ipv6 dest for network device \"%s\"",
+ /* Setup device route if ipv6_gateway_dev is enabled */
+ if (netdev->ipv6_gateway_dev) {
+ err = lxc_ipv6_gateway_add(netdev->ifindex, NULL);
+ if (err < 0) {
+ SYSERROR("Failed to setup ipv6 gateway to network device \"%s\"",
ifname);
+ return minus_one_set_errno(-err);
}
-
+ } else {
err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
if (err) {
- errno = -err;
- SYSERROR("Failed to setup ipv6 gateway for network device \"%s\"",
- ifname);
+ err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway, 128);
+ if (err) {
+ errno = -err;
+ SYSERROR("Failed to add ipv6 dest for network device \"%s\"",
+ ifname);
+ }
- if (netdev->ipv6_gateway_auto) {
- char buf[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
- ERROR("Tried to set autodetected ipv6 "
- "gateway for network device "
- "\"%s\"", buf);
+ err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+ if (err) {
+ errno = -err;
+ SYSERROR("Failed to setup ipv6 gateway for network device \"%s\"",
+ ifname);
+
+ if (netdev->ipv6_gateway_auto) {
+ char buf[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
+ ERROR("Tried to set autodetected ipv6 "
+ "gateway for network device "
+ "\"%s\"", buf);
+ }
+ return -1;
}
- return -1;
}
}
}
* @ipv6 : a list of ipv6 addresses to be set on the network device
* @ipv4_gateway_auto : whether the ipv4 gateway is to be automatically gathered
* from the associated @link
+ * @ipv4_gateway_dev : whether the ipv4 gateway is to be set as a device route
* @ipv4_gateway : ipv4 gateway
* @ipv6_gateway_auto : whether the ipv6 gateway is to be automatically gathered
* from the associated @link
+ * @ipv6_gateway_dev : whether the ipv6 gateway is to be set as a device route
* @ipv6_gateway : ipv6 gateway
* @upscript : a script filename to be executed during interface
* configuration
struct lxc_list ipv4;
struct lxc_list ipv6;
bool ipv4_gateway_auto;
+ bool ipv4_gateway_dev;
struct in_addr *ipv4_gateway;
bool ipv6_gateway_auto;
+ bool ipv6_gateway_dev;
struct in6_addr *ipv6_gateway;
char *upscript;
char *downscript;
return -1;
}
+ if (!c->set_config_item(c, "lxc.net.1.ipv4.gateway", "auto")) {
+ lxc_error("%s\n", "lxc.net.1.ipv4.gateway");
+ return -1;
+ }
+
+ if (!c->set_config_item(c, "lxc.net.1.ipv4.gateway", "dev")) {
+ lxc_error("%s\n", "lxc.net.1.ipv4.gateway");
+ return -1;
+ }
+
if (!c->set_config_item(c, "lxc.net.1.ipv6.address",
"2003:db8:1:0:214:1234:fe0b:3596/64")) {
lxc_error("%s\n", "lxc.net.1.ipv6.address");
return -1;
}
+ if (!c->set_config_item(c, "lxc.net.1.ipv6.gateway", "auto")) {
+ lxc_error("%s\n", "lxc.net.1.ipv6.gateway");
+ return -1;
+ }
+
+ if (!c->set_config_item(c, "lxc.net.1.ipv6.gateway", "dev")) {
+ lxc_error("%s\n", "lxc.net.1.ipv6.gateway");
+ return -1;
+ }
+
if (!c->set_config_item(c, "lxc.net.1.flags", "up")) {
lxc_error("%s\n", "lxc.net.1.flags");
return -1;
goto non_test_error;
}
+ if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv4.gateway", "auto", tmpf, true)) {
+ lxc_error("%s\n", "lxc.net.0.ipv4.gateway");
+ goto non_test_error;
+ }
+
+ if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv4.gateway", "dev", tmpf, true)) {
+ lxc_error("%s\n", "lxc.net.0.ipv4.gateway");
+ goto non_test_error;
+ }
+
if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv6.gateway", "2003:db8:1::1", tmpf, true)) {
lxc_error("%s\n", "lxc.net.0.ipv6.gateway");
goto non_test_error;
}
+ if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv6.gateway", "auto", tmpf, true)) {
+ lxc_error("%s\n", "lxc.net.0.ipv6.gateway");
+ goto non_test_error;
+ }
+
+ if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv6.gateway", "dev", tmpf, true)) {
+ lxc_error("%s\n", "lxc.net.0.ipv6.gateway");
+ goto non_test_error;
+ }
+
if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv4.address", "10.0.2.3/24", tmpf, true)) {
lxc_error("%s\n", "lxc.net.0.ipv4.address");
goto non_test_error;