]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf/util: fix non-specification of IP route destination address
authorLaine Stump <laine@redhat.com>
Tue, 24 Feb 2026 07:14:38 +0000 (02:14 -0500)
committerLaine Stump <laine@redhat.com>
Mon, 9 Mar 2026 05:14:55 +0000 (01:14 -0400)
The Linux/libnl version of virNetDevIPRouteAdd() has always had code
that would use "0.0.0.0" (or "::" for IPv6) for the route's
destination address if none was specified, but 1) our validation code
has always required it to be specified anyway, 2) the FreeBSD version
of virnertDevIPRouteAdd() expected that it would be specified, and 3)
virNetDevIPRouteFormat() also expected route->address to be
valid. This patch fixes those 3 deficiencies, so that this XML now
works:

   <route gateway='1.2.3.4'/>

i.e. it is the same as:

   <route address='0.0.0.0' prefix='0' gateway='1.2.3.4'/>

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
docs/formatnetwork.rst
src/conf/networkcommon_conf.c
src/conf/schemas/networkcommon.rng
src/util/virnetdevip.c

index 12468c276e088209d42635f13e55d3d063d5a03b..e57feebc12b15ea5ab8975a1226e10cd141ee47b 100644 (file)
@@ -664,6 +664,12 @@ network is running, the configuration for the system-defined route should be
 modified to have a higher metric, and the route on the virtual network given a
 lower metric (for example, the default metric of "1").
 
+Only the ``gateway`` attribute is mandatory for a ``route``
+element. If ``address`` is unspecified, it is assumed to be "0.0.0.0"
+(or "::" for IPv6), and if neither prefix nor netmask is specified, a
+prefix of "0" is assumed (thus, a ``route`` with only gateway is
+essentially specifying the "default route").
+
 ::
 
    ...
index 6f88d173c6cfd5f03cf47c8824ed60169038dcd8..bfa58a26a8440a0b5413013149065ca0f12d9f3d 100644 (file)
@@ -50,15 +50,6 @@ virNetDevIPRouteCreate(const char *errorDetail,
     def->metric = metric;
     def->has_metric = hasMetric;
 
-    /* Note: both network and gateway addresses must be specified */
-
-    if (!address) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("%1$s: Missing required address attribute in route definition"),
-                       errorDetail);
-        return NULL;
-    }
-
     if (!gateway) {
         virReportError(VIR_ERR_XML_ERROR,
                        _("%1$s: Missing required gateway attribute in route definition"),
@@ -66,17 +57,17 @@ virNetDevIPRouteCreate(const char *errorDetail,
         return NULL;
     }
 
-    if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
+    if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
         virReportError(VIR_ERR_XML_ERROR,
-                       _("%1$s: Bad network address '%2$s' in route definition"),
-                       errorDetail, address);
+                       _("%1$s: Bad gateway address '%2$s' in route definition"),
+                       errorDetail, gateway);
         return NULL;
     }
 
-    if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
+    if (address && virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
         virReportError(VIR_ERR_XML_ERROR,
-                       _("%1$s: Bad gateway address '%2$s' in route definition"),
-                       errorDetail, gateway);
+                       _("%1$s: Bad network address '%2$s' in route definition"),
+                       errorDetail, address);
         return NULL;
     }
 
@@ -127,7 +118,8 @@ virNetDevIPRouteCreate(const char *errorDetail,
             return NULL;
         }
     } else if (STREQ(def->family, "ipv6")) {
-        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+        if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6) ||
+              VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
             virReportError(VIR_ERR_XML_ERROR,
                            _("%1$s: ipv6 family specified for non-IPv6 address '%2$s' in route definition"),
                            errorDetail, address);
@@ -158,29 +150,32 @@ virNetDevIPRouteCreate(const char *errorDetail,
         return NULL;
     }
 
-    /* make sure the address is a network address */
-    if (netmask) {
-        if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("%1$s: Error converting address '%2$s' with netmask '%3$s' to network-address in route definition"),
-                           errorDetail, address, netmask);
-            return NULL;
+    if (address) {
+        /* make sure the address is a network address */
+
+        if (netmask) {
+            if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("%1$s: Error converting address '%2$s' with netmask '%3$s' to network-address in route definition"),
+                               errorDetail, address, netmask);
+                return NULL;
+            }
+        } else {
+            if (virSocketAddrMaskByPrefix(&def->address,
+                                          def->prefix, &testAddr) < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("%1$s: Error converting address '%2$s' with prefix %3$u to network-address in route definition"),
+                               errorDetail, address, def->prefix);
+                return NULL;
+            }
         }
-    } else {
-        if (virSocketAddrMaskByPrefix(&def->address,
-                                      def->prefix, &testAddr) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("%1$s: Error converting address '%2$s' with prefix %3$u to network-address in route definition"),
-                           errorDetail, address, def->prefix);
+        if (!virSocketAddrEqual(&def->address, &testAddr)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%1$s: Address '%2$s' in route definition is not a network address"),
+                           errorDetail, address);
             return NULL;
         }
     }
-    if (!virSocketAddrEqual(&def->address, &testAddr)) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("%1$s: Address '%2$s' in route definition is not a network address"),
-                       errorDetail, address);
-        return NULL;
-    }
 
     return g_steal_pointer(&def);
 }
@@ -229,10 +224,11 @@ virNetDevIPRouteFormat(virBuffer *buf,
     if (def->family)
         virBufferAsprintf(buf, " family='%s'", def->family);
 
-    if (!(address = virSocketAddrFormat(&def->address)))
-        return -1;
-    virBufferAsprintf(buf, " address='%s'", address);
-
+    if (VIR_SOCKET_ADDR_VALID(&def->address)) {
+        if (!(address = virSocketAddrFormat(&def->address)))
+            return -1;
+        virBufferAsprintf(buf, " address='%s'", address);
+    }
     if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
         if (!(netmask = virSocketAddrFormat(&def->netmask)))
             return -1;
index 28424f9abdd71f02bb94b815497f0276589fa716..49149a3d4b8bb5e5609844d6250f0002c899cb56 100644 (file)
       <optional>
         <attribute name="family"><ref name="addr-family"/></attribute>
       </optional>
-      <attribute name="address"><ref name="ipAddr"/></attribute>
+      <optional>
+        <attribute name="address"><ref name="ipAddr"/></attribute>
+      </optional>
       <optional>
         <choice>
           <attribute name="netmask"><ref name="ipv4Addr"/></attribute>
index 5ffd2bf3983e7aea5a694b4779c3625134dd379f..8786bb236e773ec8003a0fa4364e789d39b15c35 100644 (file)
@@ -465,8 +465,16 @@ virNetDevIPRouteAdd(const char *ifname,
     g_autofree char *addrstr = NULL;
     g_autofree char *gatewaystr = NULL;
 
-    if (!(addrstr = virSocketAddrFormat(addr)))
-        return -1;
+    if (VIR_SOCKET_ADDR_VALID(addr)) {
+        if (!(addrstr = virSocketAddrFormat(addr)))
+            return -1;
+    } else {
+        if (VIR_SOCKET_ADDR_IS_FAMILY(gateway, AF_INET6))
+            addrstr = g_strdup(VIR_SOCKET_ADDR_IPV6_ALL);
+        else
+            addrstr = g_strdup(VIR_SOCKET_ADDR_IPV4_ALL);
+    }
+
     if (!(gatewaystr = virSocketAddrFormat(gateway)))
         return -1;
     cmd = virCommandNew("ip");