[PATCH 6/6] qemu: support setting default route for passt interfaces inside the guest

Laine Stump via Devel posted 6 patches 6 days, 19 hours ago
[PATCH 6/6] qemu: support setting default route for passt interfaces inside the guest
Posted by Laine Stump via Devel 6 days, 19 hours ago
From: Laine Stump <laine@redhat.com>

libvirt's <interface> element has for a long time supported adding
<route> sub-elements to specify arbitrary routes to be added to the
guest OS networking, but historically this has only worked for LXC
guests. If you tried to add <route> to the interface of a QEMU guest,
it would be rejected.

passt networking doesn't support setting *any arbitrary* route but it
does support setting a default route (using the passt commandline
"--gateway" parameter). A default route is really just a "route with
unspecified destination/prefix", so a default route can be specified
in libvirt XML with:

   <route gateway='192.168.0.1'/>

Attempts to give a specified destination, prefix, or metric will
result in a validation error.

Resolves: https://issues.redhat.com/browse/RHEL-46602
Signed-off-by: Laine Stump <laine@redhat.com>
---
 src/qemu/qemu_passt.c    | 16 +++++++++++++
 src/qemu/qemu_validate.c | 50 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c
index 56d048d585..125227747d 100644
--- a/src/qemu/qemu_passt.c
+++ b/src/qemu/qemu_passt.c
@@ -263,6 +263,22 @@ qemuPasstBuildCommand(char **socketName,
         }
     }
 
+    /* Add default route(s) */
+    for (i = 0; i < net->guestIP.nroutes; i++) {
+        const virNetDevIPRoute *route = net->guestIP.routes[i];
+        g_autofree char *gateway = NULL;
+
+        if (!(gateway = virSocketAddrFormat(&route->gateway)))
+            return NULL;
+
+        /* validation has already guaranteed that there is at most 1
+         * IPv4 and 1 IPv6 route, and that they are only default
+         * routes (i.e. destination 0.0.0.0/0)
+         */
+
+        virCommandAddArgList(cmd, "--gateway", gateway, NULL);
+    }
+
     /* Add port forwarding info */
 
     for (i = 0; i < net->nPortForwards; i++) {
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 1c6662751b..c194a8a7cd 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -1884,6 +1884,8 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
 {
     bool hasV4Addr = false;
     bool hasV6Addr = false;
+    bool hasV4Route = false;
+    bool hasV6Route = false;
     size_t i;
 
     if (net->type == VIR_DOMAIN_NET_TYPE_USER ||
@@ -1958,10 +1960,50 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
         }
     }
 
-    if (net->guestIP.nroutes) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Invalid attempt to set network interface guest-side IP route, not supported by QEMU"));
-        return -1;
+
+    for (i = 0; i < net->guestIP.nroutes; i++) {
+        const virNetDevIPRoute *route = net->guestIP.routes[i];
+
+        if (net->backend.type != VIR_DOMAIN_NET_BACKEND_PASST) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("Invalid attempt to set network interface guest-side IP route, not supported for this interface type/backend"));
+            return -1;
+        }
+
+        switch (VIR_SOCKET_ADDR_FAMILY(&route->gateway)) {
+        case AF_INET:
+            if (hasV4Route) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("only one IPv4 default route can be specified for an interface using the passt backend"));
+                return -1;
+            }
+            hasV4Route = true;
+            break;
+        case AF_INET6:
+            if (hasV6Route) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("only one IPv6 default route can be specified for an interface using the passt backend"));
+                return -1;
+            }
+            hasV6Route = true;
+            break;
+        default:
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("All <route> elements of an interface using the passt backend must be default routes, with an IPv4 or IPv6 gateway specified"));
+            return -1;
+        }
+
+        /* the only type of route that can be specified for passt is
+         * the default route, so none of the parameters except gateway
+         * are acceptable
+         */
+        if (VIR_SOCKET_ADDR_VALID(&route->address) ||
+            virNetDevIPRouteGetPrefix(route) != 0 ||
+            route->has_metric) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("<route> elements of an interface using the passt backend must be default routes, with only a gateway specified"));
+            return -1;
+        }
     }
 
     if (net->type == VIR_DOMAIN_NET_TYPE_VDPA) {
-- 
2.52.0
Re: [PATCH 6/6] qemu: support setting default route for passt interfaces inside the guest
Posted by Michal Prívozník via Devel 6 days, 13 hours ago
On 2/24/26 08:52, Laine Stump via Devel wrote:
> From: Laine Stump <laine@redhat.com>
> 
> libvirt's <interface> element has for a long time supported adding
> <route> sub-elements to specify arbitrary routes to be added to the
> guest OS networking, but historically this has only worked for LXC
> guests. If you tried to add <route> to the interface of a QEMU guest,
> it would be rejected.
> 
> passt networking doesn't support setting *any arbitrary* route but it
> does support setting a default route (using the passt commandline
> "--gateway" parameter). A default route is really just a "route with
> unspecified destination/prefix", so a default route can be specified
> in libvirt XML with:
> 
>    <route gateway='192.168.0.1'/>
> 
> Attempts to give a specified destination, prefix, or metric will
> result in a validation error.
> 
> Resolves: https://issues.redhat.com/browse/RHEL-46602
> Signed-off-by: Laine Stump <laine@redhat.com>
> ---
>  src/qemu/qemu_passt.c    | 16 +++++++++++++
>  src/qemu/qemu_validate.c | 50 ++++++++++++++++++++++++++++++++++++----
>  2 files changed, 62 insertions(+), 4 deletions(-)
> 

Please, squash in the following:

diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args
index b0f26d8089..182d8ae054 100644
--- i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args
+++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args
@@ -9,6 +9,7 @@ passt \
 --address 172.17.2.0 \
 --netmask 24 \
 --address 2001:db8:ac10:fd01::feed \
+--gateway 192.168.0.1 \
 --tcp-ports '2001:db8:ac10:fd01::1:10/22:2022,1000-1050,~1020,~1030-1040' \
 --udp-ports '1.2.3.4%eth0/5000-5020:6000-6020,~5010-5015' \
 --tcp-ports 80 \
diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
index 77da297936..ecad9a40b5 100644
--- i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
+++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
@@ -33,6 +33,7 @@
       <source dev='eth42'/>
       <ip address='172.17.2.0' family='ipv4' prefix='24'/>
       <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
+      <route gateway='192.168.0.1'/>
       <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
         <range start='22' to='2022'/>
         <range start='1000' end='1050'/>
diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args
index b0f26d8089..182d8ae054 100644
--- i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args
+++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args
@@ -9,6 +9,7 @@ passt \
 --address 172.17.2.0 \
 --netmask 24 \
 --address 2001:db8:ac10:fd01::feed \
+--gateway 192.168.0.1 \
 --tcp-ports '2001:db8:ac10:fd01::1:10/22:2022,1000-1050,~1020,~1030-1040' \
 --udp-ports '1.2.3.4%eth0/5000-5020:6000-6020,~5010-5015' \
 --tcp-ports 80 \
diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
index 917a9edaa0..fc5a5e37aa 100644
--- i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
+++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
@@ -33,6 +33,7 @@
       <source dev='eth42'/>
       <ip address='172.17.2.0' family='ipv4' prefix='24'/>
       <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
+      <route gateway='192.168.0.1'/>
       <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
         <range start='22' to='2022'/>
         <range start='1000' end='1050'/>
diff --git i/tests/qemuxmlconfdata/net-user-passt.xml w/tests/qemuxmlconfdata/net-user-passt.xml
index 80d15de2ed..3edad133aa 100644
--- i/tests/qemuxmlconfdata/net-user-passt.xml
+++ w/tests/qemuxmlconfdata/net-user-passt.xml
@@ -30,6 +30,7 @@
       <source dev='eth42'/>
       <ip address='172.17.2.0' family='ipv4' prefix='24'/>
       <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
+      <route gateway='192.168.0.1'/>
       <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
         <range start='22' to='2022'/>
         <range start='1000' end='1050'/>

Michal
Re: [PATCH 6/6] qemu: support setting default route for passt interfaces inside the guest
Posted by Laine Stump via Devel 6 days, 5 hours ago
On 2/24/26 8:12 AM, Michal Prívozník via Devel wrote:
> On 2/24/26 08:52, Laine Stump via Devel wrote:
>> From: Laine Stump <laine@redhat.com>
>>
>> libvirt's <interface> element has for a long time supported adding
>> <route> sub-elements to specify arbitrary routes to be added to the
>> guest OS networking, but historically this has only worked for LXC
>> guests. If you tried to add <route> to the interface of a QEMU guest,
>> it would be rejected.
>>
>> passt networking doesn't support setting *any arbitrary* route but it
>> does support setting a default route (using the passt commandline
>> "--gateway" parameter). A default route is really just a "route with
>> unspecified destination/prefix", so a default route can be specified
>> in libvirt XML with:
>>
>>     <route gateway='192.168.0.1'/>
>>
>> Attempts to give a specified destination, prefix, or metric will
>> result in a validation error.
>>
>> Resolves: https://issues.redhat.com/browse/RHEL-46602
>> Signed-off-by: Laine Stump <laine@redhat.com>
>> ---
>>   src/qemu/qemu_passt.c    | 16 +++++++++++++
>>   src/qemu/qemu_validate.c | 50 ++++++++++++++++++++++++++++++++++++----
>>   2 files changed, 62 insertions(+), 4 deletions(-)
>>
> 
> Please, squash in the following:

This (forgetting to add docs and a test case) is what happens when I 
post something at 3AM just so I can get it out of my hair! :-). I'll do 
you one better - I'll make one of the cases add an IPv6 default route.

> 
> diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args
> index b0f26d8089..182d8ae054 100644
> --- i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args
> +++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.passt0.args
> @@ -9,6 +9,7 @@ passt \
>   --address 172.17.2.0 \
>   --netmask 24 \
>   --address 2001:db8:ac10:fd01::feed \
> +--gateway 192.168.0.1 \
>   --tcp-ports '2001:db8:ac10:fd01::1:10/22:2022,1000-1050,~1020,~1030-1040' \
>   --udp-ports '1.2.3.4%eth0/5000-5020:6000-6020,~5010-5015' \
>   --tcp-ports 80 \
> diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
> index 77da297936..ecad9a40b5 100644
> --- i/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
> +++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-7.2.0.xml
> @@ -33,6 +33,7 @@
>         <source dev='eth42'/>
>         <ip address='172.17.2.0' family='ipv4' prefix='24'/>
>         <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
> +      <route gateway='192.168.0.1'/>
>         <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
>           <range start='22' to='2022'/>
>           <range start='1000' end='1050'/>
> diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args
> index b0f26d8089..182d8ae054 100644
> --- i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args
> +++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.passt0.args
> @@ -9,6 +9,7 @@ passt \
>   --address 172.17.2.0 \
>   --netmask 24 \
>   --address 2001:db8:ac10:fd01::feed \
> +--gateway 192.168.0.1 \
>   --tcp-ports '2001:db8:ac10:fd01::1:10/22:2022,1000-1050,~1020,~1030-1040' \
>   --udp-ports '1.2.3.4%eth0/5000-5020:6000-6020,~5010-5015' \
>   --tcp-ports 80 \
> diff --git i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
> index 917a9edaa0..fc5a5e37aa 100644
> --- i/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
> +++ w/tests/qemuxmlconfdata/net-user-passt.x86_64-latest.xml
> @@ -33,6 +33,7 @@
>         <source dev='eth42'/>
>         <ip address='172.17.2.0' family='ipv4' prefix='24'/>
>         <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
> +      <route gateway='192.168.0.1'/>
>         <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
>           <range start='22' to='2022'/>
>           <range start='1000' end='1050'/>
> diff --git i/tests/qemuxmlconfdata/net-user-passt.xml w/tests/qemuxmlconfdata/net-user-passt.xml
> index 80d15de2ed..3edad133aa 100644
> --- i/tests/qemuxmlconfdata/net-user-passt.xml
> +++ w/tests/qemuxmlconfdata/net-user-passt.xml
> @@ -30,6 +30,7 @@
>         <source dev='eth42'/>
>         <ip address='172.17.2.0' family='ipv4' prefix='24'/>
>         <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
> +      <route gateway='192.168.0.1'/>
>         <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
>           <range start='22' to='2022'/>
>           <range start='1000' end='1050'/>
> 
> Michal
>