qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 2/2] slirp: Add classless static routes support to D


From: Benjamin Drung
Subject: [Qemu-devel] [PATCH 2/2] slirp: Add classless static routes support to DHCP server
Date: Tue, 27 Feb 2018 17:06:02 +0100

This patch will allow the user to specify classless static routes for
the replies from the built-in DHCP server.

Signed-off-by: Benjamin Drung <address@hidden>
---
 net/slirp.c      | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 qapi/net.json    |  4 ++++
 qemu-options.hx  | 13 +++++++++++-
 slirp/bootp.c    | 23 ++++++++++++++++++++
 slirp/bootp.h    |  2 ++
 slirp/libslirp.h |  9 +++++++-
 slirp/slirp.c    |  7 +++++-
 slirp/slirp.h    |  2 ++
 8 files changed, 119 insertions(+), 6 deletions(-)

diff --git a/net/slirp.c b/net/slirp.c
index 8c08e5644f..78df361485 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -158,7 +158,7 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
                           const char *vnameserver, const char *vnameserver6,
                           const char *smb_export, const char *vsmbserver,
                           const char **dnssearch, const char *vdomainname,
-                          Error **errp)
+                          const StringList *vroutes, Error **errp)
 {
     /* default settings according to historic slirp */
     struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
@@ -177,8 +177,12 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
     char buf[20];
     uint32_t addr;
     int shift;
+    int i = 0;
     char *end;
+    unsigned int route_count = 0;
     struct slirp_config_str *config;
+    struct StaticRoute *routes = NULL;
+    const StringList *iter;
 
     if (!ipv4 && (vnetwork || vhost || vnameserver)) {
         error_setg(errp, "IPv4 disabled but netmask/host/dns provided");
@@ -365,6 +369,58 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
         return -1;
     }
 
+    iter = vroutes;
+    while (iter) {
+        route_count++;
+        iter = iter->next;
+    }
+    routes = g_malloc(route_count * sizeof(StaticRoute));
+
+    iter = vroutes;
+    while(iter != NULL) {
+        char buf2[20];
+        const char *gateway = iter->value->str;
+        const char *mask;
+        char *end;
+        long mask_width;
+
+        // Split "subnet/mask:gateway" into its components
+        if (get_str_sep(buf2, sizeof(buf2), &gateway, ':') < 0) {
+            error_setg(errp, "Failed to parse route: No colon found in '%s'",
+                       iter->value->str);
+            return -1;
+        }
+        mask = buf2;
+        if (get_str_sep(buf, sizeof(buf), &mask, '/') < 0) {
+            error_setg(errp, "Failed to parse route: No slash found in '%s'",
+                       mask);
+            return -1;
+        }
+        if (!inet_aton(buf, &routes[i].subnet)) {
+            error_setg(errp, "Failed to parse route subnet '%s'", buf);
+            return -1;
+        }
+
+        mask_width = strtol(mask, &end, 10);
+        if (*end != '\0') {
+            error_setg(errp,
+                       "Failed to parse netmask '%s' (trailing chars)", mask);
+            return -1;
+        } else if (mask_width < 0 || mask_width > 32) {
+            error_setg(errp,
+                       "Invalid netmask provided (must be in range 0-32)");
+            return -1;
+        }
+        routes[i].mask_width = (uint8_t)mask_width;
+
+        if (!inet_aton(gateway, &routes[i].gateway)) {
+            error_setg(errp, "Failed to parse route gateway '%s'", gateway);
+            return -1;
+        }
+
+        iter = iter->next;
+        i++;
+    }
 
     nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
 
@@ -377,7 +433,8 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
     s->slirp = slirp_init(restricted, ipv4, net, mask, host,
                           ipv6, ip6_prefix, vprefix6_len, ip6_host,
                           vhostname, tftp_export, bootfile, dhcp,
-                          dns, ip6_dns, dnssearch, vdomainname, s);
+                          dns, ip6_dns, dnssearch, vdomainname,
+                          route_count, routes, s);
     QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
 
     for (config = slirp_configs; config; config = config->next) {
@@ -409,6 +466,7 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
     return 0;
 
 error:
+    g_free(routes);
     qemu_del_net_client(nc);
     return -1;
 }
@@ -964,7 +1022,8 @@ int net_init_slirp(const Netdev *netdev, const char *name,
                          user->ipv6_host, user->hostname, user->tftp,
                          user->bootfile, user->dhcpstart,
                          user->dns, user->ipv6_dns, user->smb,
-                         user->smbserver, dnssearch, user->domainname, errp);
+                         user->smbserver, dnssearch, user->domainname,
+                         user->route, errp);
 
     while (slirp_configs) {
         config = slirp_configs;
diff --git a/qapi/net.json b/qapi/net.json
index 9dfd34cafa..8a85debd92 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -163,6 +163,9 @@
 # @domainname: guest-visible domain name of the virtual nameserver
 #              (since 2.12)
 #
+# @route: guest-visible static classless route of the virtual nameserver
+#         (since 2.12)
+#
 # @ipv6-prefix: IPv6 network prefix (default is fec0::) (since
 #               2.6). The network prefix is given in the usual
 #               hexadecimal IPv6 address notation.
@@ -201,6 +204,7 @@
     '*dns':       'str',
     '*dnssearch': ['String'],
     '*domainname': 'str',
+    '*route':     ['String'],
     '*ipv6-prefix':      'str',
     '*ipv6-prefixlen':   'int',
     '*ipv6-host':        'str',
diff --git a/qemu-options.hx b/qemu-options.hx
index c000ef454e..e4bb5919ab 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1907,7 +1907,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
     "         [,ipv6[=on|off]][,ipv6-net=addr[/int]][,ipv6-host=addr]\n"
     "         [,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
     "         
[,dns=addr][,ipv6-dns=addr][,dnssearch=domain][,domainname=domain]\n"
-    "         [,tftp=dir][,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
+    "         
[,route=addr/mask:gateway][,tftp=dir][,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
 #ifndef _WIN32
                                              "[,smb=dir[,smbserver=addr]]\n"
 #endif
@@ -2119,6 +2119,17 @@ qemu -net 
user,dnssearch=mgmt.example.org,dnssearch=example.org [...]
 @item address@hidden
 Specifies the client domain name reported by the built-in DHCP server.
 
address@hidden address@hidden/@var{mask}:@var{gateway}
+Provides an entry for the classless static routes list sent by the built-in
+DHCP server. More than one route can be transmitted by specifying
+this option multiple times. If supported, this will cause the guest to
+automatically set the given static routes instead of the given default gateway.
+
+Example:
address@hidden
+qemu -net user,route=10.0.2.0/24:10.0.2.2,route=192.168.0.0/16:10.0.2.2 [...]
address@hidden example
+
 @item address@hidden
 When using the user mode network stack, activate a built-in TFTP
 server. The files in @var{dir} will be exposed as the root of a TFTP server.
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 9e7b53ba94..a694a43189 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -306,6 +306,29 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t 
*bp)
             q += val;
         }
 
+        if (slirp->route_count > 0) {
+            uint8_t option_length = 0;
+            uint8_t significant_octets;
+
+            for (int i = 0; i < slirp->route_count; i++) {
+                significant_octets = slirp->routes[i].mask_width / 8
+                                     + (slirp->routes[i].mask_width % 8 > 0);
+                option_length += significant_octets + 5;
+            }
+
+            *q++ = RFC3442_CLASSLESS_STATIC_ROUTE;
+            *q++ = option_length;
+            for (int i = 0; i < slirp->route_count; i++) {
+                significant_octets = slirp->routes[i].mask_width / 8
+                                     + (slirp->routes[i].mask_width % 8 > 0);
+                *q++ = slirp->routes[i].mask_width;
+                memcpy(q, &slirp->routes[i].subnet.s_addr, significant_octets);
+                q += significant_octets;
+                memcpy(q, &slirp->routes[i].gateway.s_addr, 4);
+                q += 4;
+            }
+        }
+
         if (slirp->vdnssearch) {
             size_t spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend);
             val = slirp->vdnssearch_len;
diff --git a/slirp/bootp.h b/slirp/bootp.h
index 394525733e..60bef4e80d 100644
--- a/slirp/bootp.h
+++ b/slirp/bootp.h
@@ -71,6 +71,8 @@
 #define RFC2132_RENEWAL_TIME    58
 #define RFC2132_REBIND_TIME     59
 
+#define RFC3442_CLASSLESS_STATIC_ROUTE 121
+
 #define DHCPDISCOVER           1
 #define DHCPOFFER              2
 #define DHCPREQUEST            3
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 740408a96e..3d2e395b08 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -5,6 +5,12 @@
 
 typedef struct Slirp Slirp;
 
+typedef struct StaticRoute {
+    struct in_addr subnet;
+    uint8_t mask_width;
+    struct in_addr gateway;
+} StaticRoute;
+
 int get_dns_addr(struct in_addr *pdns_addr);
 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
 
@@ -16,7 +22,8 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct 
in_addr vnetwork,
                   const char *tftp_path, const char *bootfile,
                   struct in_addr vdhcp_start, struct in_addr vnameserver,
                   struct in6_addr vnameserver6, const char **vdnssearch,
-                  const char *vdomainname, void *opaque);
+                  const char *vdomainname, unsigned int routes_count,
+                  const StaticRoute *vroutes, void *opaque);
 void slirp_cleanup(Slirp *slirp);
 
 void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout);
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 4f29753444..4e5f249eeb 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -286,7 +286,8 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct 
in_addr vnetwork,
                   const char *tftp_path, const char *bootfile,
                   struct in_addr vdhcp_start, struct in_addr vnameserver,
                   struct in6_addr vnameserver6, const char **vdnssearch,
-                  const char *vdomainname, void *opaque)
+                  const char *vdomainname, unsigned int route_count,
+                  const StaticRoute *vroutes, void *opaque)
 {
     Slirp *slirp = g_malloc0(sizeof(Slirp));
 
@@ -321,6 +322,9 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct 
in_addr vnetwork,
     slirp->vdhcp_startaddr = vdhcp_start;
     slirp->vnameserver_addr = vnameserver;
     slirp->vnameserver_addr6 = vnameserver6;
+    slirp->route_count = route_count;
+    slirp->routes = g_malloc(route_count * sizeof(StaticRoute));
+    memcpy(slirp->routes, vroutes, route_count * sizeof(StaticRoute));
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
@@ -351,6 +355,7 @@ void slirp_cleanup(Slirp *slirp)
     g_free(slirp->tftp_prefix);
     g_free(slirp->bootp_filename);
     g_free(slirp->vdomainname);
+    g_free(slirp->routes);
     g_free(slirp);
 }
 
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 10b410898a..3c81b7f7cc 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -194,6 +194,8 @@ struct Slirp {
     size_t vdnssearch_len;
     uint8_t *vdnssearch;
     char *vdomainname;
+    unsigned int route_count;
+    struct StaticRoute *routes;
 
     /* tcp states */
     struct socket tcb;
-- 
2.14.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]