public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: passt-dev@passt.top
Subject: [PATCH 01/12] doc: Rewrite demo script
Date: Thu, 18 Aug 2022 22:22:24 +0200	[thread overview]
Message-ID: <20220818202235.1591828-2-sbrivio@redhat.com> (raw)
In-Reply-To: <20220818202235.1591828-1-sbrivio@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 14213 bytes --]

The original demo script was written when pasta wasn't a thing yet,
so it needed to run as root, set up a veth pair, and configure
addresses and routes by itself.

Now pasta can do all that for us, and become part of the demo as
well.

Further, extend it to start qemu, optionally preparing a basic demo
image with mbuto (https://mbuto.sh), and execute one logical step at
a time, for clarity.

Signed-off-by: Stefano Brivio <sbrivio(a)redhat.com>
---
 README.md   |  29 ++---
 doc/demo.sh | 340 +++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 244 insertions(+), 125 deletions(-)

diff --git a/README.md b/README.md
index 628b9bb..2cd40c7 100644
--- a/README.md
+++ b/README.md
@@ -541,25 +541,11 @@ See also the [test logs](/builds/latest/test/).
 
         man ./passt.1
 
-* run the demo script, that creates a network namespace called `passt`, sets up
-  sets up a _veth_ pair and and addresses, together with NAT for IPv4 and NDP
-  proxying for IPv6, then starts _passt_ in the network namespace:
+* run the demo script, that detaches user and network namespaces, configures the
+  new network namespace using `pasta`, starts `passt` and, optionally, `qemu`:
 
         doc/demo.sh
 
-* from the same network namespace, start qemu. At the moment, qemu doesn't
-  support UNIX domain sockets for the `socket` back-end. Two alternatives:
-
-    * use the _qrap_ wrapper, which maps a tap socket descriptor to _passt_'s
-      UNIX domain socket, for example:
-
-            ip netns exec passt ./qrap 5 qemu-system-x86_64 ... -net socket,fd=5 -net nic,model=virtio ...
-
-    * or patch qemu with [this patch](/passt/tree/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch)
-      and start it like this:
-
-            qemu-system-x86_64 ... -net socket,connect=/tmp/passt.socket -net nic,model=virtio
-
 * alternatively, you can use libvirt, with [this patch](/passt/tree/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch),
   to start qemu (with the patch mentioned above), with this kind of network
   interface configuration:
@@ -613,6 +599,17 @@ See also the [test logs](/builds/latest/test/).
 
         dhclient -6
 
+    * alternatively, start pasta as:
+
+            ./pasta --config-net
+
+        to let pasta configure networking in the namespace by itself, using
+        `netlink`
+
+    * ...or run the demo script:
+
+        doc/demo.sh
+
 * and that's it, you should now have TCP connections, UDP, and ICMP/ICMPv6
   echo working from/to the namespace for IPv4 and IPv6
 
diff --git a/doc/demo.sh b/doc/demo.sh
index f49110a..d39a10e 100755
--- a/doc/demo.sh
+++ b/doc/demo.sh
@@ -4,122 +4,244 @@
 #
 # PASST - Plug A Simple Socket Transport
 #
-# demo.sh - Set up namespaces, addresses and routes to show PASST functionality
+# demo.sh - Set up namespace with pasta, start qemu and passt, step by step
 #
-# Copyright (c) 2020-2021 Red Hat GmbH
+# Copyright (c) 2020-2022 Red Hat GmbH
 # Author: Stefano Brivio <sbrivio(a)redhat.com>
 
-get_token() {
-	IFS=' 	'
-	__next=0
-	for __token in ${@}; do
-		[ ${__next} -eq 2 ] && echo "${__token}" && return
-		[ "${__token}" = "${1}" ] && __next=$((__next + 1))
-	done
-	unset IFS
+# mbuto_profile() - Profile for https://mbuto.sh/, sourced, return after setting
+mbuto_profile() {
+	PROGS="${PROGS:-ash,dash,bash ip mount ls ln chmod insmod mkdir sleep
+	       lsmod modprobe find grep mknod mv rm umount iperf3 dhclient cat
+	       hostname chown socat dd strace ping killall sysctl wget,curl}"
+
+	KMODS="${KMODS:- virtio_net virtio_pci}"
+
+	LINKS="${LINKS:-
+		 ash,dash,bash		/init
+		 ash,dash,bash		/bin/sh}"
+
+	DIRS="${DIRS} /tmp /sbin /var/log /var/run /var/lib"
+
+	# shellcheck disable=SC2016
+	FIXUP="${FIXUP}"'
+		cat > /sbin/dhclient-script << EOF
+#!/bin/sh
+
+[ -n "\${new_interface_mtu}" ]       && ip link set dev \${interface} mtu \${new_interface_mtu}
+
+[ -n "\${new_ip_address}" ]          && ip addr add \${new_ip_address}/\${new_subnet_mask} dev \${interface}
+[ -n "\${new_routers}" ]             && for r in \${new_routers}; do ip route add default via \${r} dev \${interface}; done
+[ -n "\${new_domain_name_servers}" ] && for d in \${new_domain_name_servers}; do echo "nameserver \${d}" >> /etc/resolv.conf; done
+[ -n "\${new_domain_name}" ]         && echo "search \${new_domain_name}" >> /etc/resolf.conf
+[ -n "\${new_domain_search}" ]       && (printf "search"; for d in \${new_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf
+[ -n "\${new_ip6_address}" ]         && ip addr add \${new_ip6_address}/\${new_ip6_prefixlen} dev \${interface}
+[ -n "\${new_dhcp6_name_servers}" ]  && for d in \${new_dhcp6_name_servers}; do echo "nameserver \${d}%\${interface}" >> /etc/resolv.conf; done
+[ -n "\${new_dhcp6_domain_search}" ] && (printf "search"; for d in \${new_dhcp6_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf
+[ -n "\${new_host_name}" ]           && hostname "\${new_host_name}"
+exit 0
+EOF
+
+		chmod 755 /sbin/dhclient-script
+
+		mkdir -p /etc/dhcp
+		echo "timeout 3;" > /etc/dhcp/dhclient.conf
+
+		ln -s /sbin /usr/sbin
+		:> /etc/fstab
+
+		echo
+		echo "The guest is up and running. Networking is not configured yet:"
+		echo
+		echo "$ ip address show"
+		echo
+		ip address show
+		echo
+		echo "...the next step will take care of that."
+		read x
+
+		echo "$ ip link set dev eth0 up"
+		ip link set dev eth0 up
+		sleep 3
+		echo "$ /sbin/dhclient -4 -1"
+		/sbin/dhclient -4 -1
+		sleep 2
+		echo "$ /sbin/dhclient -6 -1"
+		/sbin/dhclient -6 -1
+		sleep 2
+		echo
+		echo "$ ip address show"
+		ip address show
+		echo
+		echo "$ ip route show"
+		ip route show
+		echo
+		echo "...done."
+		read x
+
+		echo "Checking connectivity..."
+		echo
+		echo "$ wget --no-check-certificate https://passt.top/ || curl -k https://passt.top/"
+		wget --no-check-certificate https://passt.top/ || curl -k https://passt.top/
+		echo "...done."
+		read x
+
+		echo "An interactive shell will start now. When you are done,"
+		echo "use ^C to terminate the guest and exit the demo."
+		echo
+
+		sh +m
+'
 }
 
-ipv6_dev() { get_token "dev" $(ip -o -6 route show default | grep via); }
-ipv6_devaddr() { get_token "inet6" $(ip -o -6 addr show dev "${1}" scope global); }
-ipv6_ll_addr() { get_token "inet6" $(ip -o -6 addr show dev "${1}" scope link); }
-ipv6_mask() { echo ${1#*/}; }
-ipv6_mangle() {
-	IFS=':'
-	__c=0
-	for __16b in ${1%%/*}; do
-		if [ ${__c} -lt 7 ]; then
-			printf "${__16b}:"
-		else
-			printf "%04x\n" $((0xabc0 + ${2})) && break
-		fi
-		__c=$((__c + 1))
-	done
-	unset IFS
+[ "${0##*/}" = "mbuto" ] && mbuto_profile && return 0
+
+# cmd() - Show command being executed, then run it
+# $@: Command and arguments
+cmd() {
+	echo "$" "$@"
+	"$@"
+}
+
+# next() - Go to next step once a key is pressed, sets $KEY
+next() {
+	KEY="$(dd ibs=1 count=1 2>/dev/null)"
+	echo
 }
 
-ndp_setup() {
-	sysctl -w net.ipv6.conf.all.proxy_ndp=1
-	ip -6 neigh add proxy "${1}" dev "$(ipv6_dev)"
+# cleanup() - Terminate pasta and passt, clean up, restore TTY settings
+cleanup() {
+	[ -f "${DEMO_DIR}/pasta.pid" ] && kill "$(cat "${DEMO_DIR}/pasta.pid")"
+	[ -f "${DEMO_DIR}/passt.pid" ] && kill "$(cat "${DEMO_DIR}/passt.pid")"
+	rm -rf "${DEMO_DIR}" 2>/dev/null
+	[ -n "${STTY_BACKUP}" ] && stty "${STTY_BACKUP}"
+}
+
+# start_pasta_delayed() - Start pasta once $DEMO_DIR/pasta.wait is gone
+start_pasta_delayed() {
+	trap '' EXIT
+	while [ -d "${DEMO_DIR}/pasta.wait" ]; do sleep 1; done
+	cmd pasta --config-net -P "${DEMO_DIR}/pasta.pid" \
+		"$(cat "${DEMO_DIR}/shell.pid")"
+	echo
+	echo "...pasta is running."
+	exit 0
+}
 
-	for i in `seq 1 63`; do
-		__neigh="$(ipv6_mangle ${1} ${i})"
-		if [ "${__neigh}" != "${1}" ]; then
-			ip -6 neigh add proxy "${__neigh}" dev "${2}"
-		fi
-	done
+# into_ns() - Entry point and demo script to run inside new namespace
+into_ns() {
+	echo "We're in the new namespace now."
+	next
+
+	echo "Networking is not configured yet:"
+	echo
+	cmd ip link show
+	echo
+	cmd ip address show
+	next
+
+	echo "Let's run pasta(1) to configure networking and connect this"
+	echo "namespace. Note that we'll run pasta(1) from outside this"
+	echo "namespace, because it needs to implement the connection between"
+	echo "this namespace and the initial (\"outer\") one."
+	next
+
+	echo "$$" > "${DEMO_DIR}/shell.pid"
+	rmdir "${DEMO_DIR}/pasta.wait"
+	next
+
+	echo "Back to the new namespace, networking is configured:"
+	echo
+	cmd ip link show
+	echo
+	cmd ip address show
+	next
+
+	echo "and we can now start passt(1), to connect this namespace to a"
+	echo "virtual machine. If you want to start a shell in this namespace,"
+	echo "press 's' now. Exiting the shell will resume the script."
+	next
+	[ "${KEY}" = "s" ] && ${SHELL}
+
+	cmd passt -P "${DEMO_DIR}/passt.pid"
+	echo
+	echo "...passt is running."
+	next
+
+	__arch="$(uname -m)"
+	case ${__arch} in
+	x86_64)
+		__arch_supported=1
+		__qemu_arch="qemu-system-x86_64 -M pc,accel=kvm:tcg"
+		;;
+	*)
+		__arch_supported=0
+		;;
+	esac
+
+	if [ "${__arch_supported}" -eq 1 ]; then
+		echo "We're ready to start a virtual machine now. This script"
+		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
+	fi
+
+	if [ "${__arch_supported}" -eq 0 ] || [ "${KEY}" = "s" ]; then
+		echo "Start a virtual machine now. Pressing any key here will"
+		echo "terminate passt and pasta, and clean up."
+		next
+
+		exit 0
+	fi
+
+	cmd git -C "${DEMO_DIR}" clone git://mbuto.sh/mbuto
+	echo
+	cmd "${DEMO_DIR}/mbuto/mbuto" \
+		-p "$(realpath "${0}")" -f "${DEMO_DIR}/demo.img"
+	echo
+	echo "The guest image is ready. The next step will start the guest."
+	echo "Use ^C to terminate it."
+	next
+
+	cmd qrap 5 qemu-system-x86_64 -M pc,accel=kvm:tcg		    \
+		-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 || :
 }
 
-ns_idx=0
-for i in `seq 1 63`; do
-	ns="passt_${i}"
-	ns_idx=${i}
-
-	busy=0
-	for p in $(pidof passt); do
-		[ "$(ip netns identify ${p})" = "${ns}" ] && busy=1 && break
-	done
-	[ ${busy} -eq 0 ] && break
-done
-
-[ ${busy} -ne 0 ] && echo "Couldn't create namespace" && exit 1
-
-ip netns del "${ns}" 2>/dev/null || :
-ip netns add "${ns}"
-ip link del "veth_${ns}" 2>/dev/null || :
-ip link add "veth_${ns}" up netns "${ns}" type veth peer name "veth_${ns}"
-ip link set dev "veth_${ns}" up
-ip link set dev "veth_${ns}" mtu 65535
-ip -n "${ns}" link set dev "veth_${ns}" mtu 65535
-ip -n "${ns}" link set dev lo up
-
-ipv4_main="192.0.2.$(((ns_idx - 1) * 4 + 1))"
-ipv4_ns="192.0.2.$(((ns_idx - 1) * 4 + 2))"
-
-ip -n "${ns}" addr add "${ipv4_ns}/30" dev "veth_${ns}"
-ip addr add "${ipv4_main}/30" dev "veth_${ns}"
-ip -n "${ns}" route add default via "${ipv4_main}"
-
-sysctl -w net.ipv4.ip_forward=1
-nft delete table "${ns}_nat" 2>/dev/null || :
-nft add table "${ns}_nat"
-nft add chain "${ns}_nat" postrouting '{ type nat hook postrouting priority -100 ; }'
-nft add rule "${ns}_nat" postrouting ip saddr "${ipv4_ns}" masquerade
-
-ipv6_addr="$(ipv6_devaddr "$(ipv6_dev)")"
-if [ -n "${ipv6_addr}" ]; then
-	ipv6_passt="$(ipv6_mangle "${ipv6_addr}" ${ns_idx})"
-	ndp_setup "${ipv6_passt}" "veth_${ns}"
-	ip -n "${ns}" addr add "${ipv6_passt}/$(ipv6_mask "${ipv6_addr}")" dev "veth_${ns}"
-	ip addr add "${ipv6_addr}" dev "veth_${ns}"
-	ip route add "${ipv6_passt}" dev "veth_${ns}"
-	passt_ll="$(ipv6_ll_addr "veth_${ns}")"
-	main_ll="$(get_token "link/ether" $(ip -o link show "veth_${ns}"))"
-	ip neigh add "${passt_ll%%/*}" dev "veth_${ns}" lladdr "${main_ll}"
-	ip -n "${ns}" route add default via "${passt_ll%%/*}" dev "veth_${ns}"
-
-	sysctl -w net.ipv6.conf.all.forwarding=1
-else
-	ipv6_passt=
-fi
-
-ethtool -K "veth_${ns}" tx off
-ip netns exec "${ns}" ethtool -K "veth_${ns}" tx off
-ip netns exec "${ns}" sysctl -w net.ipv4.ping_group_range="0 2147483647"
-
-
-sysctl -w net.core.rmem_max=16777216
-sysctl -w net.core.wmem_max=16777216
-sysctl -w net.core.rmem_default=16777216
-sysctl -w net.core.wmem_default=16777216
-sysctl -w net.ipv4.tcp_rmem="16777216 131072 16777216"
-sysctl -w net.ipv4.tcp_wmem="16777216 131072 16777216"
-
-echo
-echo "Namespace ${ns} set up, addresses:"
-echo "    ${ipv4_ns}"
-echo "    ${ipv6_passt}"
-echo
-echo "Starting passt..."
-echo
-
-ip netns exec "${ns}" ./passt -f -e -t all -u all
+STTY_BACKUP="$(stty -g)"
+stty -icanon
+
+trap cleanup EXIT INT
+[ "${1}" = "into_ns" ] && into_ns && exit 0
+
+DEMO_DIR="$(mktemp -d)"
+mkdir "${DEMO_DIR}/pasta.wait"
+
+echo "This script sets up a network and user namespace using pasta(1), then"
+echo "starts a virtual machine in it, connected via passt(1), pausing at every"
+echo "step. Press any key to go to the next step."
+next
+
+echo "Let's create the network and user namespace, first. This could be done"
+echo "with pasta(1) itself (just issue \`pasta\`), but for the sake of this"
+echo "script we'll create it first with unshare(1), and run the next steps"
+echo "of this script from there."
+next
+
+start_pasta_delayed &
+DEMO_DIR="${DEMO_DIR}" cmd unshare -rUn "${0}" into_ns
+
+exit 0
-- 
@@ -4,122 +4,244 @@
 #
 # PASST - Plug A Simple Socket Transport
 #
-# demo.sh - Set up namespaces, addresses and routes to show PASST functionality
+# demo.sh - Set up namespace with pasta, start qemu and passt, step by step
 #
-# Copyright (c) 2020-2021 Red Hat GmbH
+# Copyright (c) 2020-2022 Red Hat GmbH
 # Author: Stefano Brivio <sbrivio(a)redhat.com>
 
-get_token() {
-	IFS=' 	'
-	__next=0
-	for __token in ${@}; do
-		[ ${__next} -eq 2 ] && echo "${__token}" && return
-		[ "${__token}" = "${1}" ] && __next=$((__next + 1))
-	done
-	unset IFS
+# mbuto_profile() - Profile for https://mbuto.sh/, sourced, return after setting
+mbuto_profile() {
+	PROGS="${PROGS:-ash,dash,bash ip mount ls ln chmod insmod mkdir sleep
+	       lsmod modprobe find grep mknod mv rm umount iperf3 dhclient cat
+	       hostname chown socat dd strace ping killall sysctl wget,curl}"
+
+	KMODS="${KMODS:- virtio_net virtio_pci}"
+
+	LINKS="${LINKS:-
+		 ash,dash,bash		/init
+		 ash,dash,bash		/bin/sh}"
+
+	DIRS="${DIRS} /tmp /sbin /var/log /var/run /var/lib"
+
+	# shellcheck disable=SC2016
+	FIXUP="${FIXUP}"'
+		cat > /sbin/dhclient-script << EOF
+#!/bin/sh
+
+[ -n "\${new_interface_mtu}" ]       && ip link set dev \${interface} mtu \${new_interface_mtu}
+
+[ -n "\${new_ip_address}" ]          && ip addr add \${new_ip_address}/\${new_subnet_mask} dev \${interface}
+[ -n "\${new_routers}" ]             && for r in \${new_routers}; do ip route add default via \${r} dev \${interface}; done
+[ -n "\${new_domain_name_servers}" ] && for d in \${new_domain_name_servers}; do echo "nameserver \${d}" >> /etc/resolv.conf; done
+[ -n "\${new_domain_name}" ]         && echo "search \${new_domain_name}" >> /etc/resolf.conf
+[ -n "\${new_domain_search}" ]       && (printf "search"; for d in \${new_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf
+[ -n "\${new_ip6_address}" ]         && ip addr add \${new_ip6_address}/\${new_ip6_prefixlen} dev \${interface}
+[ -n "\${new_dhcp6_name_servers}" ]  && for d in \${new_dhcp6_name_servers}; do echo "nameserver \${d}%\${interface}" >> /etc/resolv.conf; done
+[ -n "\${new_dhcp6_domain_search}" ] && (printf "search"; for d in \${new_dhcp6_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf
+[ -n "\${new_host_name}" ]           && hostname "\${new_host_name}"
+exit 0
+EOF
+
+		chmod 755 /sbin/dhclient-script
+
+		mkdir -p /etc/dhcp
+		echo "timeout 3;" > /etc/dhcp/dhclient.conf
+
+		ln -s /sbin /usr/sbin
+		:> /etc/fstab
+
+		echo
+		echo "The guest is up and running. Networking is not configured yet:"
+		echo
+		echo "$ ip address show"
+		echo
+		ip address show
+		echo
+		echo "...the next step will take care of that."
+		read x
+
+		echo "$ ip link set dev eth0 up"
+		ip link set dev eth0 up
+		sleep 3
+		echo "$ /sbin/dhclient -4 -1"
+		/sbin/dhclient -4 -1
+		sleep 2
+		echo "$ /sbin/dhclient -6 -1"
+		/sbin/dhclient -6 -1
+		sleep 2
+		echo
+		echo "$ ip address show"
+		ip address show
+		echo
+		echo "$ ip route show"
+		ip route show
+		echo
+		echo "...done."
+		read x
+
+		echo "Checking connectivity..."
+		echo
+		echo "$ wget --no-check-certificate https://passt.top/ || curl -k https://passt.top/"
+		wget --no-check-certificate https://passt.top/ || curl -k https://passt.top/
+		echo "...done."
+		read x
+
+		echo "An interactive shell will start now. When you are done,"
+		echo "use ^C to terminate the guest and exit the demo."
+		echo
+
+		sh +m
+'
 }
 
-ipv6_dev() { get_token "dev" $(ip -o -6 route show default | grep via); }
-ipv6_devaddr() { get_token "inet6" $(ip -o -6 addr show dev "${1}" scope global); }
-ipv6_ll_addr() { get_token "inet6" $(ip -o -6 addr show dev "${1}" scope link); }
-ipv6_mask() { echo ${1#*/}; }
-ipv6_mangle() {
-	IFS=':'
-	__c=0
-	for __16b in ${1%%/*}; do
-		if [ ${__c} -lt 7 ]; then
-			printf "${__16b}:"
-		else
-			printf "%04x\n" $((0xabc0 + ${2})) && break
-		fi
-		__c=$((__c + 1))
-	done
-	unset IFS
+[ "${0##*/}" = "mbuto" ] && mbuto_profile && return 0
+
+# cmd() - Show command being executed, then run it
+# $@: Command and arguments
+cmd() {
+	echo "$" "$@"
+	"$@"
+}
+
+# next() - Go to next step once a key is pressed, sets $KEY
+next() {
+	KEY="$(dd ibs=1 count=1 2>/dev/null)"
+	echo
 }
 
-ndp_setup() {
-	sysctl -w net.ipv6.conf.all.proxy_ndp=1
-	ip -6 neigh add proxy "${1}" dev "$(ipv6_dev)"
+# cleanup() - Terminate pasta and passt, clean up, restore TTY settings
+cleanup() {
+	[ -f "${DEMO_DIR}/pasta.pid" ] && kill "$(cat "${DEMO_DIR}/pasta.pid")"
+	[ -f "${DEMO_DIR}/passt.pid" ] && kill "$(cat "${DEMO_DIR}/passt.pid")"
+	rm -rf "${DEMO_DIR}" 2>/dev/null
+	[ -n "${STTY_BACKUP}" ] && stty "${STTY_BACKUP}"
+}
+
+# start_pasta_delayed() - Start pasta once $DEMO_DIR/pasta.wait is gone
+start_pasta_delayed() {
+	trap '' EXIT
+	while [ -d "${DEMO_DIR}/pasta.wait" ]; do sleep 1; done
+	cmd pasta --config-net -P "${DEMO_DIR}/pasta.pid" \
+		"$(cat "${DEMO_DIR}/shell.pid")"
+	echo
+	echo "...pasta is running."
+	exit 0
+}
 
-	for i in `seq 1 63`; do
-		__neigh="$(ipv6_mangle ${1} ${i})"
-		if [ "${__neigh}" != "${1}" ]; then
-			ip -6 neigh add proxy "${__neigh}" dev "${2}"
-		fi
-	done
+# into_ns() - Entry point and demo script to run inside new namespace
+into_ns() {
+	echo "We're in the new namespace now."
+	next
+
+	echo "Networking is not configured yet:"
+	echo
+	cmd ip link show
+	echo
+	cmd ip address show
+	next
+
+	echo "Let's run pasta(1) to configure networking and connect this"
+	echo "namespace. Note that we'll run pasta(1) from outside this"
+	echo "namespace, because it needs to implement the connection between"
+	echo "this namespace and the initial (\"outer\") one."
+	next
+
+	echo "$$" > "${DEMO_DIR}/shell.pid"
+	rmdir "${DEMO_DIR}/pasta.wait"
+	next
+
+	echo "Back to the new namespace, networking is configured:"
+	echo
+	cmd ip link show
+	echo
+	cmd ip address show
+	next
+
+	echo "and we can now start passt(1), to connect this namespace to a"
+	echo "virtual machine. If you want to start a shell in this namespace,"
+	echo "press 's' now. Exiting the shell will resume the script."
+	next
+	[ "${KEY}" = "s" ] && ${SHELL}
+
+	cmd passt -P "${DEMO_DIR}/passt.pid"
+	echo
+	echo "...passt is running."
+	next
+
+	__arch="$(uname -m)"
+	case ${__arch} in
+	x86_64)
+		__arch_supported=1
+		__qemu_arch="qemu-system-x86_64 -M pc,accel=kvm:tcg"
+		;;
+	*)
+		__arch_supported=0
+		;;
+	esac
+
+	if [ "${__arch_supported}" -eq 1 ]; then
+		echo "We're ready to start a virtual machine now. This script"
+		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
+	fi
+
+	if [ "${__arch_supported}" -eq 0 ] || [ "${KEY}" = "s" ]; then
+		echo "Start a virtual machine now. Pressing any key here will"
+		echo "terminate passt and pasta, and clean up."
+		next
+
+		exit 0
+	fi
+
+	cmd git -C "${DEMO_DIR}" clone git://mbuto.sh/mbuto
+	echo
+	cmd "${DEMO_DIR}/mbuto/mbuto" \
+		-p "$(realpath "${0}")" -f "${DEMO_DIR}/demo.img"
+	echo
+	echo "The guest image is ready. The next step will start the guest."
+	echo "Use ^C to terminate it."
+	next
+
+	cmd qrap 5 qemu-system-x86_64 -M pc,accel=kvm:tcg		    \
+		-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 || :
 }
 
-ns_idx=0
-for i in `seq 1 63`; do
-	ns="passt_${i}"
-	ns_idx=${i}
-
-	busy=0
-	for p in $(pidof passt); do
-		[ "$(ip netns identify ${p})" = "${ns}" ] && busy=1 && break
-	done
-	[ ${busy} -eq 0 ] && break
-done
-
-[ ${busy} -ne 0 ] && echo "Couldn't create namespace" && exit 1
-
-ip netns del "${ns}" 2>/dev/null || :
-ip netns add "${ns}"
-ip link del "veth_${ns}" 2>/dev/null || :
-ip link add "veth_${ns}" up netns "${ns}" type veth peer name "veth_${ns}"
-ip link set dev "veth_${ns}" up
-ip link set dev "veth_${ns}" mtu 65535
-ip -n "${ns}" link set dev "veth_${ns}" mtu 65535
-ip -n "${ns}" link set dev lo up
-
-ipv4_main="192.0.2.$(((ns_idx - 1) * 4 + 1))"
-ipv4_ns="192.0.2.$(((ns_idx - 1) * 4 + 2))"
-
-ip -n "${ns}" addr add "${ipv4_ns}/30" dev "veth_${ns}"
-ip addr add "${ipv4_main}/30" dev "veth_${ns}"
-ip -n "${ns}" route add default via "${ipv4_main}"
-
-sysctl -w net.ipv4.ip_forward=1
-nft delete table "${ns}_nat" 2>/dev/null || :
-nft add table "${ns}_nat"
-nft add chain "${ns}_nat" postrouting '{ type nat hook postrouting priority -100 ; }'
-nft add rule "${ns}_nat" postrouting ip saddr "${ipv4_ns}" masquerade
-
-ipv6_addr="$(ipv6_devaddr "$(ipv6_dev)")"
-if [ -n "${ipv6_addr}" ]; then
-	ipv6_passt="$(ipv6_mangle "${ipv6_addr}" ${ns_idx})"
-	ndp_setup "${ipv6_passt}" "veth_${ns}"
-	ip -n "${ns}" addr add "${ipv6_passt}/$(ipv6_mask "${ipv6_addr}")" dev "veth_${ns}"
-	ip addr add "${ipv6_addr}" dev "veth_${ns}"
-	ip route add "${ipv6_passt}" dev "veth_${ns}"
-	passt_ll="$(ipv6_ll_addr "veth_${ns}")"
-	main_ll="$(get_token "link/ether" $(ip -o link show "veth_${ns}"))"
-	ip neigh add "${passt_ll%%/*}" dev "veth_${ns}" lladdr "${main_ll}"
-	ip -n "${ns}" route add default via "${passt_ll%%/*}" dev "veth_${ns}"
-
-	sysctl -w net.ipv6.conf.all.forwarding=1
-else
-	ipv6_passt=
-fi
-
-ethtool -K "veth_${ns}" tx off
-ip netns exec "${ns}" ethtool -K "veth_${ns}" tx off
-ip netns exec "${ns}" sysctl -w net.ipv4.ping_group_range="0 2147483647"
-
-
-sysctl -w net.core.rmem_max=16777216
-sysctl -w net.core.wmem_max=16777216
-sysctl -w net.core.rmem_default=16777216
-sysctl -w net.core.wmem_default=16777216
-sysctl -w net.ipv4.tcp_rmem="16777216 131072 16777216"
-sysctl -w net.ipv4.tcp_wmem="16777216 131072 16777216"
-
-echo
-echo "Namespace ${ns} set up, addresses:"
-echo "    ${ipv4_ns}"
-echo "    ${ipv6_passt}"
-echo
-echo "Starting passt..."
-echo
-
-ip netns exec "${ns}" ./passt -f -e -t all -u all
+STTY_BACKUP="$(stty -g)"
+stty -icanon
+
+trap cleanup EXIT INT
+[ "${1}" = "into_ns" ] && into_ns && exit 0
+
+DEMO_DIR="$(mktemp -d)"
+mkdir "${DEMO_DIR}/pasta.wait"
+
+echo "This script sets up a network and user namespace using pasta(1), then"
+echo "starts a virtual machine in it, connected via passt(1), pausing at every"
+echo "step. Press any key to go to the next step."
+next
+
+echo "Let's create the network and user namespace, first. This could be done"
+echo "with pasta(1) itself (just issue \`pasta\`), but for the sake of this"
+echo "script we'll create it first with unshare(1), and run the next steps"
+echo "of this script from there."
+next
+
+start_pasta_delayed &
+DEMO_DIR="${DEMO_DIR}" cmd unshare -rUn "${0}" into_ns
+
+exit 0
-- 
2.35.1


  reply	other threads:[~2022-08-18 20:22 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-18 20:22 [PATCH 00/12] Updates and fixes for documentation and Fedora package Stefano Brivio
2022-08-18 20:22 ` Stefano Brivio [this message]
2022-08-18 20:22 ` [PATCH 02/12] README: Add link to Copr repositories Stefano Brivio
2022-08-18 20:22 ` [PATCH 03/12] Makefile: Ugly hack to get a "plain" Markdown version of README Stefano Brivio
2022-08-18 20:22 ` [PATCH 04/12] Makefile: Install demo.sh too, uninstall stuff under /usr/share Stefano Brivio
2022-08-18 20:22 ` [PATCH 05/12] fedora: Install "plain" README, instead of web version, and demo script Stefano Brivio
2022-08-18 20:22 ` [PATCH 06/12] fedora: Introduce own rpkg macro for changelog Stefano Brivio
2022-08-18 20:22 ` [PATCH 07/12] fedora: Start Release tag from 1, not 0 Stefano Brivio
2022-08-18 20:22 ` [PATCH 08/12] fedora: Drop VCS tag from spec file Stefano Brivio
2022-08-18 20:22 ` [PATCH 09/12] fedora: Change source URL to HEAD link with explicit commit SHA Stefano Brivio
2022-08-18 20:22 ` [PATCH 10/12] fedora: Build SELinux subpackage as noarch Stefano Brivio
2022-08-18 20:22 ` [PATCH 11/12] fedora: Don't hardcode CFLAGS setting, use %set_build_flags macro instead Stefano Brivio
2022-08-18 20:22 ` [PATCH 12/12] fedora: Fix man pages wildcards in spec file Stefano Brivio

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220818202235.1591828-2-sbrivio@redhat.com \
    --to=sbrivio@redhat.com \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).