From mboxrd@z Thu Jan 1 00:00:00 1970 Received: by passt.top (Postfix, from userid 1000) id E49195A0269; Sat, 18 Jul 2026 09:42:25 +0200 (CEST) From: Stefano Brivio To: passt-dev@passt.top Subject: [PATCH] treewide: Sandbox qrap Date: Sat, 18 Jul 2026 09:42:25 +0200 Message-ID: <20260718074225.1331134-1-sbrivio@redhat.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: MAS6EUD7XYRHQKV3A56NPYUYJFI4V4P5 X-Message-ID-Hash: MAS6EUD7XYRHQKV3A56NPYUYJFI4V4P5 X-MailFrom: sbrivio@passt.top X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson , Andrea Bolognani X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: No sunsetting or rightsizing for you, qrap: dig, bury, and cover. Signed-off-by: Stefano Brivio --- .gitignore | 1 - Makefile | 11 +- README.md | 4 - contrib/fedora/passt.spec | 2 - doc/demo.sh | 12 +- doc/passt_overview.excalidraw | 29 --- hooks/pre-push | 2 +- passt.1 | 235 ++++++++++--------- qrap.1 | 77 ------ qrap.c | 429 ---------------------------------- tap.c | 2 - test/distro/opensuse | 2 +- 12 files changed, 127 insertions(+), 679 deletions(-) delete mode 100644 qrap.1 delete mode 100644 qrap.c diff --git a/.gitignore b/.gitignore index 3e40d9f..71420b6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ /pasta.avx2 /passt-repair /pesto -/qrap /pasta.1 /seccomp.h /seccomp_pesto.h diff --git a/Makefile b/Makefile index 5757aef..77474d6 100644 --- a/Makefile +++ b/Makefile @@ -39,13 +39,12 @@ PASST_SRCS = arch.c arp.c bitmap.c checksum.c conf.c dhcp.c dhcpv6.c \ parse.c passt.c pasta.c pcap.c pif.c repair.c serialise.c tap.c tcp.c \ tcp_buf.c tcp_splice.c tcp_vu.c udp.c udp_flow.c udp_vu.c util.c \ vhost_user.c virtio.c vu_common.c -QRAP_SRCS = qrap.c PASST_REPAIR_SRCS = passt-repair.c PESTO_SRCS = pesto.c bitmap.c fwd_rule.c inany.c ip.c lineread.c parse.c \ serialise.c -SRCS = $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS) +SRCS = $(PASST_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS) -MANPAGES = passt.1 pasta.1 pesto.1 qrap.1 passt-repair.1 +MANPAGES = passt.1 pasta.1 pesto.1 passt-repair.1 PASST_HEADERS = arch.h arp.h bitmap.h checksum.h conf.h dhcp.h dhcpv6.h \ epoll_ctl.h flow.h fwd.h fwd_rule.h flow_table.h icmp.h icmp_flow.h \ @@ -54,7 +53,6 @@ PASST_HEADERS = arch.h arp.h bitmap.h checksum.h conf.h dhcp.h dhcpv6.h \ serialise.h siphash.h tap.h tcp.h tcp_buf.h tcp_conn.h tcp_internal.h \ tcp_splice.h tcp_vu.h udp.h udp_flow.h udp_internal.h udp_vu.h util.h \ vhost_user.h virtio.h vu_common.h -QRAP_HEADERS = arp.h ip.h passt.h util.h PASST_REPAIR_HEADERS = linux_dep.h PESTO_HEADERS = bitmap.h common.h fwd_rule.h inany.h ip.h log.h parse.h \ pesto.h serialise.h @@ -76,7 +74,7 @@ docdir ?= $(datarootdir)/doc/passt mandir ?= $(datarootdir)/man man1dir ?= $(mandir)/man1 -BASEBIN := passt qrap passt-repair pesto +BASEBIN := passt passt-repair pesto ifeq ($(TARGET_ARCH),x86_64) BASEBIN += passt.avx2 endif @@ -112,9 +110,6 @@ passt.avx2: $(PASST_SRCS) $(PASST_HEADERS) seccomp.h pasta.avx2 pasta.1 pasta: pasta%: passt% ln -sf $< $@ -qrap: BASE_CPPFLAGS += -DARCH=\"$(TARGET_ARCH)\" -qrap: $(QRAP_SRCS) $(QRAP_HEADERS) - passt-repair: $(PASST_REPAIR_SRCS) $(PASST_REPAIR_HEADERS) seccomp_repair.h pesto: BASE_CPPFLAGS += -DPESTO diff --git a/README.md b/README.md index 8fdc0a3..43caf49 100644 --- a/README.md +++ b/README.md @@ -376,10 +376,6 @@ speeding up local connections, and usually requiring NAT. _pasta_: _passt_ exchanges packets with _qemu_ via UNIX domain socket, using the `socket` back-end in qemu. This is supported since qemu 7.2. -For older versions, the [qrap](/passt/tree/qrap.c) wrapper can be used to -connect to a UNIX domain socket and to start qemu, which can now use the file -descriptor that's already opened. - This approach, compared to using a _tap_ device, doesn't require any security capabilities, as we don't need to create any interface. diff --git a/contrib/fedora/passt.spec b/contrib/fedora/passt.spec index 34838af..6c7530a 100644 --- a/contrib/fedora/passt.spec +++ b/contrib/fedora/passt.spec @@ -118,12 +118,10 @@ fi %doc %{_docdir}/%{name}/demo.sh %{_bindir}/passt %{_bindir}/pasta -%{_bindir}/qrap %{_bindir}/passt-repair %{_bindir}/pesto %{_mandir}/man1/passt.1* %{_mandir}/man1/pasta.1* -%{_mandir}/man1/qrap.1* %{_mandir}/man1/passt-repair.1* %{_mandir}/man1/pesto.1* %ifarch x86_64 diff --git a/doc/demo.sh b/doc/demo.sh index 6b0917c..b56669f 100755 --- a/doc/demo.sh +++ b/doc/demo.sh @@ -177,7 +177,7 @@ into_ns() { next [ "${KEY}" = "s" ] && ${SHELL} - cmd passt -P "${DEMO_DIR}/passt.pid" + cmd passt -P "${DEMO_DIR}/passt.pid" -s "${DEMO_DIR}/passt.socket" echo echo "...passt is running." next @@ -198,15 +198,12 @@ into_ns() { echo "can download and use mbuto (https://mbuto.sh/) to build a" echo "basic initramfs image. Otherwise, press 's' to skip this" echo "step, and start an existing virtual machine yourself." - echo "You'll need to use the qrap(1) wrapper, with qemu options" - echo "as reported above." next else echo "This script doesn't know, yet, how to run a virtual" echo "machine on your architecture (${__arch}). Please start an" - echo "existing virtual machine yourself, using the qrap(1)" - echo "wrapper, with qemu options as reported above." + echo "existing virtual machine yourself." echo fi @@ -225,12 +222,13 @@ into_ns() { next # shellcheck disable=SC2086 - cmd qrap 5 ${__qemu_arch} \ + cmd ${__qemu_arch} \ -smp "$(nproc)" -m 1024 \ -nographic -serial stdio -nodefaults -no-reboot -vga none \ -initrd "${DEMO_DIR}/demo.img" \ -kernel "/boot/vmlinuz-$(uname -r)" -append "console=ttyS0" \ - -net socket,fd=5 -net nic,model=virtio || : + -device virtio-net-pci,netdev=s \ + -netdev stream,id=s,server=off,addr.type=unix,addr.path="${DEMO_DIR}/passt.socket" || : } STTY_BACKUP="$(stty -g)" diff --git a/doc/passt_overview.excalidraw b/doc/passt_overview.excalidraw index 790728e..3217b3f 100644 --- a/doc/passt_overview.excalidraw +++ b/doc/passt_overview.excalidraw @@ -3595,35 +3595,6 @@ "baseline": 17, "textAlign": "left", "verticalAlign": "top" - }, - { - "type": "text", - "version": 1448, - "versionNonce": 1345391945, - "isDeleted": false, - "id": "c-esZiuHSm3wnTRlmIJZk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dotted", - "roughness": 1, - "opacity": 100, - "angle": 4.969352159599495, - "x": 816.7081559166961, - "y": 215.74807066759342, - "strokeColor": "#2b8a3e", - "backgroundColor": "transparent", - "width": 211, - "height": 23, - "seed": 939668423, - "groupIds": [], - "strokeSharpness": "round", - "boundElementIds": [], - "fontSize": 20, - "fontFamily": 1, - "text": "(currently \"qrap\" wrapper)", - "baseline": 17, - "textAlign": "left", - "verticalAlign": "top" } ], "appState": { diff --git a/hooks/pre-push b/hooks/pre-push index 3e2d15f..8eebdbc 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -54,7 +54,7 @@ done cd .. make pkgs -scp passt passt.avx2 passt.1 qrap qrap.1 "${USER_HOST}:${BIN}" +scp passt passt.avx2 passt.1 "${USER_HOST}:${BIN}" scp pasta pasta.avx2 pasta.1 "${USER_HOST}:${BIN}" scp passt-repair passt-repair.1 "${USER_HOST}:${BIN}" scp pesto pesto.1 "${USER_HOST}:${BIN}" diff --git a/passt.1 b/passt.1 index 995590a..53e072a 100644 --- a/passt.1 +++ b/passt.1 @@ -580,8 +580,7 @@ Default is \fBnone\fR for \fBpasst\fR and \fBauto\fR for \fBpasta\fR. .TP .BR \-s ", " \-\-socket-path ", " \-\-socket " " \fIpath -Path for UNIX domain socket used by \fBqemu\fR(1) or \fBqrap\fR(1) to connect to -\fBpasst\fR. +Path for UNIX domain socket used by \fBqemu\fR(1) to connect to \fBpasst\fR. Default is to probe a free socket, not accepting connections, starting from \fI/tmp/passt_1.socket\fR to \fI/tmp/passt_64.socket\fR. @@ -762,129 +761,132 @@ forwards loopback traffic between namespaces. .RS .nf $ iperf3 -s -D -$ ./pasta -Outbound interface: eth0, namespace interface: eth0 -ARP: - address: 28:16:ad:39:a9:ea -DHCP: - assign: 192.168.1.118 - mask: 255.255.255.0 - router: 192.168.1.1 -NDP/DHCPv6: - assign: 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17 - router: fe80::62e3:27ff:fe33:2b01 -# -# dhclient -4 --no-pid -# dhclient -6 --no-pid + +$ pasta --config-net + # ip address show 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever - inet6 ::1/128 scope host + inet6 ::1/128 scope host proto kernel_lo valid_lft forever preferred_lft forever -2: eth0: mtu 65520 qdisc pfifo_fast state UNKNOWN group default qlen 1000 - link/ether 5e:90:02:eb:b0:2a brd ff:ff:ff:ff:ff:ff - inet 192.168.1.118/24 brd 192.168.1.255 scope global eth0 +2: enp9s0: mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000 + link/ether be:16:49:5a:65:dc brd ff:ff:ff:ff:ff:ff + inet 88.198.0.164/27 brd 88.198.0.191 scope global noprefixroute enp9s0 valid_lft forever preferred_lft forever - inet6 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17/128 scope global + inet6 2a01:4f8:222:904::2/64 scope global nodad valid_lft forever preferred_lft forever - inet6 2a02:6d40:3ca5:2001:5c90:2ff:feeb:b02a/64 scope global dynamic mngtmpaddr - valid_lft 3591sec preferred_lft 3591sec - inet6 fe80::5c90:2ff:feeb:b02a/64 scope link + inet6 fe80::bc16:49ff:fe5a:65dc/64 scope link nodad proto kernel_ll valid_lft forever preferred_lft forever + # ip route show -default via 192.168.1.1 dev eth0 -192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.118 +default via 88.198.0.161 dev enp9s0 proto dhcp metric 1002 +88.198.0.160/27 dev enp9s0 proto dhcp scope link metric 1002 + # ip -6 route show -2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17 dev eth0 proto kernel metric 256 pref medium -2a02:6d40:3ca5:2001::/64 dev eth0 proto kernel metric 256 expires 3584sec pref medium -fe80::/64 dev eth0 proto kernel metric 256 pref medium -default via fe80::62e3:27ff:fe33:2b01 dev eth0 proto ra metric 1024 expires 3584sec pref medium +2a01:4f8:222:904::/64 dev enp9s0 proto kernel metric 256 pref medium +fe80::/64 dev enp9s0 proto kernel metric 256 pref medium +default via fe80::1 dev enp9s0 metric 1024 onlink pref medium + # iperf3 -c 127.0.0.1 -t1 Connecting to host 127.0.0.1, port 5201 -[ 5] local 127.0.0.1 port 51938 connected to 127.0.0.1 port 5201 +[ 5] local 127.0.0.1 port 59112 connected to 127.0.0.1 port 5201 [ ID] Interval Transfer Bitrate Retr Cwnd -[ 5] 0.00-1.00 sec 4.46 GBytes 38.3 Gbits/sec 0 3.93 MBytes +[ 5] 0.00-1.00 sec 3.89 GBytes 33.4 Gbits/sec 0 2.62 MBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate Retr -[ 5] 0.00-1.00 sec 4.46 GBytes 38.3 Gbits/sec 0 sender -[ 5] 0.00-1.41 sec 4.45 GBytes 27.1 Gbits/sec receiver +[ 5] 0.00-1.00 sec 3.89 GBytes 33.4 Gbits/sec 0 sender +[ 5] 0.00-1.00 sec 3.89 GBytes 33.4 Gbits/sec receiver iperf Done. + # iperf3 -c ::1 -t1 Connecting to host ::1, port 5201 -[ 5] local ::1 port 50108 connected to ::1 port 5201 +[ 5] local ::1 port 49138 connected to ::1 port 5201 [ ID] Interval Transfer Bitrate Retr Cwnd -[ 5] 0.00-1.00 sec 4.35 GBytes 37.4 Gbits/sec 0 4.99 MBytes +[ 5] 0.00-1.00 sec 4.32 GBytes 37.0 Gbits/sec 0 1.06 MBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate Retr -[ 5] 0.00-1.00 sec 4.35 GBytes 37.4 Gbits/sec 0 sender -[ 5] 0.00-1.41 sec 4.35 GBytes 26.4 Gbits/sec receiver +[ 5] 0.00-1.00 sec 4.32 GBytes 37.0 Gbits/sec 0 sender +[ 5] 0.00-1.00 sec 4.32 GBytes 37.0 Gbits/sec receiver iperf Done. -# ping -c1 -4 spaghetti.pizza -PING spaghetti.pizza (172.67.192.217) 56(84) bytes of data. -64 bytes from 172.67.192.217: icmp_seq=1 ttl=255 time=37.3 ms + +# ping -nc1 -4 spaghetti.pizza +PING spaghetti.pizza (5.161.47.86) 56(84) bytes of data. +64 bytes from 5.161.47.86: icmp_seq=1 ttl=255 time=99.4 ms --- spaghetti.pizza ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms -# ping -c1 -6 spaghetti.pizza -PING spaghetti.pizza(2606:4700:3034::6815:147a (2606:4700:3034::6815:147a)) 56 data bytes -64 bytes from 2606:4700:3034::6815:147a: icmp_seq=1 ttl=255 time=35.6 ms +rtt min/avg/max/mdev = 99.433/99.433/99.433/0.000 ms +# ping -nc1 -6 spaghetti.pizza +PING spaghetti.pizza (2a01:4f8:1c1e:d6f1::1) 56 data bytes +64 bytes from 2a01:4f8:1c1e:d6f1::1: icmp_seq=1 ttl=255 time=3.11 ms --- spaghetti.pizza ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms -rtt min/avg/max/mdev = 35.605/35.605/35.605/0.000 ms -# logout -$ - -.RE +rtt min/avg/max/mdev = 3.110/3.110/3.110/0.000 ms .fi +.RE .BR "Connect an existing user and network namespace" .RS .nf $ unshare -rUn -# echo $$ -2446678 +# echo $$ +1295969 .fi -.BR " [From another terminal]" + +.BR "[From another terminal]" .nf -$ ./pasta 2446678 -Outbound interface: eth0, namespace interface: eth0 -ARP: - address: 28:16:ad:39:a9:ea +$ pasta --config-net 1295969 +Template interface: enp9s0 (IPv4), enp9s0 (IPv6) +Namespace interface: enp9s0 +MAC: + host: 9a:55:9a:55:9a:55 + NAT to host 127.0.0.1: 88.198.0.161 DHCP: - assign: 192.168.1.118 - mask: 255.255.255.0 - router: 192.168.1.1 + assign: 88.198.0.164 + mask: 255.255.255.224 + router: 88.198.0.161 +DNS: + 185.12.64.1 + 185.12.64.2 + NAT to host ::1: fe80::1 NDP/DHCPv6: - assign: 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17 - router: fe80::62e3:27ff:fe33:2b01 - + assign: 2a01:4f8:222:904::2 + router: fe80::1 + our link-local: fe80::1 +Inbound forwarding rules (HOST): + TCP [*]:1-32767 => 1-32767 (best effort) (auto-scan) + TCP [*]:61000-65535 => 61000-65535 (best effort) (auto-scan) + UDP [*]:1-32767 => 1-32767 (best effort) (auto-scan) + UDP [*]:61000-65535 => 61000-65535 (best effort) (auto-scan) +Outbound forwarding rules (SPLICE): + TCP [*]%lo:1-32767 => 1-32767 (best effort) (auto-scan) + TCP [*]%lo:61000-65535 => 61000-65535 (best effort) (auto-scan) + UDP [*]%lo:1-32767 => 1-32767 (best effort) (auto-scan) + UDP [*]%lo:61000-65535 => 61000-65535 (best effort) (auto-scan) .fi -.BR " [Back to the original terminal]" + +.BR "[Back to the original terminal]" .nf -# dhclient -4 --no-pid -# dhclient -6 --no-pid # ip address show 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever - inet6 ::1/128 scope host + inet6 ::1/128 scope host proto kernel_lo valid_lft forever preferred_lft forever -2: eth0: mtu 65520 qdisc pfifo_fast state UNKNOWN group default qlen 1000 - link/ether fa:c1:2a:27:92:a9 brd ff:ff:ff:ff:ff:ff - inet 192.168.1.118/24 brd 192.168.1.255 scope global eth0 +2: enp9s0: mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000 + link/ether 9a:44:5e:54:d3:2c brd ff:ff:ff:ff:ff:ff + inet 88.198.0.164/27 brd 88.198.0.191 scope global noprefixroute enp9s0 valid_lft forever preferred_lft forever - inet6 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17/128 scope global + inet6 2a01:4f8:222:904::2/64 scope global nodad valid_lft forever preferred_lft forever - inet6 2a02:6d40:3ca5:2001:f8c1:2aff:fe27:92a9/64 scope global dynamic mngtmpaddr - valid_lft 3594sec preferred_lft 3594sec - inet6 fe80::f8c1:2aff:fe27:92a9/64 scope link + inet6 fe80::9844:5eff:fe54:d32c/64 scope link nodad proto kernel_ll valid_lft forever preferred_lft forever .fi .RE @@ -893,72 +895,69 @@ NDP/DHCPv6: .BR "Start and connect a guest with basic port forwarding" .RS .nf -$ ./passt -f -t 2222:22 -Outbound interface: eth0 -ARP: - address: 28:16:ad:39:a9:ea +$ passt -f -t 2222:22 +UNIX domain socket bound at /tmp/passt_1.socket +No IPv6 nameserver available for NDP/DHCPv6 +Template interface: enp9s0 (IPv4), enp9s0 (IPv6) +MAC: + host: 9a:55:9a:55:9a:55 + NAT to host 127.0.0.1: 88.198.0.161 DHCP: - assign: 192.168.1.118 - mask: 255.255.255.0 - router: 192.168.1.1 - search: - redhat.com + assign: 88.198.0.164 + mask: 255.255.255.224 + router: 88.198.0.161 +DNS: + 185.12.64.1 + 185.12.64.2 + NAT to host ::1: fe80::1 NDP/DHCPv6: - assign: 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17 - router: fe80::62e3:27ff:fe33:2b01 - search: - redhat.com -UNIX domain socket bound at /tmp/passt_1.socket - -You can now start qrap: - ./qrap 5 qemu-system-x86_64 ... -net socket,fd=5 -net nic,model=virtio -or directly qemu, patched with: - qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch -as follows: - qemu-system-x86_64 ... -net socket,connect=/tmp/passt_1.socket -net nic,model=virtio - + assign: 2a01:4f8:222:904::2 + router: fe80::1 + our link-local: fe80::1 +Inbound forwarding rules (HOST): + TCP [*]:2222 => 22 + +You can now start qemu (>= 7.2, with commit 13c6be96618c): + kvm ... -device virtio-net-pci,netdev=s -netdev stream,id=s,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket .fi -.BR " [From another terminal]" -.nf -$ ./qrap 5 qemu-system-x86_64 test.qcow2 -m 1024 -display none -nodefaults -nographic -net socket,fd=5 -net nic,model=virtio -Connected to /tmp/passt_1.socket -.fi -.BR " [Back to the original terminal]" +.BR "[From another terminal]" .nf -passt: DHCP: ack to request -passt: from 52:54:00:12:34:56 -passt: NDP: received NS, sending NA -passt: NDP: received RS, sending RA -passt: DHCPv6: received SOLICIT, sending ADVERTISE -passt: NDP: received NS, sending NA -passt: DHCPv6: received REQUEST/RENEW/CONFIRM, sending REPLY -passt: NDP: received NS, sending NA +$ qemu-system-x86_64 -m 128 test.qcow2 -display none -nodefaults -nographic -device virtio-net-pci,netdev=s -netdev stream,id=s,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket +.fi +.BR "[Back to the original terminal]" +.nf +accepted connection from PID 1301736 +New guest MAC address observed: 52:54:00:12:34:56 +DHCP: offer to discover + from 52:54:00:12:34:56 +DHCP: ack to request + from 52:54:00:12:34:56 +NDP: received RS, sending RA .fi -.BR " [From yet another terminal]" + +.BR "[From yet another terminal]" .nf $ ssh -p 2222 root@localhost root@localhost's password: .fi -.BR " [...]" +.BR "[...]" .nf # ip address show -1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 +1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever -2: ens2: mtu 65520 qdisc pfifo_fast state UP group default qlen 1000 +2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff - inet 192.168.1.118/24 brd 192.168.1.255 scope global noprefixroute ens2 + inet 88.198.0.164/27 scope global eth0 valid_lft forever preferred_lft forever - inet6 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17/128 scope global noprefixroute + inet6 2a01:4f8:222:904:5054:ff:fe12:3456/64 scope global dynamic flags 100 valid_lft forever preferred_lft forever - inet6 2a02:6d40:3ca5:2001:b019:9ae2:a2fe:e6b4/64 scope global dynamic noprefixroute - valid_lft 3588sec preferred_lft 3588sec - inet6 fe80::1f98:d09f:9309:9e77/64 scope link noprefixroute + inet6 fe80::5054:ff:fe12:3456/64 scope link valid_lft forever preferred_lft forever .fi .RE diff --git a/qrap.1 b/qrap.1 deleted file mode 100644 index 98cc877..0000000 --- a/qrap.1 +++ /dev/null @@ -1,77 +0,0 @@ -.\" SPDX-License-Identifier: GPL-2.0-or-later -.\" Copyright (c) 2020-2021 Red Hat GmbH -.\" Author: Stefano Brivio -.TH qrap 1 - -.SH NAME -.B qrap -\- temporary qemu wrapper connecting UNIX domain socket to file descriptor - -.SH SYNOPSIS -.B qrap -[\fIFDNUM\fR \fIQEMU_CMD\fR] [\fIQEMU_ARG\fR]... -.SH DESCRIPTION -\fBqrap\fR is a wrapper, designed specifically for usage with \fBqemu\fR(1) and -\fBpasst\fR(1), connecting a UNIX domain socket to a file descriptor, and -running \fBqemu\fR(1) with given arguments. - -A running instance of \fBpasst\fR(1) is probed checking for UNIX domain sockets, -answering a dummy ARP request, with names starting from -\fI/tmp/passt_1.socket\fR up to \fI/tmp/passt_64.socket\fR. - -If first and second arguments are not a socket number and a command, that is, -respectively, \fIFDNUM\fR and \fIQEMU_CMD\fR, \fBqrap\fR will try to locate a -qemu executable in \fBPATH\fR and patch the command line to specify a network -device and a \fInetdev\fR back-end for usage with \fBpasst\fR(1). - -If \fBqrap\fR patches the command line, it will remove any potentially -conflicting network device, that is, any \fI-netdev\fR or \fI-net\fR option, or -any \fI-device\fR option with argument starting with \fIvirtio-net-pci,\fR, -\fIvirtio-net-ccw,\fR, \fIe1000,\fR, \fIe1000e,\fR, or \fIrtl8139,\fR. - -.SH EXAMPLES - -.BR "Start qemu explicitly passing its command name and a socket number" -.RS -.nf -$ ./qrap 5 kvm test.qcow2 -m 1024 -display none -nodefaults -nographic -net socket,fd=5 -net nic,model=virtio -.fi -.RE - -.BR "Start qemu without command name and socket number, patching arguments" -.RS -.nf -$ ./qrap test.qcow2 -m 1024 -display none -nodefaults -nographic -.fi -.RE - -.SH NOTES - -This wrapper is temporary: qemu commit 13c6be96618c ("net: stream: add unix -socket") introduces native AF_UNIX socket support, and it should be included in -qemu starting from the 7.2 release. It will be around for a little bit longer to -give users enough time to switch. - -.SH AUTHOR - -Stefano Brivio - -.SH REPORTING BUGS - -No public bug tracker is available at this time. For the moment being, report -issues to Stefano Brivio . - -.SH COPYRIGHT - -Copyright (c) 2020-2021 Red Hat GmbH. - -\fBqrap\fR is free software: you can redistribute is and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 2 of the License, or (at your option) any later -version. - -.SH SEE ALSO - -\fBqemu\fR(1), \fBpasst\fR(1). - -High-level documentation is available at https://passt.top/passt/about/. diff --git a/qrap.c b/qrap.c deleted file mode 100644 index d596706..0000000 --- a/qrap.c +++ /dev/null @@ -1,429 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -/* PASST - Plug A Simple Socket Transport - * - * qrap.c - qemu wrapper connecting UNIX domain socket to file descriptor - * - * Copyright (c) 2020-2021 Red Hat GmbH - * Author: Stefano Brivio - * - * TODO: Drop this implementation once qemu commit 13c6be96618c ("net: stream: - * add unix socket") is included in a release (7.2), and once we can reasonably - * assume existing users switched to it. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "util.h" -#include "ip.h" -#include "passt.h" -#include "arp.h" - -static char *qemu_names[] = { - "kvm", - "qemu-kvm", -#ifdef ARCH - ( "qemu-system-" ARCH ), -#endif - "/usr/libexec/qemu-kvm", - NULL, -}; - -/** - * struct drop_arg - Drop matching arguments on command line - * @name: Option name - * @val: Substring in option value, NULL matches any value - */ -static const struct drop_arg { - char *name; - char *val; -} drop_args[] = { - { "-netdev", NULL }, - { "-net", NULL }, - { "-device", "virtio-net-pci," }, - { "-device", "{\"driver\":\"virtio-net-pci\"," }, - { "-device", "virtio-net-ccw," }, - { "-device", "{\"driver\":\"virtio-net-ccw\"," }, - { "-device", "e1000," }, - { "-device", "{\"driver\":\"e1000\"," }, - { "-device", "e1000e," }, - { "-device", "{\"driver\":\"e1000e\"," }, - { "-device", "rtl8139," }, - { "-device", "{\"driver\":\"rtl8139\"," }, - { 0 }, -}; - -/** - * struct pci_dev - PCI devices to add on command line depending on machine name - * @mach: Machine name - * @name: Device ("-device") name to insert - * @template: Prefix for device specification (first part of address) - * @template_post: Suffix for device specification (last part of address) - * @template_json: Device prefix for when JSON is used - * @template_json_post: Device suffix for when JSON is used - * @base: Base used for PCI addresses - * @first: First usable PCI address - * @last: Last usable PCI address - */ -static const struct pci_dev { - char *mach; - char *name; - char *template; - char *template_post; - char *template_json; - char *template_json_post; - int base; - int first; - int last; -} pci_devs[] = { - { - "pc-q35", "virtio-net-pci", - "bus=pci.", ",addr=0x0", - "\"bus\":\"pci.", ",\"addr\":\"0x0\"", - 10, 3, /* 2: hotplug bus */ 31 - }, - { - "pc-", "virtio-net-pci", - "bus=pci.0,addr=0x", "", - "\"bus\":\"pci.0\",\"addr\":\"0x", "", - 16, 2, /* 1: ISA bridge */ 31 - }, - { - "s390-ccw", "virtio-net-ccw", - "devno=fe.0.", "", - "\"devno\":\"fe.0.", "", - 16, 1, 16 - }, - { 0 }, -}; - -#define DEFAULT_FD 5 - -/** - * usage() - Print usage and exit - * @name: Executable name - */ -void usage(const char *name) -{ - fprintf(stderr, "Usage: %s [FDNUM QEMU_CMD] [QEMU_ARG]...\n", name); - fprintf(stderr, "\n"); - fprintf(stderr, "If first and second arguments aren't a socket number\n" - "and a path, %s will try to locate a qemu binary\n" - "and directly patch the command line\n", name); - - exit(EXIT_FAILURE); -} - -/** - * main() - Entry point and main loop - * @argc: Argument count - * @argv: File descriptor number, then qemu with arguments - * - * Return: 0 once interrupted, non-zero on failure - */ -int main(int argc, char **argv) -{ - int i, s, qemu_argc = 0, addr_map = 0, has_dev = 0, has_json = 0, retry_on_reset, rc; - struct timeval tv = { .tv_sec = 0, .tv_usec = (long)(500 * 1000) }; - char *qemu_argv[ARG_MAX], dev_str[ARG_MAX]; - struct sockaddr_un addr = { - .sun_family = AF_UNIX, - }; - const struct pci_dev *dev = NULL; - long fd; - struct { - uint32_t vnet_len4; - struct ethhdr eh4; - struct arphdr ah; - struct arpmsg am; - - uint32_t vnet_len6; - struct ethhdr eh6; - struct ipv6hdr ip6hr; - struct icmp6hdr ihr; - struct in6_addr target; - } __attribute__((__packed__)) probe = { - .vnet_len4 = htonl(42), - { - .h_dest = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - .h_source = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - .h_proto = htons(ETH_P_ARP), - }, - { .ar_hrd = htons(ARPHRD_ETHER), - .ar_pro = htons(ETH_P_IP), - .ar_hln = ETH_ALEN, - .ar_pln = 4, - .ar_op = htons(ARPOP_REQUEST), - }, - { - .sha = { 0 }, .sip = { 0 }, .tha = { 0 }, .tip = { 0 }, - }, - .vnet_len6 = htonl(78), - { - .h_dest = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - .h_source = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - .h_proto = htons(ETH_P_IPV6), - }, - { - .version = 6, - .payload_len = htons(24), - .nexthdr = IPPROTO_ICMPV6, - .hop_limit = 255, - .saddr = IN6ADDR_LOOPBACK_INIT, - .daddr = IN6ADDR_ANY_INIT, - }, - { - .icmp6_type = 135, - .icmp6_code = 0, - }, - IN6ADDR_ANY_INIT, - }; - char probe_r; - - if (argc >= 3) { - const char *path = getenv("PATH"); - errno = 0; - fd = strtol(argv[1], NULL, 0); - if (fd >= 3 && fd < INT_MAX && !errno && path) { - char env_path[ARG_MAX + 1], *p, command[ARG_MAX]; - - strncpy(env_path, path, ARG_MAX); - /* cppcheck-suppress strtokCalled */ - p = strtok(env_path, ":"); - while (p) { - snprintf(command, ARG_MAX, "%s/%s", p, argv[2]); - if (!access(command, X_OK)) - goto valid_args; - - /* cppcheck-suppress strtokCalled */ - p = strtok(NULL, ":"); - } - } - } - - fd = DEFAULT_FD; - - for (i = 1; i < argc - 1; i++) { - if (strcmp(argv[i], "-machine")) - continue; - - for (dev = pci_devs; dev->mach; dev++) { - if (strstr(argv[i + 1], dev->mach) == argv[i + 1]) - break; - } - } - - if (!dev || !dev->mach) - dev = pci_devs; - - for (qemu_argc = 1, i = 1; i < argc; i++) { - const struct drop_arg *a; - - for (a = drop_args; a->name; a++) { - if (!strcmp(argv[i], a->name)) { - if (!a->val) - break; - - if (i + 1 < argc && - strstr(argv[i + 1], a->val) == argv[i + 1]) - break; - } - } - if (a->name) { - i++; - continue; - } - - if (!strcmp(argv[i], "-device") && i + 1 < argc) { - const char *template = NULL; - const char *p; - - has_dev = 1; - - if ((p = strstr(argv[i + 1], dev->template))) { - template = dev->template; - } else if ((p = strstr(argv[i + 1], dev->template_json))) { - template = dev->template_json; - has_json = 1; - } - - if (template) { - long n; - - n = strtol(p + strlen(template), NULL, dev->base); - if (!errno) - addr_map |= (1 << n); - } - } - - qemu_argv[qemu_argc++] = argv[i]; - } - - for (i = dev->first; i < dev->last; i++) { - if (!(addr_map & (1 << i))) - break; - } - if (i == dev->last) { - fprintf(stderr, "Couldn't find free address for device\n"); - usage(argv[0]); - } - - if (has_dev) { - qemu_argv[qemu_argc++] = "-device"; - if (!has_json) { - if (dev->base == 16) { - snprintf(dev_str, ARG_MAX, - "%s,%s%x%s,netdev=hostnet0,x-txburst=4096", - dev->name, dev->template, i, dev->template_post); - } else if (dev->base == 10) { - snprintf(dev_str, ARG_MAX, - "%s,%s%d%s,netdev=hostnet0,x-txburst=4096", - dev->name, dev->template, i, dev->template_post); - } - } else { - if (dev->base == 16) { - snprintf(dev_str, ARG_MAX, - "{\"driver\":\"%s\",%s%x\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}", - dev->name, dev->template_json, i, dev->template_json_post); - } else if (dev->base == 10) { - snprintf(dev_str, ARG_MAX, - "{\"driver\":\"%s\",%s%d\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}", - dev->name, dev->template_json, i, dev->template_json_post); - } - } - qemu_argv[qemu_argc++] = dev_str; - } - - qemu_argv[qemu_argc++] = "-netdev"; - if (!has_json) { - qemu_argv[qemu_argc++] = "socket,fd=" STR(DEFAULT_FD) ",id=hostnet0"; - } else { - qemu_argv[qemu_argc++] = "{\"type\":\"socket\",\"fd\":\"" STR(DEFAULT_FD) "\",\"id\":\"hostnet0\"}"; - } - qemu_argv[qemu_argc] = NULL; - -valid_args: - for (i = 1; i < UNIX_SOCK_MAX; i++) { - retry_on_reset = 50; - -retry: - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) { - perror("socket"); - exit(EXIT_FAILURE); - } - - if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) - perror("setsockopt SO_RCVTIMEO"); - if (setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))) - perror("setsockopt SO_SNDTIMEO"); - - snprintf(addr.sun_path, UNIX_PATH_MAX, UNIX_SOCK_PATH, i); - - errno = 0; - - if (connect(s, (const struct sockaddr *)&addr, sizeof(addr))) { - rc = errno; - perror("connect"); - } else if (send(s, &probe, sizeof(probe), 0) != sizeof(probe)) { - rc = errno; - perror("send"); - } else if (recv(s, &probe_r, 1, MSG_PEEK) <= 0) { - rc = errno; - perror("recv"); - } else { - break; - } - - /* FIXME: in a KubeVirt environment, libvirtd invokes qrap three - * times in a strict sequence when a virtual machine needs to - * be started, namely, when: - * - the domain XML is saved - * - the domain is started (for "probing") - * - the virtual machine is started for real - * and it often happens that the qemu process is still running - * when qrap is invoked again, so passt will refuse the new - * connection because the previous one is still active. This - * overlap seems to be anywhere between 0 and 3ms. - * - * If we get a connection reset, retry a few times, to allow for - * the previous qemu instance to terminate and, in turn, for the - * connection to passt to be closed. - * - * This should be fixed in libvirt instead. It probably makes - * sense to check this behaviour once native libvirt support is - * there, and this implies native qemu support too, so at that - * point qrap will have no reason to exist anymore -- that is, - * this FIXME will probably remain until the tool itself is - * obsoleted. - */ - if (retry_on_reset && rc == ECONNRESET) { - retry_on_reset--; - /* cppcheck-suppress usleepCalled */ - usleep(50 * 1000); - goto retry; - } - - fprintf(stderr, "Probe of %s failed\n", addr.sun_path); - - close(s); - } - - if (i == UNIX_SOCK_MAX) { - perror("connect"); - exit(EXIT_FAILURE); - } - - tv.tv_usec = 0; - if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) - perror("setsockopt, SO_RCVTIMEO reset"); - if (setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))) - perror("setsockopt, SO_SNDTIMEO reset"); - - fprintf(stderr, "Connected to %s\n", addr.sun_path); - - if (dup2(s, (int)fd) < 0) { - perror("dup"); - exit(EXIT_FAILURE); - } - - close(s); - - if (qemu_argc) { - char **name; - - for (name = qemu_names; *name; name++) { - qemu_argv[0] = *name; - execvp(*name, qemu_argv); - if (errno != ENOENT) { - perror("execvp"); - usage(argv[0]); - } - } - if (errno == ENOENT) - fprintf(stderr, "Couldn't find qemu command\n"); - } else { - execvp(argv[2], argv + 2); - } - - perror("execvp"); - - return EXIT_FAILURE; -} diff --git a/tap.c b/tap.c index cf87591..dfa66c7 100644 --- a/tap.c +++ b/tap.c @@ -1377,8 +1377,6 @@ static void tap_backend_show_hints(const struct ctx *c) info("\nYou can now start qemu (>= 7.2, with commit 13c6be96618c):"); info(" kvm ... -device virtio-net-pci,netdev=s -netdev stream,id=s,server=off,addr.type=unix,addr.path=%s", c->sock_path); - info("or qrap, for earlier qemu versions:"); - info(" ./qrap 5 kvm ... -net socket,fd=5 -net nic,model=virtio"); break; case MODE_VU: info("You can start qemu with:"); diff --git a/test/distro/opensuse b/test/distro/opensuse index eab722b..9ceb0bd 100644 --- a/test/distro/opensuse +++ b/test/distro/opensuse @@ -39,7 +39,7 @@ hostb ./passt -s __STATEDIR__/passt.socket -P __PIDFILE__ & sleep 1 host echo hout DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | head -1 -hout GUEST_FILES ls -1 *.c *.h *.sh passt.1 qrap.1 Makefile README.md | tr '\n' ' '; echo +hout GUEST_FILES ls -1 *.c *.h *.sh passt.1 Makefile README.md | tr '\n' ' '; echo test OpenSUSE Leap 15.1 -- 2.43.0