<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/docker-playground/+/23560">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add ttcn3-ns-test-fr container<br><br>... which requires some modifications to osmo-ns-master<br>regarding pipework / docker-entrypoint.sh<br><br>Change-Id: I418f81eb1fbb2b15335ef64a3aa04d1c98a452c9<br>Related: SYS#5396<br>---<br>M osmo-ns-master/Dockerfile<br>A osmo-ns-master/docker-entrypoint.sh<br>A osmo-ns-master/pipework<br>A ttcn3-ns-test-fr/fr<br>A ttcn3-ns-test-fr/jenkins.sh<br>A ttcn3-ns-test-fr/netdev-to-docker.sh<br>A ttcn3-ns-test/fr/NS_Tests.cfg<br>A ttcn3-ns-test/fr/osmo-ns-dummy.cfg<br>A ttcn3-ns-test/jenkins-fr.sh<br>9 files changed, 691 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/docker-playground refs/changes/60/23560/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/osmo-ns-master/Dockerfile b/osmo-ns-master/Dockerfile</span><br><span>index 283c410..1185253 100644</span><br><span>--- a/osmo-ns-master/Dockerfile</span><br><span>+++ b/osmo-ns-master/Dockerfile</span><br><span>@@ -39,7 +39,12 @@</span><br><span> </span><br><span> COPY       osmo-ns-dummy.cfg /data/osmo-ns-dummy.cfg</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+# work-around for stupid docker not being able to properly deal with host netdevices or start</span><br><span style="color: hsl(120, 100%, 40%);">+# containers in pre-existing netns</span><br><span style="color: hsl(120, 100%, 40%);">+COPY  pipework                /usr/bin/pipework</span><br><span style="color: hsl(120, 100%, 40%);">+COPY docker-entrypoint.sh    /docker-entrypoint.sh</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> WORKDIR      /data</span><br><span style="color: hsl(0, 100%, 40%);">-CMD        ["/usr/local/bin/osmo-ns-dummy", "-p", "13245"]</span><br><span style="color: hsl(120, 100%, 40%);">+CMD      ["/docker-entrypoint.sh"]</span><br><span> </span><br><span> #EXPOSE</span><br><span>diff --git a/osmo-ns-master/docker-entrypoint.sh b/osmo-ns-master/docker-entrypoint.sh</span><br><span>new file mode 100755</span><br><span>index 0000000..7bb480d</span><br><span>--- /dev/null</span><br><span>+++ b/osmo-ns-master/docker-entrypoint.sh</span><br><span>@@ -0,0 +1,9 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/bin/bash</span><br><span style="color: hsl(120, 100%, 40%);">+set -e</span><br><span style="color: hsl(120, 100%, 40%);">+set -x</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if [[ -n ${WAIT_FOR_NETDEV:-} ]]; then</span><br><span style="color: hsl(120, 100%, 40%);">+      /usr/bin/pipework --wait -i ${WAIT_FOR_NETDEV}</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/usr/local/bin/osmo-ns-dummy -c /data/osmo-ns-dummy.cfg -p 4240 >/data/osmo-ns-dummy.log 2>&1</span><br><span>diff --git a/osmo-ns-master/pipework b/osmo-ns-master/pipework</span><br><span>new file mode 100755</span><br><span>index 0000000..97ce66b</span><br><span>--- /dev/null</span><br><span>+++ b/osmo-ns-master/pipework</span><br><span>@@ -0,0 +1,489 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/bin/sh</span><br><span style="color: hsl(120, 100%, 40%);">+# This code should (try to) follow Google's Shell Style Guide</span><br><span style="color: hsl(120, 100%, 40%);">+# (https://google.github.io/styleguide/shell.xml)</span><br><span style="color: hsl(120, 100%, 40%);">+set -e</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+case "$1" in</span><br><span style="color: hsl(120, 100%, 40%);">+  --wait)</span><br><span style="color: hsl(120, 100%, 40%);">+    WAIT=1</span><br><span style="color: hsl(120, 100%, 40%);">+    ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  --direct-phys)</span><br><span style="color: hsl(120, 100%, 40%);">+    DIRECT_PHYS=1</span><br><span style="color: hsl(120, 100%, 40%);">+    shift</span><br><span style="color: hsl(120, 100%, 40%);">+    ;;</span><br><span style="color: hsl(120, 100%, 40%);">+esac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+IFNAME=$1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# default value set further down if not set here</span><br><span style="color: hsl(120, 100%, 40%);">+CONTAINER_IFNAME=</span><br><span style="color: hsl(120, 100%, 40%);">+if [ "$2" = "-i" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  CONTAINER_IFNAME=$3</span><br><span style="color: hsl(120, 100%, 40%);">+  shift 2</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if [ "$2" = "-l" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  LOCAL_IFNAME=$3</span><br><span style="color: hsl(120, 100%, 40%);">+  shift 2</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#inet or inet6</span><br><span style="color: hsl(120, 100%, 40%);">+FAMILY_FLAG="-4"</span><br><span style="color: hsl(120, 100%, 40%);">+if [ "$2" = "-a" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  FAMILY_FLAG="-$3"</span><br><span style="color: hsl(120, 100%, 40%);">+  shift 2</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GUESTNAME=$2</span><br><span style="color: hsl(120, 100%, 40%);">+IPADDR=$3</span><br><span style="color: hsl(120, 100%, 40%);">+MACADDR=$4</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+case "$MACADDR" in</span><br><span style="color: hsl(120, 100%, 40%);">+  *@*)</span><br><span style="color: hsl(120, 100%, 40%);">+    VLAN="${MACADDR#*@}"</span><br><span style="color: hsl(120, 100%, 40%);">+    VLAN="${VLAN%%@*}"</span><br><span style="color: hsl(120, 100%, 40%);">+    MACADDR="${MACADDR%%@*}"</span><br><span style="color: hsl(120, 100%, 40%);">+    ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  *)</span><br><span style="color: hsl(120, 100%, 40%);">+    VLAN=</span><br><span style="color: hsl(120, 100%, 40%);">+    ;;</span><br><span style="color: hsl(120, 100%, 40%);">+esac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# did they ask to generate a custom MACADDR?</span><br><span style="color: hsl(120, 100%, 40%);">+# generate the unique string</span><br><span style="color: hsl(120, 100%, 40%);">+case "$MACADDR" in</span><br><span style="color: hsl(120, 100%, 40%);">+  U:*)</span><br><span style="color: hsl(120, 100%, 40%);">+    macunique="${MACADDR#*:}"</span><br><span style="color: hsl(120, 100%, 40%);">+    # now generate a 48-bit hash string from $macunique</span><br><span style="color: hsl(120, 100%, 40%);">+    MACADDR=$(echo $macunique|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/')</span><br><span style="color: hsl(120, 100%, 40%);">+   ;;</span><br><span style="color: hsl(120, 100%, 40%);">+esac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IPADDR" ] || [ "$WAIT" ] || {</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "Syntax:"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] [-a addressfamily] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] <guest> dhcp [macaddr][@vlan]"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework mac:<hostinterface_macaddress> [-i containerinterface] [-l localinterfacename] [-a addressfamily] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework mac:<hostinterface_macaddress> [-i containerinterface] [-l localinterfacename] <guest> dhcp [macaddr][@vlan]"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework route <guest> <route_command>"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework rule <guest> <rule_command>"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework tc <guest> <tc_command>"</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "pipework --wait [-i containerinterface]"</span><br><span style="color: hsl(120, 100%, 40%);">+  exit 1</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Succeed if the given utility is installed. Fail otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+# For explanations about `which` vs `type` vs `command`, see:</span><br><span style="color: hsl(120, 100%, 40%);">+# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212</span><br><span style="color: hsl(120, 100%, 40%);">+# (Thanks to @chenhanxiao for pointing this out!)</span><br><span style="color: hsl(120, 100%, 40%);">+installed () {</span><br><span style="color: hsl(120, 100%, 40%);">+  command -v "$1" >/dev/null 2>&1</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Google Styleguide says error messages should go to standard error.</span><br><span style="color: hsl(120, 100%, 40%);">+warn () {</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "$@" >&2</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+die () {</span><br><span style="color: hsl(120, 100%, 40%);">+  status="$1"</span><br><span style="color: hsl(120, 100%, 40%);">+  shift</span><br><span style="color: hsl(120, 100%, 40%);">+  warn "$@"</span><br><span style="color: hsl(120, 100%, 40%);">+  exit "$status"</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if echo $IFNAME | grep -q '^mac:'; then</span><br><span style="color: hsl(120, 100%, 40%);">+  mac_address=$(echo $IFNAME | cut -c5-)</span><br><span style="color: hsl(120, 100%, 40%);">+  ifmatch=</span><br><span style="color: hsl(120, 100%, 40%);">+  for iftest in /sys/class/net/*; do</span><br><span style="color: hsl(120, 100%, 40%);">+    if [ -f $iftest/address ] && [ "$mac_address" = "$(cat $iftest/address)" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+      ifmatch="$(basename $iftest)"</span><br><span style="color: hsl(120, 100%, 40%);">+      break</span><br><span style="color: hsl(120, 100%, 40%);">+    fi</span><br><span style="color: hsl(120, 100%, 40%);">+  done</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if [ -z "$ifmatch" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+    die 1 "Mac address $mac_address specified for interface but no host interface matched."</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+    IFNAME=$ifmatch</span><br><span style="color: hsl(120, 100%, 40%);">+  fi</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# First step: determine type of first argument (bridge, physical interface...),</span><br><span style="color: hsl(120, 100%, 40%);">+# Unless "--wait" is set (then skip the whole section)</span><br><span style="color: hsl(120, 100%, 40%);">+if [ -z "$WAIT" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  if [ -d "/sys/class/net/$IFNAME" ]</span><br><span style="color: hsl(120, 100%, 40%);">+  then</span><br><span style="color: hsl(120, 100%, 40%);">+    if [ -d "/sys/class/net/$IFNAME/bridge" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+      IFTYPE=bridge</span><br><span style="color: hsl(120, 100%, 40%);">+      BRTYPE=linux</span><br><span style="color: hsl(120, 100%, 40%);">+    elif installed ovs-vsctl && ovs-vsctl list-br|grep -q "^${IFNAME}$"; then</span><br><span style="color: hsl(120, 100%, 40%);">+      IFTYPE=bridge</span><br><span style="color: hsl(120, 100%, 40%);">+      BRTYPE=openvswitch</span><br><span style="color: hsl(120, 100%, 40%);">+    elif [ "$(cat "/sys/class/net/$IFNAME/type")" -eq 32 ]; then # InfiniBand IPoIB interface type 32</span><br><span style="color: hsl(120, 100%, 40%);">+      IFTYPE=ipoib</span><br><span style="color: hsl(120, 100%, 40%);">+      # The IPoIB kernel module is fussy, set device name to ib0 if not overridden</span><br><span style="color: hsl(120, 100%, 40%);">+      CONTAINER_IFNAME=${CONTAINER_IFNAME:-ib0}</span><br><span style="color: hsl(120, 100%, 40%);">+      PKEY=$VLAN</span><br><span style="color: hsl(120, 100%, 40%);">+    else IFTYPE=phys</span><br><span style="color: hsl(120, 100%, 40%);">+    fi</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+    case "$IFNAME" in</span><br><span style="color: hsl(120, 100%, 40%);">+      br*)</span><br><span style="color: hsl(120, 100%, 40%);">+        IFTYPE=bridge</span><br><span style="color: hsl(120, 100%, 40%);">+        BRTYPE=linux</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+      ovs*)</span><br><span style="color: hsl(120, 100%, 40%);">+        if ! installed ovs-vsctl; then</span><br><span style="color: hsl(120, 100%, 40%);">+          die 1 "Need OVS installed on the system to create an ovs bridge"</span><br><span style="color: hsl(120, 100%, 40%);">+        fi</span><br><span style="color: hsl(120, 100%, 40%);">+        IFTYPE=bridge</span><br><span style="color: hsl(120, 100%, 40%);">+        BRTYPE=openvswitch</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+      route*)</span><br><span style="color: hsl(120, 100%, 40%);">+        IFTYPE=route</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+      rule*)</span><br><span style="color: hsl(120, 100%, 40%);">+        IFTYPE=rule</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+      tc*)</span><br><span style="color: hsl(120, 100%, 40%);">+        IFTYPE=tc</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+      dummy*)</span><br><span style="color: hsl(120, 100%, 40%);">+        IFTYPE=dummy</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+      *) die 1 "I do not know how to setup interface $IFNAME." ;;</span><br><span style="color: hsl(120, 100%, 40%);">+    esac</span><br><span style="color: hsl(120, 100%, 40%);">+  fi</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Set the default container interface name to eth1 if not already set</span><br><span style="color: hsl(120, 100%, 40%);">+CONTAINER_IFNAME=${CONTAINER_IFNAME:-eth1}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$WAIT" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  while true; do</span><br><span style="color: hsl(120, 100%, 40%);">+    # This first method works even without `ip` or `ifconfig` installed,</span><br><span style="color: hsl(120, 100%, 40%);">+    # but doesn't work on older kernels (e.g. CentOS 6.X). See #128.</span><br><span style="color: hsl(120, 100%, 40%);">+    grep -q '^1$' "/sys/class/net/$CONTAINER_IFNAME/carrier" && break</span><br><span style="color: hsl(120, 100%, 40%);">+    # This method hopefully works on those older kernels.</span><br><span style="color: hsl(120, 100%, 40%);">+    ip link ls dev "$CONTAINER_IFNAME" && break</span><br><span style="color: hsl(120, 100%, 40%);">+    sleep 1</span><br><span style="color: hsl(120, 100%, 40%);">+  done > /dev/null 2>&1</span><br><span style="color: hsl(120, 100%, 40%);">+  exit 0</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = bridge ] && [ "$BRTYPE" = linux ] && [ "$VLAN" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  die 1 "VLAN configuration currently unsupported for Linux bridge."</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = ipoib ] && [ "$MACADDR" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  die 1 "MACADDR configuration unsupported for IPoIB interfaces."</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Second step: find the guest (for now, we only support LXC containers)</span><br><span style="color: hsl(120, 100%, 40%);">+while read _ mnt fstype options _; do</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$fstype" != "cgroup" ] && continue</span><br><span style="color: hsl(120, 100%, 40%);">+  echo "$options" | grep -qw devices || continue</span><br><span style="color: hsl(120, 100%, 40%);">+  CGROUPMNT=$mnt</span><br><span style="color: hsl(120, 100%, 40%);">+done < /proc/mounts</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$CGROUPMNT" ] || {</span><br><span style="color: hsl(120, 100%, 40%);">+    die 1 "Could not locate cgroup mount point."</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Try to find a cgroup matching exactly the provided name.</span><br><span style="color: hsl(120, 100%, 40%);">+M=$(find "$CGROUPMNT" -name "$GUESTNAME")</span><br><span style="color: hsl(120, 100%, 40%);">+N=$(echo "$M" | wc -l)</span><br><span style="color: hsl(120, 100%, 40%);">+if [ -z "$M" ] ; then</span><br><span style="color: hsl(120, 100%, 40%);">+    N=0</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+case "$N" in</span><br><span style="color: hsl(120, 100%, 40%);">+  0)</span><br><span style="color: hsl(120, 100%, 40%);">+    # If we didn't find anything, try to lookup the container with Docker.</span><br><span style="color: hsl(120, 100%, 40%);">+    if installed docker; then</span><br><span style="color: hsl(120, 100%, 40%);">+      RETRIES=3</span><br><span style="color: hsl(120, 100%, 40%);">+      while [ "$RETRIES" -gt 0 ]; do</span><br><span style="color: hsl(120, 100%, 40%);">+        DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' "$GUESTNAME")</span><br><span style="color: hsl(120, 100%, 40%);">+        DOCKERCID=$(docker inspect --format='{{ .ID }}' "$GUESTNAME")</span><br><span style="color: hsl(120, 100%, 40%);">+        DOCKERCNAME=$(docker inspect --format='{{ .Name }}' "$GUESTNAME")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        [ "$DOCKERPID" != 0 ] && break</span><br><span style="color: hsl(120, 100%, 40%);">+        sleep 1</span><br><span style="color: hsl(120, 100%, 40%);">+        RETRIES=$((RETRIES - 1))</span><br><span style="color: hsl(120, 100%, 40%);">+      done</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      [ "$DOCKERPID" = 0 ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+        die 1 "Docker inspect returned invalid PID 0"</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      [ "$DOCKERPID" = "<no value>" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+        die 1 "Container $GUESTNAME not found, and unknown to Docker."</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+    else</span><br><span style="color: hsl(120, 100%, 40%);">+      die 1 "Container $GUESTNAME not found, and Docker not installed."</span><br><span style="color: hsl(120, 100%, 40%);">+    fi</span><br><span style="color: hsl(120, 100%, 40%);">+    ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  1) true ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  2)  # LXC >=3.1.0 returns two entries from the cgroups mount instead of one.</span><br><span style="color: hsl(120, 100%, 40%);">+      echo "$M" | grep -q "lxc\.monitor" || die 1 "Found more than one container matching $GUESTNAME."</span><br><span style="color: hsl(120, 100%, 40%);">+      ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  *) die 1 "Found more than one container matching $GUESTNAME." ;;</span><br><span style="color: hsl(120, 100%, 40%);">+esac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# only check IPADDR if we are not in a route mode</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" != route ] && [ "$IFTYPE" != rule ] && [ "$IFTYPE" != tc ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  case "$IPADDR" in</span><br><span style="color: hsl(120, 100%, 40%);">+    # Let's check first if the user asked for DHCP allocation.</span><br><span style="color: hsl(120, 100%, 40%);">+        dhcp|dhcp:*)</span><br><span style="color: hsl(120, 100%, 40%);">+            # Use Docker-specific strategy to run the DHCP client</span><br><span style="color: hsl(120, 100%, 40%);">+         # from the busybox image, in the network namespace of</span><br><span style="color: hsl(120, 100%, 40%);">+         # the container.</span><br><span style="color: hsl(120, 100%, 40%);">+      if ! [ "$DOCKERPID" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+           warn "You asked for a Docker-specific DHCP method."</span><br><span style="color: hsl(120, 100%, 40%);">+         warn "However, $GUESTNAME doesn't seem to be a Docker container."</span><br><span style="color: hsl(120, 100%, 40%);">+       warn "Try to replace 'dhcp' with another option?"</span><br><span style="color: hsl(120, 100%, 40%);">+           die 1 "Aborting."</span><br><span style="color: hsl(120, 100%, 40%);">+         fi</span><br><span style="color: hsl(120, 100%, 40%);">+            DHCP_CLIENT=${IPADDR%%:*}</span><br><span style="color: hsl(120, 100%, 40%);">+     ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          udhcpc|udhcpc:*|udhcpc-f|udhcpc-f:*|dhcpcd|dhcpcd:*|dhclient|dhclient:*|dhclient-f|dhclient-f:*)</span><br><span style="color: hsl(120, 100%, 40%);">+        DHCP_CLIENT=${IPADDR%%:*}</span><br><span style="color: hsl(120, 100%, 40%);">+     # did they ask for the client to remain?</span><br><span style="color: hsl(120, 100%, 40%);">+      DHCP_FOREGROUND=</span><br><span style="color: hsl(120, 100%, 40%);">+      [ "${DHCP_CLIENT%-f}" != "${DHCP_CLIENT}" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+            DHCP_FOREGROUND=true</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     DHCP_CLIENT=${DHCP_CLIENT%-f}</span><br><span style="color: hsl(120, 100%, 40%);">+         if ! installed "$DHCP_CLIENT"; then</span><br><span style="color: hsl(120, 100%, 40%);">+           die 1 "You asked for DHCP client $DHCP_CLIENT, but I can't find it."</span><br><span style="color: hsl(120, 100%, 40%);">+          fi</span><br><span style="color: hsl(120, 100%, 40%);">+            ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          # Alright, no DHCP? Then let's see if we have a subnet *and* gateway.</span><br><span style="color: hsl(120, 100%, 40%);">+     */*@*)</span><br><span style="color: hsl(120, 100%, 40%);">+          GATEWAY="${IPADDR#*@}" GATEWAY="${GATEWAY%%@*}"</span><br><span style="color: hsl(120, 100%, 40%);">+           IPADDR="${IPADDR%%@*}"</span><br><span style="color: hsl(120, 100%, 40%);">+      ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          # No gateway? We need at least a subnet, anyway!</span><br><span style="color: hsl(120, 100%, 40%);">+      */*) : ;;</span><br><span style="color: hsl(120, 100%, 40%);">+     # ... No? Then stop right here.</span><br><span style="color: hsl(120, 100%, 40%);">+       *)</span><br><span style="color: hsl(120, 100%, 40%);">+      warn "The IP address should include a netmask."</span><br><span style="color: hsl(120, 100%, 40%);">+     die 1 "Maybe you meant $IPADDR/24 ?"</span><br><span style="color: hsl(120, 100%, 40%);">+        ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  esac</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# If a DHCP method was specified, extract the DHCP options.</span><br><span style="color: hsl(120, 100%, 40%);">+if [ "$DHCP_CLIENT" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  case "$IPADDR" in</span><br><span style="color: hsl(120, 100%, 40%);">+    *:*) DHCP_OPTIONS="${IPADDR#*:}" ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  esac</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if [ "$DOCKERPID" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  NSPID=$DOCKERPID</span><br><span style="color: hsl(120, 100%, 40%);">+else</span><br><span style="color: hsl(120, 100%, 40%);">+  NSPID=$(head -n 1 "$(find "$CGROUPMNT" -name "$GUESTNAME" | head -n 1)/tasks")</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$NSPID" ] || {</span><br><span style="color: hsl(120, 100%, 40%);">+    # it is an alternative way to get the pid</span><br><span style="color: hsl(120, 100%, 40%);">+    NSPID=$(lxc-info -n  "$GUESTNAME" | grep PID | grep -Eo '[0-9]+')</span><br><span style="color: hsl(120, 100%, 40%);">+    [ "$NSPID" ] || {</span><br><span style="color: hsl(120, 100%, 40%);">+      die 1 "Could not find a process inside container $GUESTNAME."</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Check if an incompatible VLAN device already exists</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = phys ] && [ "$VLAN" ] && [ -d "/sys/class/net/$IFNAME.VLAN" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  ip -d link show "$IFNAME.$VLAN" | grep -q "vlan.*id $VLAN" || {</span><br><span style="color: hsl(120, 100%, 40%);">+    die 1 "$IFNAME.VLAN already exists but is not a VLAN device for tag $VLAN"</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ ! -d /var/run/netns ] && mkdir -p /var/run/netns</span><br><span style="color: hsl(120, 100%, 40%);">+rm -f "/var/run/netns/$NSPID"</span><br><span style="color: hsl(120, 100%, 40%);">+ln -s "/proc/$NSPID/ns/net" "/var/run/netns/$NSPID"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# Check if we need to create a bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = bridge ] && [ ! -d "/sys/class/net/$IFNAME" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$BRTYPE" = linux ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+    (ip link add dev "$IFNAME" type bridge > /dev/null 2>&1) || (brctl addbr "$IFNAME")</span><br><span style="color: hsl(120, 100%, 40%);">+    ip link set "$IFNAME" up</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$BRTYPE" = openvswitch ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+    ovs-vsctl add-br "$IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" != "route" ] && [ "$IFTYPE" != "dummy" ] && [ "$IFTYPE" != "rule" ] && [ "$IFTYPE" != "tc" ] && MTU=$(ip link show "$IFNAME" | awk '{print $5}')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# If it's a bridge, we need to create a veth pair</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = bridge ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  if [ -z "$LOCAL_IFNAME" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+    LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}"</span><br><span style="color: hsl(120, 100%, 40%);">+  fi</span><br><span style="color: hsl(120, 100%, 40%);">+  GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}"</span><br><span style="color: hsl(120, 100%, 40%);">+  # Does the link already exist?</span><br><span style="color: hsl(120, 100%, 40%);">+  if ip link show "$LOCAL_IFNAME" >/dev/null 2>&1; then</span><br><span style="color: hsl(120, 100%, 40%);">+    # link exists, is it in use?</span><br><span style="color: hsl(120, 100%, 40%);">+    if ip link show "$LOCAL_IFNAME" up | grep -q "UP"; then</span><br><span style="color: hsl(120, 100%, 40%);">+      echo "Link $LOCAL_IFNAME exists and is up"</span><br><span style="color: hsl(120, 100%, 40%);">+      exit 1</span><br><span style="color: hsl(120, 100%, 40%);">+    fi</span><br><span style="color: hsl(120, 100%, 40%);">+    # delete the link so we can re-add it afterwards</span><br><span style="color: hsl(120, 100%, 40%);">+    ip link del "$LOCAL_IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+  fi</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link add name "$LOCAL_IFNAME" mtu "$MTU" type veth peer name "$GUEST_IFNAME" mtu "$MTU"</span><br><span style="color: hsl(120, 100%, 40%);">+  case "$BRTYPE" in</span><br><span style="color: hsl(120, 100%, 40%);">+    linux)</span><br><span style="color: hsl(120, 100%, 40%);">+      (ip link set "$LOCAL_IFNAME" master "$IFNAME" > /dev/null 2>&1) || (brctl addif "$IFNAME" "$LOCAL_IFNAME")</span><br><span style="color: hsl(120, 100%, 40%);">+      ;;</span><br><span style="color: hsl(120, 100%, 40%);">+    openvswitch)</span><br><span style="color: hsl(120, 100%, 40%);">+      if ! ovs-vsctl list-ports "$IFNAME" | grep -q "^${LOCAL_IFNAME}$"; then</span><br><span style="color: hsl(120, 100%, 40%);">+        ovs-vsctl add-port "$IFNAME" "$LOCAL_IFNAME" ${VLAN:+tag="$VLAN"} \</span><br><span style="color: hsl(120, 100%, 40%);">+            -- set Interface "$LOCAL_IFNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                external-ids:pipework.interface="$LOCAL_IFNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                external-ids:pipework.bridge="$IFNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                ${DOCKERCID:+external-ids:pipework.containerid="$DOCKERCID"} \</span><br><span style="color: hsl(120, 100%, 40%);">+                ${DOCKERCNAME:+external-ids:pipework.containername="$DOCKERCNAME"} \</span><br><span style="color: hsl(120, 100%, 40%);">+                ${NSPID:+external-ids:pipework.nspid="$NSPID"} \</span><br><span style="color: hsl(120, 100%, 40%);">+                ${VLAN:+external-ids:pipework.vlan="$VLAN"}</span><br><span style="color: hsl(120, 100%, 40%);">+      fi</span><br><span style="color: hsl(120, 100%, 40%);">+      ;;</span><br><span style="color: hsl(120, 100%, 40%);">+  esac</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link set "$LOCAL_IFNAME" up</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# If it's a physical interface, create a macvlan subinterface</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = phys ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$VLAN" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+    [ ! -d "/sys/class/net/${IFNAME}.${VLAN}" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+      ip link add link "$IFNAME" name "$IFNAME.$VLAN" mtu "$MTU" type vlan id "$VLAN"</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+    ip link set "$IFNAME" up</span><br><span style="color: hsl(120, 100%, 40%);">+    IFNAME=$IFNAME.$VLAN</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if [ ! -z "$DIRECT_PHYS" ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+    GUEST_IFNAME=$IFNAME</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+    GUEST_IFNAME=ph$NSPID$CONTAINER_IFNAME</span><br><span style="color: hsl(120, 100%, 40%);">+    ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge</span><br><span style="color: hsl(120, 100%, 40%);">+  fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link set "$IFNAME" up</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# If it's an IPoIB interface, create a virtual IPoIB interface (the IPoIB</span><br><span style="color: hsl(120, 100%, 40%);">+# equivalent of a macvlan device)</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Note: no macvlan subinterface nor Ethernet bridge can be created on top of an</span><br><span style="color: hsl(120, 100%, 40%);">+# IPoIB interface. InfiniBand is not Ethernet. IPoIB is an IP layer on top of</span><br><span style="color: hsl(120, 100%, 40%);">+# InfiniBand, without an intermediate Ethernet layer.</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = ipoib ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  GUEST_IFNAME="${IFNAME}.${NSPID}"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  # If a partition key is provided, use it</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$PKEY" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+    GUEST_IFNAME="${IFNAME}.${PKEY}.${NSPID}"</span><br><span style="color: hsl(120, 100%, 40%);">+    PKEY="pkey 0x$PKEY"</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link add link "$IFNAME" name "$GUEST_IFNAME" type ipoib $PKEY</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link set "$IFNAME" up</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# If its a dummy interface, create a dummy interface.</span><br><span style="color: hsl(120, 100%, 40%);">+[ "$IFTYPE" = dummy ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+  GUEST_IFNAME=du$NSPID$CONTAINER_IFNAME</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link add dev "$GUEST_IFNAME" type dummy</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# If the `route` command was specified ...</span><br><span style="color: hsl(120, 100%, 40%);">+if [ "$IFTYPE" = route ]; then</span><br><span style="color: hsl(120, 100%, 40%);">+  # ... discard the first two arguments and pass the rest to the route command.</span><br><span style="color: hsl(120, 100%, 40%);">+  shift 2</span><br><span style="color: hsl(120, 100%, 40%);">+  ip netns exec "$NSPID" ip route "$@"</span><br><span style="color: hsl(120, 100%, 40%);">+elif [ "$IFTYPE" = rule ] ; then</span><br><span style="color: hsl(120, 100%, 40%);">+  shift 2</span><br><span style="color: hsl(120, 100%, 40%);">+  ip netns exec "$NSPID" ip rule "$@"</span><br><span style="color: hsl(120, 100%, 40%);">+elif [ "$IFTYPE" = tc ] ; then</span><br><span style="color: hsl(120, 100%, 40%);">+  shift 2</span><br><span style="color: hsl(120, 100%, 40%);">+  ip netns exec "$NSPID" tc "$@"</span><br><span style="color: hsl(120, 100%, 40%);">+else</span><br><span style="color: hsl(120, 100%, 40%);">+  # Otherwise, run normally.</span><br><span style="color: hsl(120, 100%, 40%);">+  ip link set "$GUEST_IFNAME" netns "$NSPID"</span><br><span style="color: hsl(120, 100%, 40%);">+  ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+  [ "$MACADDR" ] && ip netns exec "$NSPID" ip link set dev "$CONTAINER_IFNAME" address "$MACADDR"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   # When using any of the DHCP methods, we start a DHCP client in the</span><br><span style="color: hsl(120, 100%, 40%);">+   # network namespace of the container. With the 'dhcp' method, the</span><br><span style="color: hsl(120, 100%, 40%);">+     # client used is taken from the Docker busybox image (therefore</span><br><span style="color: hsl(120, 100%, 40%);">+       # requiring no specific client installed on the host). Other methods</span><br><span style="color: hsl(120, 100%, 40%);">+  # use a locally installed client.</span><br><span style="color: hsl(120, 100%, 40%);">+     case "$DHCP_CLIENT" in</span><br><span style="color: hsl(120, 100%, 40%);">+        dhcp)</span><br><span style="color: hsl(120, 100%, 40%);">+           docker run -d --net container:$GUESTNAME --cap-add NET_ADMIN \</span><br><span style="color: hsl(120, 100%, 40%);">+               busybox udhcpc -i "$CONTAINER_IFNAME" -x "hostname:$GUESTNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                  $DHCP_OPTIONS \</span><br><span style="color: hsl(120, 100%, 40%);">+               >/dev/null</span><br><span style="color: hsl(120, 100%, 40%);">+          ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          udhcpc)</span><br><span style="color: hsl(120, 100%, 40%);">+         DHCP_Q="-q"</span><br><span style="color: hsl(120, 100%, 40%);">+         [ "$DHCP_FOREGROUND" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+           DHCP_OPTIONS="$DHCP_OPTIONS -f"</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     ip netns exec "$NSPID" "$DHCP_CLIENT" -qi "$CONTAINER_IFNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                                               -x "hostname:$GUESTNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  -p "/var/run/udhcpc.$GUESTNAME.pid" \</span><br><span style="color: hsl(120, 100%, 40%);">+                                               $DHCP_OPTIONS</span><br><span style="color: hsl(120, 100%, 40%);">+           [ ! "$DHCP_FOREGROUND" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+         rm "/var/run/udhcpc.$GUESTNAME.pid"</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          dhclient)</span><br><span style="color: hsl(120, 100%, 40%);">+       ip netns exec "$NSPID" "$DHCP_CLIENT" "$CONTAINER_IFNAME" \</span><br><span style="color: hsl(120, 100%, 40%);">+                                           -pf "/var/run/dhclient.$GUESTNAME.pid" \</span><br><span style="color: hsl(120, 100%, 40%);">+                                            -lf "/etc/dhclient/dhclient.$GUESTNAME.leases" \</span><br><span style="color: hsl(120, 100%, 40%);">+                                            $DHCP_OPTIONS</span><br><span style="color: hsl(120, 100%, 40%);">+           # kill dhclient after get ip address to prevent device be used after container close</span><br><span style="color: hsl(120, 100%, 40%);">+          [ ! "$DHCP_FOREGROUND" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+         kill "$(cat "/var/run/dhclient.$GUESTNAME.pid")"</span><br><span style="color: hsl(120, 100%, 40%);">+          rm "/var/run/dhclient.$GUESTNAME.pid"</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          dhcpcd)</span><br><span style="color: hsl(120, 100%, 40%);">+         ip netns exec "$NSPID" "$DHCP_CLIENT" -q "$CONTAINER_IFNAME" -h "$GUESTNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+          ;;</span><br><span style="color: hsl(120, 100%, 40%);">+          "")</span><br><span style="color: hsl(120, 100%, 40%);">+           if installed ipcalc; then</span><br><span style="color: hsl(120, 100%, 40%);">+       eval $(ipcalc -b $IPADDR)</span><br><span style="color: hsl(120, 100%, 40%);">+             ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" brd "$BROADCAST" dev "$CONTAINER_IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+            ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" dev "$CONTAINER_IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+         fi</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          [ "$GATEWAY" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+           ip netns exec "$NSPID" ip "$FAMILY_FLAG" route delete default >/dev/null 2>&1 && true</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+     ip netns exec "$NSPID" ip "$FAMILY_FLAG" link set "$CONTAINER_IFNAME" up</span><br><span style="color: hsl(120, 100%, 40%);">+        [ "$GATEWAY" ] && {</span><br><span style="color: hsl(120, 100%, 40%);">+           ip netns exec "$NSPID" ip "$FAMILY_FLAG" route get "$GATEWAY" >/dev/null 2>&1 || \</span><br><span style="color: hsl(120, 100%, 40%);">+            ip netns exec "$NSPID" ip "$FAMILY_FLAG" route add "$GATEWAY/32" dev "$CONTAINER_IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+              ip netns exec "$NSPID" ip "$FAMILY_FLAG" route replace default via "$GATEWAY" dev "$CONTAINER_IFNAME"</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ;;</span><br><span style="color: hsl(120, 100%, 40%);">+        esac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  # Give our ARP neighbors a nudge about the new interface</span><br><span style="color: hsl(120, 100%, 40%);">+  if installed arping; then</span><br><span style="color: hsl(120, 100%, 40%);">+    IPADDR=$(echo "$IPADDR" | cut -d/ -f1)</span><br><span style="color: hsl(120, 100%, 40%);">+    ip netns exec "$NSPID" arping -c 1 -A -I "$CONTAINER_IFNAME" "$IPADDR" > /dev/null 2>&1 || true</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+    echo "Warning: arping not found; interface may not be immediately reachable"</span><br><span style="color: hsl(120, 100%, 40%);">+  fi</span><br><span style="color: hsl(120, 100%, 40%);">+fi</span><br><span style="color: hsl(120, 100%, 40%);">+# Remove NSPID to avoid `ip netns` catch it.</span><br><span style="color: hsl(120, 100%, 40%);">+rm -f "/var/run/netns/$NSPID"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab :</span><br><span>diff --git a/ttcn3-ns-test-fr/fr b/ttcn3-ns-test-fr/fr</span><br><span>new file mode 120000</span><br><span>index 0000000..ce2797b</span><br><span>--- /dev/null</span><br><span>+++ b/ttcn3-ns-test-fr/fr</span><br><span>@@ -0,0 +1 @@</span><br><span style="color: hsl(120, 100%, 40%);">+../ttcn3-ns-test/fr</span><br><span>\ No newline at end of file</span><br><span>diff --git a/ttcn3-ns-test-fr/jenkins.sh b/ttcn3-ns-test-fr/jenkins.sh</span><br><span>new file mode 120000</span><br><span>index 0000000..19f578b</span><br><span>--- /dev/null</span><br><span>+++ b/ttcn3-ns-test-fr/jenkins.sh</span><br><span>@@ -0,0 +1 @@</span><br><span style="color: hsl(120, 100%, 40%);">+../ttcn3-ns-test/jenkins-fr.sh</span><br><span>\ No newline at end of file</span><br><span>diff --git a/ttcn3-ns-test-fr/netdev-to-docker.sh b/ttcn3-ns-test-fr/netdev-to-docker.sh</span><br><span>new file mode 120000</span><br><span>index 0000000..3ae2cf8</span><br><span>--- /dev/null</span><br><span>+++ b/ttcn3-ns-test-fr/netdev-to-docker.sh</span><br><span>@@ -0,0 +1 @@</span><br><span style="color: hsl(120, 100%, 40%);">+../ttcn3-gbproxy-test-fr/netdev-to-docker.sh</span><br><span>\ No newline at end of file</span><br><span>diff --git a/ttcn3-ns-test/fr/NS_Tests.cfg b/ttcn3-ns-test/fr/NS_Tests.cfg</span><br><span>new file mode 100644</span><br><span>index 0000000..5ece397</span><br><span>--- /dev/null</span><br><span>+++ b/ttcn3-ns-test/fr/NS_Tests.cfg</span><br><span>@@ -0,0 +1,56 @@</span><br><span style="color: hsl(120, 100%, 40%);">+[ORDERED_INCLUDE]</span><br><span style="color: hsl(120, 100%, 40%);">+"/osmo-ttcn3-hacks/Common.cfg"</span><br><span style="color: hsl(120, 100%, 40%);">+"/osmo-ttcn3-hacks/ns/NS_Tests.default"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[LOGGING]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[TESTPORT_PARAMETERS]</span><br><span style="color: hsl(120, 100%, 40%);">+*.NSVTY.CTRL_HOSTNAME := "172.18.30.101"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[MODULE_PARAMETERS]</span><br><span style="color: hsl(120, 100%, 40%);">+NS_Tests.mp_dialect := NS2_DIALECT_IPACCESS</span><br><span style="color: hsl(120, 100%, 40%);">+NS_Tests.mp_nsconfig := {</span><br><span style="color: hsl(120, 100%, 40%);">+  nsei := 2001,</span><br><span style="color: hsl(120, 100%, 40%);">+ role_sgsn := false,</span><br><span style="color: hsl(120, 100%, 40%);">+   handle_sns := false,</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc := {</span><br><span style="color: hsl(120, 100%, 40%);">+             {</span><br><span style="color: hsl(120, 100%, 40%);">+                     provider := {</span><br><span style="color: hsl(120, 100%, 40%);">+                         fr := {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       netdev := "hdlc1",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  dlci := 16</span><br><span style="color: hsl(120, 100%, 40%);">+                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                     },</span><br><span style="color: hsl(120, 100%, 40%);">+                    nsvci := 1</span><br><span style="color: hsl(120, 100%, 40%);">+            }, {</span><br><span style="color: hsl(120, 100%, 40%);">+                  provider := {</span><br><span style="color: hsl(120, 100%, 40%);">+                         fr := {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       netdev := "hdlc2",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  dlci := 17</span><br><span style="color: hsl(120, 100%, 40%);">+                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                     },</span><br><span style="color: hsl(120, 100%, 40%);">+                    nsvci := 2</span><br><span style="color: hsl(120, 100%, 40%);">+            }, {</span><br><span style="color: hsl(120, 100%, 40%);">+                  provider := {</span><br><span style="color: hsl(120, 100%, 40%);">+                         fr := {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       netdev := "hdlc3",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  dlci := 18</span><br><span style="color: hsl(120, 100%, 40%);">+                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                     },</span><br><span style="color: hsl(120, 100%, 40%);">+                    nsvci := 3</span><br><span style="color: hsl(120, 100%, 40%);">+            }, {</span><br><span style="color: hsl(120, 100%, 40%);">+                  provider := {</span><br><span style="color: hsl(120, 100%, 40%);">+                         fr := {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       netdev := "hdlc4",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  dlci := 19</span><br><span style="color: hsl(120, 100%, 40%);">+                            }</span><br><span style="color: hsl(120, 100%, 40%);">+                     },</span><br><span style="color: hsl(120, 100%, 40%);">+                    nsvci := 4</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[MAIN_CONTROLLER]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[EXECUTE]</span><br><span style="color: hsl(120, 100%, 40%);">+NS_Tests.control</span><br><span>diff --git a/ttcn3-ns-test/fr/osmo-ns-dummy.cfg b/ttcn3-ns-test/fr/osmo-ns-dummy.cfg</span><br><span>new file mode 100644</span><br><span>index 0000000..0a3515d</span><br><span>--- /dev/null</span><br><span>+++ b/ttcn3-ns-test/fr/osmo-ns-dummy.cfg</span><br><span>@@ -0,0 +1,55 @@</span><br><span style="color: hsl(120, 100%, 40%);">+log gsmtap 172.18.30.10</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level set-all debug</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+log stderr</span><br><span style="color: hsl(120, 100%, 40%);">+ logging filter all 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print level 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print category 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print category-hex 0</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print file basename last</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print extended-timestamp 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level set-all debug</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+stats interval 0</span><br><span style="color: hsl(120, 100%, 40%);">+stats reporter statsd</span><br><span style="color: hsl(120, 100%, 40%);">+ prefix TTCN3</span><br><span style="color: hsl(120, 100%, 40%);">+ level subscriber</span><br><span style="color: hsl(120, 100%, 40%);">+ remote-ip 172.18.30.10</span><br><span style="color: hsl(120, 100%, 40%);">+ remote-port 8125</span><br><span style="color: hsl(120, 100%, 40%);">+ flush-period 1</span><br><span style="color: hsl(120, 100%, 40%);">+ mtu 1024</span><br><span style="color: hsl(120, 100%, 40%);">+ enable</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+line vty</span><br><span style="color: hsl(120, 100%, 40%);">+ no login</span><br><span style="color: hsl(120, 100%, 40%);">+ bind 172.18.30.101</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ns</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet1</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet1 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet2</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet2 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet3</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet3 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet4</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet4 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet5</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet5 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet6</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet6 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet7</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet7 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ bind fr hdlcnet8</span><br><span style="color: hsl(120, 100%, 40%);">+  fr hdlcnet8 frnet</span><br><span style="color: hsl(120, 100%, 40%);">+ nse 2001</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet1 dlci 16 nsvci 1</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet2 dlci 17 nsvci 2</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet3 dlci 18 nsvci 3</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet4 dlci 19 nsvci 4</span><br><span style="color: hsl(120, 100%, 40%);">+ nse 2002</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet5 dlci 20 nsvci 5</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet6 dlci 21 nsvci 6</span><br><span style="color: hsl(120, 100%, 40%);">+ nse 2003</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet7 dlci 22 nsvci 7</span><br><span style="color: hsl(120, 100%, 40%);">+  nsvc fr hdlcnet8 dlci 23 nsvci 8</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/ttcn3-ns-test/jenkins-fr.sh b/ttcn3-ns-test/jenkins-fr.sh</span><br><span>new file mode 100755</span><br><span>index 0000000..df23a35</span><br><span>--- /dev/null</span><br><span>+++ b/ttcn3-ns-test/jenkins-fr.sh</span><br><span>@@ -0,0 +1,73 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/bin/sh</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# WARNING: This cannot be executed on any random Linux machine or jenkins slave node!</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# We require a kernel with HLDC net-devices, specifically eight pairs of devices named</span><br><span style="color: hsl(120, 100%, 40%);">+# hdlc1 + hdlcnet1 ... hdlc8 + hdclnet8.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Those pairs of netdevices can e.g. be implemented by actually physically looping back</span><br><span style="color: hsl(120, 100%, 40%);">+# the related E1 interfaces, or e.g.by using DAHDI_NET + dahdi_dynamic_loc to create</span><br><span style="color: hsl(120, 100%, 40%);">+# pairs of virtual E1 spans.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# In addition, we need to use 'sudo' permissions in order to move the hdlc</span><br><span style="color: hsl(120, 100%, 40%);">+# net-devices into the docker containers. So in automatic test execution this means</span><br><span style="color: hsl(120, 100%, 40%);">+# that the user will need sudo privileges without entering a password (NOPASS)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+. ../jenkins-common.sh</span><br><span style="color: hsl(120, 100%, 40%);">+IMAGE_SUFFIX="${IMAGE_SUFFIX:-master}"</span><br><span style="color: hsl(120, 100%, 40%);">+docker_images_require \</span><br><span style="color: hsl(120, 100%, 40%);">+       "osmo-ns-$IMAGE_SUFFIX" \</span><br><span style="color: hsl(120, 100%, 40%);">+   "ttcn3-ns-test"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+set_clean_up_trap</span><br><span style="color: hsl(120, 100%, 40%);">+set -e</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+SUBNET=30</span><br><span style="color: hsl(120, 100%, 40%);">+network_create $SUBNET</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+mkdir $VOL_BASE_DIR/ns-tester</span><br><span style="color: hsl(120, 100%, 40%);">+cp fr/NS_Tests.cfg $VOL_BASE_DIR/ns-tester/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+mkdir $VOL_BASE_DIR/ns</span><br><span style="color: hsl(120, 100%, 40%);">+cp fr/osmo-ns-dummy.cfg $VOL_BASE_DIR/ns/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+echo Starting container with osmo-ns-dummy</span><br><span style="color: hsl(120, 100%, 40%);">+docker run        --rm \</span><br><span style="color: hsl(120, 100%, 40%);">+                --cap-add=NET_RAW --cap-add=SYS_RAWIO \</span><br><span style="color: hsl(120, 100%, 40%);">+               $(docker_network_params $SUBNET 101) \</span><br><span style="color: hsl(120, 100%, 40%);">+                --ulimit core=-1 \</span><br><span style="color: hsl(120, 100%, 40%);">+            -e "WAIT_FOR_NETDEV=hdlcnet8" \</span><br><span style="color: hsl(120, 100%, 40%);">+             -v $VOL_BASE_DIR/ns:/data \</span><br><span style="color: hsl(120, 100%, 40%);">+           --name ${BUILD_TAG}-ns -d \</span><br><span style="color: hsl(120, 100%, 40%);">+           $DOCKER_ARGS \</span><br><span style="color: hsl(120, 100%, 40%);">+                $REPO_USER/osmo-ns-$IMAGE_SUFFIX</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# move all hdlcX net-devices into container</span><br><span style="color: hsl(120, 100%, 40%);">+for i in `seq 1 8`; do</span><br><span style="color: hsl(120, 100%, 40%);">+       DEV="hdlcnet$i"</span><br><span style="color: hsl(120, 100%, 40%);">+     #sudo sethdlc ${DEV} fr lmi none</span><br><span style="color: hsl(120, 100%, 40%);">+      sudo ./netdev-to-docker.sh ${DEV} ${BUILD_TAG}-ns</span><br><span style="color: hsl(120, 100%, 40%);">+done</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+echo Starting container with NS testsuite</span><br><span style="color: hsl(120, 100%, 40%);">+docker run        --rm \</span><br><span style="color: hsl(120, 100%, 40%);">+                --cap-add=NET_RAW --cap-add=SYS_RAWIO \</span><br><span style="color: hsl(120, 100%, 40%);">+               $(docker_network_params $SUBNET 10) \</span><br><span style="color: hsl(120, 100%, 40%);">+         --ulimit core=-1 \</span><br><span style="color: hsl(120, 100%, 40%);">+            -e "TTCN3_PCAP_PATH=/data" \</span><br><span style="color: hsl(120, 100%, 40%);">+                -e "WAIT_FOR_NETDEV=hdlc8" \</span><br><span style="color: hsl(120, 100%, 40%);">+                -v $VOL_BASE_DIR/ns-tester:/data \</span><br><span style="color: hsl(120, 100%, 40%);">+            --name ${BUILD_TAG}-ttcn3-ns-test -d \</span><br><span style="color: hsl(120, 100%, 40%);">+                $DOCKER_ARGS \</span><br><span style="color: hsl(120, 100%, 40%);">+                $REPO_USER/ttcn3-ns-test</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# move all hdlcnetX net-devices into container</span><br><span style="color: hsl(120, 100%, 40%);">+for i in `seq 1 8`; do</span><br><span style="color: hsl(120, 100%, 40%);">+    DEV="hdlc$i"</span><br><span style="color: hsl(120, 100%, 40%);">+        #sudo sethdlc ${DEV} fr lmi none</span><br><span style="color: hsl(120, 100%, 40%);">+      sudo ./netdev-to-docker.sh ${DEV} ${BUILD_TAG}-ttcn3-ns-test</span><br><span style="color: hsl(120, 100%, 40%);">+done</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# emulate running container in foreground, which is no longer possible as we</span><br><span style="color: hsl(120, 100%, 40%);">+# must shift the net-devices into the container _after_ it is started</span><br><span style="color: hsl(120, 100%, 40%);">+docker logs  -f ${BUILD_TAG}-ttcn3-ns-test</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/docker-playground/+/23560">change 23560</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/docker-playground/+/23560"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: docker-playground </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I418f81eb1fbb2b15335ef64a3aa04d1c98a452c9 </div>
<div style="display:none"> Gerrit-Change-Number: 23560 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>