+ done
+ if ! $found; then
+ echo "$0: error: no open network found"
+ exit 1
+ fi
+}
+
+# ip add idempotent (if it doesn't exist already)
+ip-add() {
+ local cmd net dev
+ cmd=$1
+ net=$2
+ dev=$3
+ if ! $cmd addr show dev $dev | sed 's/^ *//;s/ *$//' | grep -xF "inet $net scope global $dev"; then
+ $cmd addr add $net dev $dev
+ fi
+
+}
+
+start() {
+ find-network
+
+ #### begin mount namespace setup ####
+ mkdir -p /run/mount-namespaces
+ if ! mountpoint /run/mount-namespaces >/dev/null; then
+ mount --bind /run/mount-namespaces /run/mount-namespaces
+ fi
+ # note: This is outside the mount condition because I've mysteriously
+ # had this become shared instead of private, perhaps it
+ # got remounted somehow and lost the setting.
+ mount --make-private /run/mount-namespaces
+ if [[ ! -e /run/mount-namespaces/$nn ]]; then
+ touch /run/mount-namespaces/$nn
+ fi
+ if ! mountpoint /run/mount-namespaces/$nn >/dev/null; then
+ # Here, we specify that we only want mount changes changes under
+ # this mountpoint to be propagated into the bind, but changes
+ # from within the bind do not propagate to outside the bind.
+ #
+ # slave is documented in.
+ # /usr/share/doc/linux-doc-4.9/Documentation/filesystems/sharedsubtree.txt.gz
+ # documentation on propagation is a bit weird because it
+ # confusingly talks about binds, namespaces, and mirrors (which
+ # seems to be just another name for bind), shared subtrees
+ # (which seems to be a term for binds and namespaces), and does not
+ # properly specify whether the documentation applies to binds,
+ # namespaces, or both. Notably, propagation for binds is marked
+ # on the original mount point, and propagation for a mount
+ # namespace is marked on mounts within the namespace.
+ unshare --propagation slave --mount=/run/mount-namespaces/$nn /bin/true
+ fi
+
+ #### end mount namespace setup ####
+
+
+ if $create; then
+ if ! ip netns | grep -xF $nn &>/dev/null; then
+ ip netns add $nn
+ fi
+ ip -n $nn link set dev lo up
+ fi
+
+ echo 1 | dexec dd of=/proc/sys/net/ipv4/ip_forward status=none
+
+ # docker helpfully changes the default FORWARD to drop...
+ diptables-add FORWARD -i $v0 -j ACCEPT
+ diptables-add FORWARD -o $v0 -j ACCEPT
+
+
+ err-cleanup() { stop; }
+ ipnn link add $v0 type veth peer name $v1
+ ipnn link set $v0 netns default
+ ip-add ipd $network.1/24 $v0
+ ipd link set $v0 up
+ nat -C &>/dev/null || nat -A
+ ip-add ipnn $network.2/24 $v1
+ ipnn link set $v1 up
+ cmd="ipnn route add default via $network.1"
+ $cmd
+ fails=0
+ max_fails=2
+ # I've had adding the default route mysteriously fail on boot, so
+ # here we check that it succeeded, do a sleep and a retry.
+ while true; do
+ default_route=$(ipnn route show default | sed -r 's,^[[:space:]]+|[[:space:]]+$,,')
+ if [[ $default_route != "default via $network.1 dev $v1" ]]; then
+ fails=$((fails + 1))
+ else
+ break