]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
network: Adds gateway device route mode 2973/head
authortomponline <thomas.parrott@canonical.com>
Fri, 3 May 2019 09:21:45 +0000 (10:21 +0100)
committertomponline <thomas.parrott@canonical.com>
Fri, 3 May 2019 14:08:49 +0000 (15:08 +0100)
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>
doc/api-extensions.md
doc/lxc.container.conf.sgml.in
src/lxc/api_extensions.h
src/lxc/confile.c
src/lxc/confile_utils.c
src/lxc/network.c
src/lxc/network.h
src/tests/parse_config_file.c

index b55acf0fb05e9ef1a7b05d6fa91751e4ff7b4a9b..a013935f72f4b04c7e69c440dfa64c126d535eb0 100644 (file)
@@ -84,3 +84,10 @@ For IPv6 addresses it will check the following sysctl values and fail with an er
 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.
index f8182567a53143899913d0ae90c4406308c47941..0af0456a5addc8510d77acf3c3fa1726b0bea315 100644 (file)
@@ -665,6 +665,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
               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>
@@ -699,6 +702,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
               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>
index 1c748a1d4a19e7f5179c3e968c4682bd3663ebc9..44293db970ea0fec036e7b304d2f305d16a4c766 100644 (file)
@@ -47,6 +47,7 @@ static char *api_extensions[] = {
        "network_veth_routes",
        "network_ipvlan",
        "network_l2proxy",
+       "network_gateway_device_route",
 };
 
 static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
index 78cb88e4fad04629271c2603dcfd9411d53d2f62..bb1edc7cb904eb641d8caaba96c9d107251f3bdf 100644 (file)
@@ -686,9 +686,13 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
 
        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;
@@ -853,9 +857,13 @@ static int set_config_net_ipv6_gateway(const char *key, const char *value,
 
        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;
@@ -5625,6 +5633,8 @@ static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
 
        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);
@@ -5714,6 +5724,8 @@ static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
 
        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);
index 07b023e4e76b5552199f14b2711f338145c27674..4394458854066cbf5ba100342861b1560cd28af2 100644 (file)
@@ -361,6 +361,9 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                        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));
@@ -377,6 +380,9 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                        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));
index a71eb5ddffb7f350f2bc6021d8548ad737eddf7a..2553c0c720844b00ce9d50f94f56dc1abfe78cb8 100644 (file)
@@ -2063,8 +2063,12 @@ static int ip_gateway_add(int family, int ifindex, void *gw)
        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.
@@ -3381,12 +3385,12 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
        }
 
        /* 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);
@@ -3399,33 +3403,43 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
                        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);
@@ -3438,29 +3452,39 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
                        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;
                        }
                }
        }
index 468593f5e3a0938e2318d659a78fb5a124e76bd2..d221b255f209c893ea9aec830a81c28c3a9c5f50 100644 (file)
@@ -156,9 +156,11 @@ union netdev_p {
  * @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
@@ -179,8 +181,10 @@ struct lxc_netdev {
        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;
index ad17867b43a8cc94bc6e2a93a44ebdd4d7e0fd93..bc68ae24cca81ed9ebfeb7bd7a77fa064bb68fdd 100644 (file)
@@ -108,6 +108,16 @@ static int set_and_clear_complete_netdev(struct lxc_container *c)
                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");
@@ -120,6 +130,16 @@ static int set_and_clear_complete_netdev(struct lxc_container *c)
                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;
@@ -781,11 +801,31 @@ int main(int argc, char *argv[])
                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;