From 266cb2165c53cec139961910b78d10d9bbbcdffa Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Fri, 11 Feb 2022 10:30:16 +0100 Subject: [PATCH] common/pipework: deduplicate Move the pipework script from several image directories to the common dir. Change-Id: I88ff40ca69c9ee76bef9bb8f24f66ca9d5ac751a --- {debian-bullseye-titan => common}/pipework | 0 debian-bullseye-titan/Dockerfile | 2 +- osmo-gbproxy-latest/Dockerfile | 2 +- osmo-gbproxy-latest/pipework | 489 --------------------- osmo-gbproxy-master/Dockerfile | 2 +- osmo-gbproxy-master/pipework | 489 --------------------- osmo-ns-master/Dockerfile | 2 +- osmo-ns-master/pipework | 489 --------------------- 8 files changed, 4 insertions(+), 1471 deletions(-) rename {debian-bullseye-titan => common}/pipework (100%) delete mode 100755 osmo-gbproxy-latest/pipework delete mode 100755 osmo-gbproxy-master/pipework delete mode 100755 osmo-ns-master/pipework diff --git a/debian-bullseye-titan/pipework b/common/pipework similarity index 100% rename from debian-bullseye-titan/pipework rename to common/pipework diff --git a/debian-bullseye-titan/Dockerfile b/debian-bullseye-titan/Dockerfile index b4b65328..16b25b9d 100644 --- a/debian-bullseye-titan/Dockerfile +++ b/debian-bullseye-titan/Dockerfile @@ -70,4 +70,4 @@ RUN if ! diff -q /tmp/deps-Makefile /osmo-ttcn3-hacks/deps/Makefile; then \ ADD ttcn3-docker-prepare.sh /usr/local/bin/ttcn3-docker-prepare ADD ttcn3-docker-run.sh /usr/local/bin/ttcn3-docker-run -ADD pipework /usr/local/bin/pipework +ADD .common/pipework /usr/local/bin/pipework diff --git a/osmo-gbproxy-latest/Dockerfile b/osmo-gbproxy-latest/Dockerfile index 5e16f993..6f586639 100644 --- a/osmo-gbproxy-latest/Dockerfile +++ b/osmo-gbproxy-latest/Dockerfile @@ -31,7 +31,7 @@ COPY osmo-gbproxy.cfg /data/osmo-gbproxy.cfg # work-around for stupid docker not being able to properly deal with host netdevices or start # containers in pre-existing netns -COPY pipework /usr/bin/pipework +COPY .common/pipework /usr/bin/pipework COPY docker-entrypoint.sh /docker-entrypoint.sh CMD ["/docker-entrypoint.sh"] diff --git a/osmo-gbproxy-latest/pipework b/osmo-gbproxy-latest/pipework deleted file mode 100755 index 97ce66b5..00000000 --- a/osmo-gbproxy-latest/pipework +++ /dev/null @@ -1,489 +0,0 @@ -#!/bin/sh -# This code should (try to) follow Google's Shell Style Guide -# (https://google.github.io/styleguide/shell.xml) -set -e - -case "$1" in - --wait) - WAIT=1 - ;; - --direct-phys) - DIRECT_PHYS=1 - shift - ;; -esac - -IFNAME=$1 - -# default value set further down if not set here -CONTAINER_IFNAME= -if [ "$2" = "-i" ]; then - CONTAINER_IFNAME=$3 - shift 2 -fi - -if [ "$2" = "-l" ]; then - LOCAL_IFNAME=$3 - shift 2 -fi - -#inet or inet6 -FAMILY_FLAG="-4" -if [ "$2" = "-a" ]; then - FAMILY_FLAG="-$3" - shift 2 -fi - -GUESTNAME=$2 -IPADDR=$3 -MACADDR=$4 - -case "$MACADDR" in - *@*) - VLAN="${MACADDR#*@}" - VLAN="${VLAN%%@*}" - MACADDR="${MACADDR%%@*}" - ;; - *) - VLAN= - ;; -esac - -# did they ask to generate a custom MACADDR? -# generate the unique string -case "$MACADDR" in - U:*) - macunique="${MACADDR#*:}" - # now generate a 48-bit hash string from $macunique - MACADDR=$(echo $macunique|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/') - ;; -esac - - -[ "$IPADDR" ] || [ "$WAIT" ] || { - echo "Syntax:" - echo "pipework [-i containerinterface] [-l localinterfacename] [-a addressfamily] /[@default_gateway] [macaddr][@vlan]" - echo "pipework [-i containerinterface] [-l localinterfacename] dhcp [macaddr][@vlan]" - echo "pipework mac: [-i containerinterface] [-l localinterfacename] [-a addressfamily] /[@default_gateway] [macaddr][@vlan]" - echo "pipework mac: [-i containerinterface] [-l localinterfacename] dhcp [macaddr][@vlan]" - echo "pipework route " - echo "pipework rule " - echo "pipework tc " - echo "pipework --wait [-i containerinterface]" - exit 1 -} - -# Succeed if the given utility is installed. Fail otherwise. -# For explanations about `which` vs `type` vs `command`, see: -# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212 -# (Thanks to @chenhanxiao for pointing this out!) -installed () { - command -v "$1" >/dev/null 2>&1 -} - -# Google Styleguide says error messages should go to standard error. -warn () { - echo "$@" >&2 -} -die () { - status="$1" - shift - warn "$@" - exit "$status" -} - -if echo $IFNAME | grep -q '^mac:'; then - mac_address=$(echo $IFNAME | cut -c5-) - ifmatch= - for iftest in /sys/class/net/*; do - if [ -f $iftest/address ] && [ "$mac_address" = "$(cat $iftest/address)" ]; then - ifmatch="$(basename $iftest)" - break - fi - done - - if [ -z "$ifmatch" ]; then - die 1 "Mac address $mac_address specified for interface but no host interface matched." - else - IFNAME=$ifmatch - fi -fi - -# First step: determine type of first argument (bridge, physical interface...), -# Unless "--wait" is set (then skip the whole section) -if [ -z "$WAIT" ]; then - if [ -d "/sys/class/net/$IFNAME" ] - then - if [ -d "/sys/class/net/$IFNAME/bridge" ]; then - IFTYPE=bridge - BRTYPE=linux - elif installed ovs-vsctl && ovs-vsctl list-br|grep -q "^${IFNAME}$"; then - IFTYPE=bridge - BRTYPE=openvswitch - elif [ "$(cat "/sys/class/net/$IFNAME/type")" -eq 32 ]; then # InfiniBand IPoIB interface type 32 - IFTYPE=ipoib - # The IPoIB kernel module is fussy, set device name to ib0 if not overridden - CONTAINER_IFNAME=${CONTAINER_IFNAME:-ib0} - PKEY=$VLAN - else IFTYPE=phys - fi - else - case "$IFNAME" in - br*) - IFTYPE=bridge - BRTYPE=linux - ;; - ovs*) - if ! installed ovs-vsctl; then - die 1 "Need OVS installed on the system to create an ovs bridge" - fi - IFTYPE=bridge - BRTYPE=openvswitch - ;; - route*) - IFTYPE=route - ;; - rule*) - IFTYPE=rule - ;; - tc*) - IFTYPE=tc - ;; - dummy*) - IFTYPE=dummy - ;; - *) die 1 "I do not know how to setup interface $IFNAME." ;; - esac - fi -fi - -# Set the default container interface name to eth1 if not already set -CONTAINER_IFNAME=${CONTAINER_IFNAME:-eth1} - -[ "$WAIT" ] && { - while true; do - # This first method works even without `ip` or `ifconfig` installed, - # but doesn't work on older kernels (e.g. CentOS 6.X). See #128. - grep -q '^1$' "/sys/class/net/$CONTAINER_IFNAME/carrier" && break - # This method hopefully works on those older kernels. - ip link ls dev "$CONTAINER_IFNAME" && break - sleep 1 - done > /dev/null 2>&1 - exit 0 -} - -[ "$IFTYPE" = bridge ] && [ "$BRTYPE" = linux ] && [ "$VLAN" ] && { - die 1 "VLAN configuration currently unsupported for Linux bridge." -} - -[ "$IFTYPE" = ipoib ] && [ "$MACADDR" ] && { - die 1 "MACADDR configuration unsupported for IPoIB interfaces." -} - -# Second step: find the guest (for now, we only support LXC containers) -while read _ mnt fstype options _; do - [ "$fstype" != "cgroup" ] && continue - echo "$options" | grep -qw devices || continue - CGROUPMNT=$mnt -done < /proc/mounts - -[ "$CGROUPMNT" ] || { - die 1 "Could not locate cgroup mount point." -} - -# Try to find a cgroup matching exactly the provided name. -M=$(find "$CGROUPMNT" -name "$GUESTNAME") -N=$(echo "$M" | wc -l) -if [ -z "$M" ] ; then - N=0 -fi -case "$N" in - 0) - # If we didn't find anything, try to lookup the container with Docker. - if installed docker; then - RETRIES=3 - while [ "$RETRIES" -gt 0 ]; do - DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' "$GUESTNAME") - DOCKERCID=$(docker inspect --format='{{ .ID }}' "$GUESTNAME") - DOCKERCNAME=$(docker inspect --format='{{ .Name }}' "$GUESTNAME") - - [ "$DOCKERPID" != 0 ] && break - sleep 1 - RETRIES=$((RETRIES - 1)) - done - - [ "$DOCKERPID" = 0 ] && { - die 1 "Docker inspect returned invalid PID 0" - } - - [ "$DOCKERPID" = "" ] && { - die 1 "Container $GUESTNAME not found, and unknown to Docker." - } - else - die 1 "Container $GUESTNAME not found, and Docker not installed." - fi - ;; - 1) true ;; - 2) # LXC >=3.1.0 returns two entries from the cgroups mount instead of one. - echo "$M" | grep -q "lxc\.monitor" || die 1 "Found more than one container matching $GUESTNAME." - ;; - *) die 1 "Found more than one container matching $GUESTNAME." ;; -esac - -# only check IPADDR if we are not in a route mode -[ "$IFTYPE" != route ] && [ "$IFTYPE" != rule ] && [ "$IFTYPE" != tc ] && { - case "$IPADDR" in - # Let's check first if the user asked for DHCP allocation. - dhcp|dhcp:*) - # Use Docker-specific strategy to run the DHCP client - # from the busybox image, in the network namespace of - # the container. - if ! [ "$DOCKERPID" ]; then - warn "You asked for a Docker-specific DHCP method." - warn "However, $GUESTNAME doesn't seem to be a Docker container." - warn "Try to replace 'dhcp' with another option?" - die 1 "Aborting." - fi - DHCP_CLIENT=${IPADDR%%:*} - ;; - udhcpc|udhcpc:*|udhcpc-f|udhcpc-f:*|dhcpcd|dhcpcd:*|dhclient|dhclient:*|dhclient-f|dhclient-f:*) - DHCP_CLIENT=${IPADDR%%:*} - # did they ask for the client to remain? - DHCP_FOREGROUND= - [ "${DHCP_CLIENT%-f}" != "${DHCP_CLIENT}" ] && { - DHCP_FOREGROUND=true - } - DHCP_CLIENT=${DHCP_CLIENT%-f} - if ! installed "$DHCP_CLIENT"; then - die 1 "You asked for DHCP client $DHCP_CLIENT, but I can't find it." - fi - ;; - # Alright, no DHCP? Then let's see if we have a subnet *and* gateway. - */*@*) - GATEWAY="${IPADDR#*@}" GATEWAY="${GATEWAY%%@*}" - IPADDR="${IPADDR%%@*}" - ;; - # No gateway? We need at least a subnet, anyway! - */*) : ;; - # ... No? Then stop right here. - *) - warn "The IP address should include a netmask." - die 1 "Maybe you meant $IPADDR/24 ?" - ;; - esac -} - -# If a DHCP method was specified, extract the DHCP options. -if [ "$DHCP_CLIENT" ]; then - case "$IPADDR" in - *:*) DHCP_OPTIONS="${IPADDR#*:}" ;; - esac -fi - -if [ "$DOCKERPID" ]; then - NSPID=$DOCKERPID -else - NSPID=$(head -n 1 "$(find "$CGROUPMNT" -name "$GUESTNAME" | head -n 1)/tasks") - [ "$NSPID" ] || { - # it is an alternative way to get the pid - NSPID=$(lxc-info -n "$GUESTNAME" | grep PID | grep -Eo '[0-9]+') - [ "$NSPID" ] || { - die 1 "Could not find a process inside container $GUESTNAME." - } - } -fi - -# Check if an incompatible VLAN device already exists -[ "$IFTYPE" = phys ] && [ "$VLAN" ] && [ -d "/sys/class/net/$IFNAME.VLAN" ] && { - ip -d link show "$IFNAME.$VLAN" | grep -q "vlan.*id $VLAN" || { - die 1 "$IFNAME.VLAN already exists but is not a VLAN device for tag $VLAN" - } -} - -[ ! -d /var/run/netns ] && mkdir -p /var/run/netns -rm -f "/var/run/netns/$NSPID" -ln -s "/proc/$NSPID/ns/net" "/var/run/netns/$NSPID" - -# Check if we need to create a bridge. -[ "$IFTYPE" = bridge ] && [ ! -d "/sys/class/net/$IFNAME" ] && { - [ "$BRTYPE" = linux ] && { - (ip link add dev "$IFNAME" type bridge > /dev/null 2>&1) || (brctl addbr "$IFNAME") - ip link set "$IFNAME" up - } - [ "$BRTYPE" = openvswitch ] && { - ovs-vsctl add-br "$IFNAME" - } -} - -[ "$IFTYPE" != "route" ] && [ "$IFTYPE" != "dummy" ] && [ "$IFTYPE" != "rule" ] && [ "$IFTYPE" != "tc" ] && MTU=$(ip link show "$IFNAME" | awk '{print $5}') - -# If it's a bridge, we need to create a veth pair -[ "$IFTYPE" = bridge ] && { - if [ -z "$LOCAL_IFNAME" ]; then - LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}" - fi - GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}" - # Does the link already exist? - if ip link show "$LOCAL_IFNAME" >/dev/null 2>&1; then - # link exists, is it in use? - if ip link show "$LOCAL_IFNAME" up | grep -q "UP"; then - echo "Link $LOCAL_IFNAME exists and is up" - exit 1 - fi - # delete the link so we can re-add it afterwards - ip link del "$LOCAL_IFNAME" - fi - ip link add name "$LOCAL_IFNAME" mtu "$MTU" type veth peer name "$GUEST_IFNAME" mtu "$MTU" - case "$BRTYPE" in - linux) - (ip link set "$LOCAL_IFNAME" master "$IFNAME" > /dev/null 2>&1) || (brctl addif "$IFNAME" "$LOCAL_IFNAME") - ;; - openvswitch) - if ! ovs-vsctl list-ports "$IFNAME" | grep -q "^${LOCAL_IFNAME}$"; then - ovs-vsctl add-port "$IFNAME" "$LOCAL_IFNAME" ${VLAN:+tag="$VLAN"} \ - -- set Interface "$LOCAL_IFNAME" \ - external-ids:pipework.interface="$LOCAL_IFNAME" \ - external-ids:pipework.bridge="$IFNAME" \ - ${DOCKERCID:+external-ids:pipework.containerid="$DOCKERCID"} \ - ${DOCKERCNAME:+external-ids:pipework.containername="$DOCKERCNAME"} \ - ${NSPID:+external-ids:pipework.nspid="$NSPID"} \ - ${VLAN:+external-ids:pipework.vlan="$VLAN"} - fi - ;; - esac - ip link set "$LOCAL_IFNAME" up -} - -# If it's a physical interface, create a macvlan subinterface -[ "$IFTYPE" = phys ] && { - [ "$VLAN" ] && { - [ ! -d "/sys/class/net/${IFNAME}.${VLAN}" ] && { - ip link add link "$IFNAME" name "$IFNAME.$VLAN" mtu "$MTU" type vlan id "$VLAN" - } - ip link set "$IFNAME" up - IFNAME=$IFNAME.$VLAN - } - - if [ ! -z "$DIRECT_PHYS" ]; then - GUEST_IFNAME=$IFNAME - else - GUEST_IFNAME=ph$NSPID$CONTAINER_IFNAME - ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge - fi - - ip link set "$IFNAME" up -} - -# If it's an IPoIB interface, create a virtual IPoIB interface (the IPoIB -# equivalent of a macvlan device) -# -# Note: no macvlan subinterface nor Ethernet bridge can be created on top of an -# IPoIB interface. InfiniBand is not Ethernet. IPoIB is an IP layer on top of -# InfiniBand, without an intermediate Ethernet layer. -[ "$IFTYPE" = ipoib ] && { - GUEST_IFNAME="${IFNAME}.${NSPID}" - - # If a partition key is provided, use it - [ "$PKEY" ] && { - GUEST_IFNAME="${IFNAME}.${PKEY}.${NSPID}" - PKEY="pkey 0x$PKEY" - } - - ip link add link "$IFNAME" name "$GUEST_IFNAME" type ipoib $PKEY - ip link set "$IFNAME" up -} - -# If its a dummy interface, create a dummy interface. -[ "$IFTYPE" = dummy ] && { - GUEST_IFNAME=du$NSPID$CONTAINER_IFNAME - ip link add dev "$GUEST_IFNAME" type dummy -} - -# If the `route` command was specified ... -if [ "$IFTYPE" = route ]; then - # ... discard the first two arguments and pass the rest to the route command. - shift 2 - ip netns exec "$NSPID" ip route "$@" -elif [ "$IFTYPE" = rule ] ; then - shift 2 - ip netns exec "$NSPID" ip rule "$@" -elif [ "$IFTYPE" = tc ] ; then - shift 2 - ip netns exec "$NSPID" tc "$@" -else - # Otherwise, run normally. - ip link set "$GUEST_IFNAME" netns "$NSPID" - ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME" - [ "$MACADDR" ] && ip netns exec "$NSPID" ip link set dev "$CONTAINER_IFNAME" address "$MACADDR" - - # When using any of the DHCP methods, we start a DHCP client in the - # network namespace of the container. With the 'dhcp' method, the - # client used is taken from the Docker busybox image (therefore - # requiring no specific client installed on the host). Other methods - # use a locally installed client. - case "$DHCP_CLIENT" in - dhcp) - docker run -d --net container:$GUESTNAME --cap-add NET_ADMIN \ - busybox udhcpc -i "$CONTAINER_IFNAME" -x "hostname:$GUESTNAME" \ - $DHCP_OPTIONS \ - >/dev/null - ;; - udhcpc) - DHCP_Q="-q" - [ "$DHCP_FOREGROUND" ] && { - DHCP_OPTIONS="$DHCP_OPTIONS -f" - } - ip netns exec "$NSPID" "$DHCP_CLIENT" -qi "$CONTAINER_IFNAME" \ - -x "hostname:$GUESTNAME" \ - -p "/var/run/udhcpc.$GUESTNAME.pid" \ - $DHCP_OPTIONS - [ ! "$DHCP_FOREGROUND" ] && { - rm "/var/run/udhcpc.$GUESTNAME.pid" - } - ;; - dhclient) - ip netns exec "$NSPID" "$DHCP_CLIENT" "$CONTAINER_IFNAME" \ - -pf "/var/run/dhclient.$GUESTNAME.pid" \ - -lf "/etc/dhclient/dhclient.$GUESTNAME.leases" \ - $DHCP_OPTIONS - # kill dhclient after get ip address to prevent device be used after container close - [ ! "$DHCP_FOREGROUND" ] && { - kill "$(cat "/var/run/dhclient.$GUESTNAME.pid")" - rm "/var/run/dhclient.$GUESTNAME.pid" - } - ;; - dhcpcd) - ip netns exec "$NSPID" "$DHCP_CLIENT" -q "$CONTAINER_IFNAME" -h "$GUESTNAME" - ;; - "") - if installed ipcalc; then - eval $(ipcalc -b $IPADDR) - ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" brd "$BROADCAST" dev "$CONTAINER_IFNAME" - else - ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" dev "$CONTAINER_IFNAME" - fi - - [ "$GATEWAY" ] && { - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route delete default >/dev/null 2>&1 && true - } - ip netns exec "$NSPID" ip "$FAMILY_FLAG" link set "$CONTAINER_IFNAME" up - [ "$GATEWAY" ] && { - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route get "$GATEWAY" >/dev/null 2>&1 || \ - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route add "$GATEWAY/32" dev "$CONTAINER_IFNAME" - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route replace default via "$GATEWAY" dev "$CONTAINER_IFNAME" - } - ;; - esac - - # Give our ARP neighbors a nudge about the new interface - if installed arping; then - IPADDR=$(echo "$IPADDR" | cut -d/ -f1) - ip netns exec "$NSPID" arping -c 1 -A -I "$CONTAINER_IFNAME" "$IPADDR" > /dev/null 2>&1 || true - else - echo "Warning: arping not found; interface may not be immediately reachable" - fi -fi -# Remove NSPID to avoid `ip netns` catch it. -rm -f "/var/run/netns/$NSPID" - -# vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab : diff --git a/osmo-gbproxy-master/Dockerfile b/osmo-gbproxy-master/Dockerfile index 61463c52..3e0e40c4 100644 --- a/osmo-gbproxy-master/Dockerfile +++ b/osmo-gbproxy-master/Dockerfile @@ -48,7 +48,7 @@ COPY osmo-gbproxy.cfg /data/osmo-gbproxy.cfg # work-around for stupid docker not being able to properly deal with host netdevices or start # containers in pre-existing netns -COPY pipework /usr/bin/pipework +COPY .common/pipework /usr/bin/pipework COPY docker-entrypoint.sh /docker-entrypoint.sh WORKDIR /data diff --git a/osmo-gbproxy-master/pipework b/osmo-gbproxy-master/pipework deleted file mode 100755 index 97ce66b5..00000000 --- a/osmo-gbproxy-master/pipework +++ /dev/null @@ -1,489 +0,0 @@ -#!/bin/sh -# This code should (try to) follow Google's Shell Style Guide -# (https://google.github.io/styleguide/shell.xml) -set -e - -case "$1" in - --wait) - WAIT=1 - ;; - --direct-phys) - DIRECT_PHYS=1 - shift - ;; -esac - -IFNAME=$1 - -# default value set further down if not set here -CONTAINER_IFNAME= -if [ "$2" = "-i" ]; then - CONTAINER_IFNAME=$3 - shift 2 -fi - -if [ "$2" = "-l" ]; then - LOCAL_IFNAME=$3 - shift 2 -fi - -#inet or inet6 -FAMILY_FLAG="-4" -if [ "$2" = "-a" ]; then - FAMILY_FLAG="-$3" - shift 2 -fi - -GUESTNAME=$2 -IPADDR=$3 -MACADDR=$4 - -case "$MACADDR" in - *@*) - VLAN="${MACADDR#*@}" - VLAN="${VLAN%%@*}" - MACADDR="${MACADDR%%@*}" - ;; - *) - VLAN= - ;; -esac - -# did they ask to generate a custom MACADDR? -# generate the unique string -case "$MACADDR" in - U:*) - macunique="${MACADDR#*:}" - # now generate a 48-bit hash string from $macunique - MACADDR=$(echo $macunique|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/') - ;; -esac - - -[ "$IPADDR" ] || [ "$WAIT" ] || { - echo "Syntax:" - echo "pipework [-i containerinterface] [-l localinterfacename] [-a addressfamily] /[@default_gateway] [macaddr][@vlan]" - echo "pipework [-i containerinterface] [-l localinterfacename] dhcp [macaddr][@vlan]" - echo "pipework mac: [-i containerinterface] [-l localinterfacename] [-a addressfamily] /[@default_gateway] [macaddr][@vlan]" - echo "pipework mac: [-i containerinterface] [-l localinterfacename] dhcp [macaddr][@vlan]" - echo "pipework route " - echo "pipework rule " - echo "pipework tc " - echo "pipework --wait [-i containerinterface]" - exit 1 -} - -# Succeed if the given utility is installed. Fail otherwise. -# For explanations about `which` vs `type` vs `command`, see: -# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212 -# (Thanks to @chenhanxiao for pointing this out!) -installed () { - command -v "$1" >/dev/null 2>&1 -} - -# Google Styleguide says error messages should go to standard error. -warn () { - echo "$@" >&2 -} -die () { - status="$1" - shift - warn "$@" - exit "$status" -} - -if echo $IFNAME | grep -q '^mac:'; then - mac_address=$(echo $IFNAME | cut -c5-) - ifmatch= - for iftest in /sys/class/net/*; do - if [ -f $iftest/address ] && [ "$mac_address" = "$(cat $iftest/address)" ]; then - ifmatch="$(basename $iftest)" - break - fi - done - - if [ -z "$ifmatch" ]; then - die 1 "Mac address $mac_address specified for interface but no host interface matched." - else - IFNAME=$ifmatch - fi -fi - -# First step: determine type of first argument (bridge, physical interface...), -# Unless "--wait" is set (then skip the whole section) -if [ -z "$WAIT" ]; then - if [ -d "/sys/class/net/$IFNAME" ] - then - if [ -d "/sys/class/net/$IFNAME/bridge" ]; then - IFTYPE=bridge - BRTYPE=linux - elif installed ovs-vsctl && ovs-vsctl list-br|grep -q "^${IFNAME}$"; then - IFTYPE=bridge - BRTYPE=openvswitch - elif [ "$(cat "/sys/class/net/$IFNAME/type")" -eq 32 ]; then # InfiniBand IPoIB interface type 32 - IFTYPE=ipoib - # The IPoIB kernel module is fussy, set device name to ib0 if not overridden - CONTAINER_IFNAME=${CONTAINER_IFNAME:-ib0} - PKEY=$VLAN - else IFTYPE=phys - fi - else - case "$IFNAME" in - br*) - IFTYPE=bridge - BRTYPE=linux - ;; - ovs*) - if ! installed ovs-vsctl; then - die 1 "Need OVS installed on the system to create an ovs bridge" - fi - IFTYPE=bridge - BRTYPE=openvswitch - ;; - route*) - IFTYPE=route - ;; - rule*) - IFTYPE=rule - ;; - tc*) - IFTYPE=tc - ;; - dummy*) - IFTYPE=dummy - ;; - *) die 1 "I do not know how to setup interface $IFNAME." ;; - esac - fi -fi - -# Set the default container interface name to eth1 if not already set -CONTAINER_IFNAME=${CONTAINER_IFNAME:-eth1} - -[ "$WAIT" ] && { - while true; do - # This first method works even without `ip` or `ifconfig` installed, - # but doesn't work on older kernels (e.g. CentOS 6.X). See #128. - grep -q '^1$' "/sys/class/net/$CONTAINER_IFNAME/carrier" && break - # This method hopefully works on those older kernels. - ip link ls dev "$CONTAINER_IFNAME" && break - sleep 1 - done > /dev/null 2>&1 - exit 0 -} - -[ "$IFTYPE" = bridge ] && [ "$BRTYPE" = linux ] && [ "$VLAN" ] && { - die 1 "VLAN configuration currently unsupported for Linux bridge." -} - -[ "$IFTYPE" = ipoib ] && [ "$MACADDR" ] && { - die 1 "MACADDR configuration unsupported for IPoIB interfaces." -} - -# Second step: find the guest (for now, we only support LXC containers) -while read _ mnt fstype options _; do - [ "$fstype" != "cgroup" ] && continue - echo "$options" | grep -qw devices || continue - CGROUPMNT=$mnt -done < /proc/mounts - -[ "$CGROUPMNT" ] || { - die 1 "Could not locate cgroup mount point." -} - -# Try to find a cgroup matching exactly the provided name. -M=$(find "$CGROUPMNT" -name "$GUESTNAME") -N=$(echo "$M" | wc -l) -if [ -z "$M" ] ; then - N=0 -fi -case "$N" in - 0) - # If we didn't find anything, try to lookup the container with Docker. - if installed docker; then - RETRIES=3 - while [ "$RETRIES" -gt 0 ]; do - DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' "$GUESTNAME") - DOCKERCID=$(docker inspect --format='{{ .ID }}' "$GUESTNAME") - DOCKERCNAME=$(docker inspect --format='{{ .Name }}' "$GUESTNAME") - - [ "$DOCKERPID" != 0 ] && break - sleep 1 - RETRIES=$((RETRIES - 1)) - done - - [ "$DOCKERPID" = 0 ] && { - die 1 "Docker inspect returned invalid PID 0" - } - - [ "$DOCKERPID" = "" ] && { - die 1 "Container $GUESTNAME not found, and unknown to Docker." - } - else - die 1 "Container $GUESTNAME not found, and Docker not installed." - fi - ;; - 1) true ;; - 2) # LXC >=3.1.0 returns two entries from the cgroups mount instead of one. - echo "$M" | grep -q "lxc\.monitor" || die 1 "Found more than one container matching $GUESTNAME." - ;; - *) die 1 "Found more than one container matching $GUESTNAME." ;; -esac - -# only check IPADDR if we are not in a route mode -[ "$IFTYPE" != route ] && [ "$IFTYPE" != rule ] && [ "$IFTYPE" != tc ] && { - case "$IPADDR" in - # Let's check first if the user asked for DHCP allocation. - dhcp|dhcp:*) - # Use Docker-specific strategy to run the DHCP client - # from the busybox image, in the network namespace of - # the container. - if ! [ "$DOCKERPID" ]; then - warn "You asked for a Docker-specific DHCP method." - warn "However, $GUESTNAME doesn't seem to be a Docker container." - warn "Try to replace 'dhcp' with another option?" - die 1 "Aborting." - fi - DHCP_CLIENT=${IPADDR%%:*} - ;; - udhcpc|udhcpc:*|udhcpc-f|udhcpc-f:*|dhcpcd|dhcpcd:*|dhclient|dhclient:*|dhclient-f|dhclient-f:*) - DHCP_CLIENT=${IPADDR%%:*} - # did they ask for the client to remain? - DHCP_FOREGROUND= - [ "${DHCP_CLIENT%-f}" != "${DHCP_CLIENT}" ] && { - DHCP_FOREGROUND=true - } - DHCP_CLIENT=${DHCP_CLIENT%-f} - if ! installed "$DHCP_CLIENT"; then - die 1 "You asked for DHCP client $DHCP_CLIENT, but I can't find it." - fi - ;; - # Alright, no DHCP? Then let's see if we have a subnet *and* gateway. - */*@*) - GATEWAY="${IPADDR#*@}" GATEWAY="${GATEWAY%%@*}" - IPADDR="${IPADDR%%@*}" - ;; - # No gateway? We need at least a subnet, anyway! - */*) : ;; - # ... No? Then stop right here. - *) - warn "The IP address should include a netmask." - die 1 "Maybe you meant $IPADDR/24 ?" - ;; - esac -} - -# If a DHCP method was specified, extract the DHCP options. -if [ "$DHCP_CLIENT" ]; then - case "$IPADDR" in - *:*) DHCP_OPTIONS="${IPADDR#*:}" ;; - esac -fi - -if [ "$DOCKERPID" ]; then - NSPID=$DOCKERPID -else - NSPID=$(head -n 1 "$(find "$CGROUPMNT" -name "$GUESTNAME" | head -n 1)/tasks") - [ "$NSPID" ] || { - # it is an alternative way to get the pid - NSPID=$(lxc-info -n "$GUESTNAME" | grep PID | grep -Eo '[0-9]+') - [ "$NSPID" ] || { - die 1 "Could not find a process inside container $GUESTNAME." - } - } -fi - -# Check if an incompatible VLAN device already exists -[ "$IFTYPE" = phys ] && [ "$VLAN" ] && [ -d "/sys/class/net/$IFNAME.VLAN" ] && { - ip -d link show "$IFNAME.$VLAN" | grep -q "vlan.*id $VLAN" || { - die 1 "$IFNAME.VLAN already exists but is not a VLAN device for tag $VLAN" - } -} - -[ ! -d /var/run/netns ] && mkdir -p /var/run/netns -rm -f "/var/run/netns/$NSPID" -ln -s "/proc/$NSPID/ns/net" "/var/run/netns/$NSPID" - -# Check if we need to create a bridge. -[ "$IFTYPE" = bridge ] && [ ! -d "/sys/class/net/$IFNAME" ] && { - [ "$BRTYPE" = linux ] && { - (ip link add dev "$IFNAME" type bridge > /dev/null 2>&1) || (brctl addbr "$IFNAME") - ip link set "$IFNAME" up - } - [ "$BRTYPE" = openvswitch ] && { - ovs-vsctl add-br "$IFNAME" - } -} - -[ "$IFTYPE" != "route" ] && [ "$IFTYPE" != "dummy" ] && [ "$IFTYPE" != "rule" ] && [ "$IFTYPE" != "tc" ] && MTU=$(ip link show "$IFNAME" | awk '{print $5}') - -# If it's a bridge, we need to create a veth pair -[ "$IFTYPE" = bridge ] && { - if [ -z "$LOCAL_IFNAME" ]; then - LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}" - fi - GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}" - # Does the link already exist? - if ip link show "$LOCAL_IFNAME" >/dev/null 2>&1; then - # link exists, is it in use? - if ip link show "$LOCAL_IFNAME" up | grep -q "UP"; then - echo "Link $LOCAL_IFNAME exists and is up" - exit 1 - fi - # delete the link so we can re-add it afterwards - ip link del "$LOCAL_IFNAME" - fi - ip link add name "$LOCAL_IFNAME" mtu "$MTU" type veth peer name "$GUEST_IFNAME" mtu "$MTU" - case "$BRTYPE" in - linux) - (ip link set "$LOCAL_IFNAME" master "$IFNAME" > /dev/null 2>&1) || (brctl addif "$IFNAME" "$LOCAL_IFNAME") - ;; - openvswitch) - if ! ovs-vsctl list-ports "$IFNAME" | grep -q "^${LOCAL_IFNAME}$"; then - ovs-vsctl add-port "$IFNAME" "$LOCAL_IFNAME" ${VLAN:+tag="$VLAN"} \ - -- set Interface "$LOCAL_IFNAME" \ - external-ids:pipework.interface="$LOCAL_IFNAME" \ - external-ids:pipework.bridge="$IFNAME" \ - ${DOCKERCID:+external-ids:pipework.containerid="$DOCKERCID"} \ - ${DOCKERCNAME:+external-ids:pipework.containername="$DOCKERCNAME"} \ - ${NSPID:+external-ids:pipework.nspid="$NSPID"} \ - ${VLAN:+external-ids:pipework.vlan="$VLAN"} - fi - ;; - esac - ip link set "$LOCAL_IFNAME" up -} - -# If it's a physical interface, create a macvlan subinterface -[ "$IFTYPE" = phys ] && { - [ "$VLAN" ] && { - [ ! -d "/sys/class/net/${IFNAME}.${VLAN}" ] && { - ip link add link "$IFNAME" name "$IFNAME.$VLAN" mtu "$MTU" type vlan id "$VLAN" - } - ip link set "$IFNAME" up - IFNAME=$IFNAME.$VLAN - } - - if [ ! -z "$DIRECT_PHYS" ]; then - GUEST_IFNAME=$IFNAME - else - GUEST_IFNAME=ph$NSPID$CONTAINER_IFNAME - ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge - fi - - ip link set "$IFNAME" up -} - -# If it's an IPoIB interface, create a virtual IPoIB interface (the IPoIB -# equivalent of a macvlan device) -# -# Note: no macvlan subinterface nor Ethernet bridge can be created on top of an -# IPoIB interface. InfiniBand is not Ethernet. IPoIB is an IP layer on top of -# InfiniBand, without an intermediate Ethernet layer. -[ "$IFTYPE" = ipoib ] && { - GUEST_IFNAME="${IFNAME}.${NSPID}" - - # If a partition key is provided, use it - [ "$PKEY" ] && { - GUEST_IFNAME="${IFNAME}.${PKEY}.${NSPID}" - PKEY="pkey 0x$PKEY" - } - - ip link add link "$IFNAME" name "$GUEST_IFNAME" type ipoib $PKEY - ip link set "$IFNAME" up -} - -# If its a dummy interface, create a dummy interface. -[ "$IFTYPE" = dummy ] && { - GUEST_IFNAME=du$NSPID$CONTAINER_IFNAME - ip link add dev "$GUEST_IFNAME" type dummy -} - -# If the `route` command was specified ... -if [ "$IFTYPE" = route ]; then - # ... discard the first two arguments and pass the rest to the route command. - shift 2 - ip netns exec "$NSPID" ip route "$@" -elif [ "$IFTYPE" = rule ] ; then - shift 2 - ip netns exec "$NSPID" ip rule "$@" -elif [ "$IFTYPE" = tc ] ; then - shift 2 - ip netns exec "$NSPID" tc "$@" -else - # Otherwise, run normally. - ip link set "$GUEST_IFNAME" netns "$NSPID" - ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME" - [ "$MACADDR" ] && ip netns exec "$NSPID" ip link set dev "$CONTAINER_IFNAME" address "$MACADDR" - - # When using any of the DHCP methods, we start a DHCP client in the - # network namespace of the container. With the 'dhcp' method, the - # client used is taken from the Docker busybox image (therefore - # requiring no specific client installed on the host). Other methods - # use a locally installed client. - case "$DHCP_CLIENT" in - dhcp) - docker run -d --net container:$GUESTNAME --cap-add NET_ADMIN \ - busybox udhcpc -i "$CONTAINER_IFNAME" -x "hostname:$GUESTNAME" \ - $DHCP_OPTIONS \ - >/dev/null - ;; - udhcpc) - DHCP_Q="-q" - [ "$DHCP_FOREGROUND" ] && { - DHCP_OPTIONS="$DHCP_OPTIONS -f" - } - ip netns exec "$NSPID" "$DHCP_CLIENT" -qi "$CONTAINER_IFNAME" \ - -x "hostname:$GUESTNAME" \ - -p "/var/run/udhcpc.$GUESTNAME.pid" \ - $DHCP_OPTIONS - [ ! "$DHCP_FOREGROUND" ] && { - rm "/var/run/udhcpc.$GUESTNAME.pid" - } - ;; - dhclient) - ip netns exec "$NSPID" "$DHCP_CLIENT" "$CONTAINER_IFNAME" \ - -pf "/var/run/dhclient.$GUESTNAME.pid" \ - -lf "/etc/dhclient/dhclient.$GUESTNAME.leases" \ - $DHCP_OPTIONS - # kill dhclient after get ip address to prevent device be used after container close - [ ! "$DHCP_FOREGROUND" ] && { - kill "$(cat "/var/run/dhclient.$GUESTNAME.pid")" - rm "/var/run/dhclient.$GUESTNAME.pid" - } - ;; - dhcpcd) - ip netns exec "$NSPID" "$DHCP_CLIENT" -q "$CONTAINER_IFNAME" -h "$GUESTNAME" - ;; - "") - if installed ipcalc; then - eval $(ipcalc -b $IPADDR) - ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" brd "$BROADCAST" dev "$CONTAINER_IFNAME" - else - ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" dev "$CONTAINER_IFNAME" - fi - - [ "$GATEWAY" ] && { - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route delete default >/dev/null 2>&1 && true - } - ip netns exec "$NSPID" ip "$FAMILY_FLAG" link set "$CONTAINER_IFNAME" up - [ "$GATEWAY" ] && { - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route get "$GATEWAY" >/dev/null 2>&1 || \ - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route add "$GATEWAY/32" dev "$CONTAINER_IFNAME" - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route replace default via "$GATEWAY" dev "$CONTAINER_IFNAME" - } - ;; - esac - - # Give our ARP neighbors a nudge about the new interface - if installed arping; then - IPADDR=$(echo "$IPADDR" | cut -d/ -f1) - ip netns exec "$NSPID" arping -c 1 -A -I "$CONTAINER_IFNAME" "$IPADDR" > /dev/null 2>&1 || true - else - echo "Warning: arping not found; interface may not be immediately reachable" - fi -fi -# Remove NSPID to avoid `ip netns` catch it. -rm -f "/var/run/netns/$NSPID" - -# vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab : diff --git a/osmo-ns-master/Dockerfile b/osmo-ns-master/Dockerfile index 11852537..2f88c835 100644 --- a/osmo-ns-master/Dockerfile +++ b/osmo-ns-master/Dockerfile @@ -41,7 +41,7 @@ COPY osmo-ns-dummy.cfg /data/osmo-ns-dummy.cfg # work-around for stupid docker not being able to properly deal with host netdevices or start # containers in pre-existing netns -COPY pipework /usr/bin/pipework +COPY .common/pipework /usr/bin/pipework COPY docker-entrypoint.sh /docker-entrypoint.sh WORKDIR /data diff --git a/osmo-ns-master/pipework b/osmo-ns-master/pipework deleted file mode 100755 index 97ce66b5..00000000 --- a/osmo-ns-master/pipework +++ /dev/null @@ -1,489 +0,0 @@ -#!/bin/sh -# This code should (try to) follow Google's Shell Style Guide -# (https://google.github.io/styleguide/shell.xml) -set -e - -case "$1" in - --wait) - WAIT=1 - ;; - --direct-phys) - DIRECT_PHYS=1 - shift - ;; -esac - -IFNAME=$1 - -# default value set further down if not set here -CONTAINER_IFNAME= -if [ "$2" = "-i" ]; then - CONTAINER_IFNAME=$3 - shift 2 -fi - -if [ "$2" = "-l" ]; then - LOCAL_IFNAME=$3 - shift 2 -fi - -#inet or inet6 -FAMILY_FLAG="-4" -if [ "$2" = "-a" ]; then - FAMILY_FLAG="-$3" - shift 2 -fi - -GUESTNAME=$2 -IPADDR=$3 -MACADDR=$4 - -case "$MACADDR" in - *@*) - VLAN="${MACADDR#*@}" - VLAN="${VLAN%%@*}" - MACADDR="${MACADDR%%@*}" - ;; - *) - VLAN= - ;; -esac - -# did they ask to generate a custom MACADDR? -# generate the unique string -case "$MACADDR" in - U:*) - macunique="${MACADDR#*:}" - # now generate a 48-bit hash string from $macunique - MACADDR=$(echo $macunique|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/') - ;; -esac - - -[ "$IPADDR" ] || [ "$WAIT" ] || { - echo "Syntax:" - echo "pipework [-i containerinterface] [-l localinterfacename] [-a addressfamily] /[@default_gateway] [macaddr][@vlan]" - echo "pipework [-i containerinterface] [-l localinterfacename] dhcp [macaddr][@vlan]" - echo "pipework mac: [-i containerinterface] [-l localinterfacename] [-a addressfamily] /[@default_gateway] [macaddr][@vlan]" - echo "pipework mac: [-i containerinterface] [-l localinterfacename] dhcp [macaddr][@vlan]" - echo "pipework route " - echo "pipework rule " - echo "pipework tc " - echo "pipework --wait [-i containerinterface]" - exit 1 -} - -# Succeed if the given utility is installed. Fail otherwise. -# For explanations about `which` vs `type` vs `command`, see: -# http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script/677212#677212 -# (Thanks to @chenhanxiao for pointing this out!) -installed () { - command -v "$1" >/dev/null 2>&1 -} - -# Google Styleguide says error messages should go to standard error. -warn () { - echo "$@" >&2 -} -die () { - status="$1" - shift - warn "$@" - exit "$status" -} - -if echo $IFNAME | grep -q '^mac:'; then - mac_address=$(echo $IFNAME | cut -c5-) - ifmatch= - for iftest in /sys/class/net/*; do - if [ -f $iftest/address ] && [ "$mac_address" = "$(cat $iftest/address)" ]; then - ifmatch="$(basename $iftest)" - break - fi - done - - if [ -z "$ifmatch" ]; then - die 1 "Mac address $mac_address specified for interface but no host interface matched." - else - IFNAME=$ifmatch - fi -fi - -# First step: determine type of first argument (bridge, physical interface...), -# Unless "--wait" is set (then skip the whole section) -if [ -z "$WAIT" ]; then - if [ -d "/sys/class/net/$IFNAME" ] - then - if [ -d "/sys/class/net/$IFNAME/bridge" ]; then - IFTYPE=bridge - BRTYPE=linux - elif installed ovs-vsctl && ovs-vsctl list-br|grep -q "^${IFNAME}$"; then - IFTYPE=bridge - BRTYPE=openvswitch - elif [ "$(cat "/sys/class/net/$IFNAME/type")" -eq 32 ]; then # InfiniBand IPoIB interface type 32 - IFTYPE=ipoib - # The IPoIB kernel module is fussy, set device name to ib0 if not overridden - CONTAINER_IFNAME=${CONTAINER_IFNAME:-ib0} - PKEY=$VLAN - else IFTYPE=phys - fi - else - case "$IFNAME" in - br*) - IFTYPE=bridge - BRTYPE=linux - ;; - ovs*) - if ! installed ovs-vsctl; then - die 1 "Need OVS installed on the system to create an ovs bridge" - fi - IFTYPE=bridge - BRTYPE=openvswitch - ;; - route*) - IFTYPE=route - ;; - rule*) - IFTYPE=rule - ;; - tc*) - IFTYPE=tc - ;; - dummy*) - IFTYPE=dummy - ;; - *) die 1 "I do not know how to setup interface $IFNAME." ;; - esac - fi -fi - -# Set the default container interface name to eth1 if not already set -CONTAINER_IFNAME=${CONTAINER_IFNAME:-eth1} - -[ "$WAIT" ] && { - while true; do - # This first method works even without `ip` or `ifconfig` installed, - # but doesn't work on older kernels (e.g. CentOS 6.X). See #128. - grep -q '^1$' "/sys/class/net/$CONTAINER_IFNAME/carrier" && break - # This method hopefully works on those older kernels. - ip link ls dev "$CONTAINER_IFNAME" && break - sleep 1 - done > /dev/null 2>&1 - exit 0 -} - -[ "$IFTYPE" = bridge ] && [ "$BRTYPE" = linux ] && [ "$VLAN" ] && { - die 1 "VLAN configuration currently unsupported for Linux bridge." -} - -[ "$IFTYPE" = ipoib ] && [ "$MACADDR" ] && { - die 1 "MACADDR configuration unsupported for IPoIB interfaces." -} - -# Second step: find the guest (for now, we only support LXC containers) -while read _ mnt fstype options _; do - [ "$fstype" != "cgroup" ] && continue - echo "$options" | grep -qw devices || continue - CGROUPMNT=$mnt -done < /proc/mounts - -[ "$CGROUPMNT" ] || { - die 1 "Could not locate cgroup mount point." -} - -# Try to find a cgroup matching exactly the provided name. -M=$(find "$CGROUPMNT" -name "$GUESTNAME") -N=$(echo "$M" | wc -l) -if [ -z "$M" ] ; then - N=0 -fi -case "$N" in - 0) - # If we didn't find anything, try to lookup the container with Docker. - if installed docker; then - RETRIES=3 - while [ "$RETRIES" -gt 0 ]; do - DOCKERPID=$(docker inspect --format='{{ .State.Pid }}' "$GUESTNAME") - DOCKERCID=$(docker inspect --format='{{ .ID }}' "$GUESTNAME") - DOCKERCNAME=$(docker inspect --format='{{ .Name }}' "$GUESTNAME") - - [ "$DOCKERPID" != 0 ] && break - sleep 1 - RETRIES=$((RETRIES - 1)) - done - - [ "$DOCKERPID" = 0 ] && { - die 1 "Docker inspect returned invalid PID 0" - } - - [ "$DOCKERPID" = "" ] && { - die 1 "Container $GUESTNAME not found, and unknown to Docker." - } - else - die 1 "Container $GUESTNAME not found, and Docker not installed." - fi - ;; - 1) true ;; - 2) # LXC >=3.1.0 returns two entries from the cgroups mount instead of one. - echo "$M" | grep -q "lxc\.monitor" || die 1 "Found more than one container matching $GUESTNAME." - ;; - *) die 1 "Found more than one container matching $GUESTNAME." ;; -esac - -# only check IPADDR if we are not in a route mode -[ "$IFTYPE" != route ] && [ "$IFTYPE" != rule ] && [ "$IFTYPE" != tc ] && { - case "$IPADDR" in - # Let's check first if the user asked for DHCP allocation. - dhcp|dhcp:*) - # Use Docker-specific strategy to run the DHCP client - # from the busybox image, in the network namespace of - # the container. - if ! [ "$DOCKERPID" ]; then - warn "You asked for a Docker-specific DHCP method." - warn "However, $GUESTNAME doesn't seem to be a Docker container." - warn "Try to replace 'dhcp' with another option?" - die 1 "Aborting." - fi - DHCP_CLIENT=${IPADDR%%:*} - ;; - udhcpc|udhcpc:*|udhcpc-f|udhcpc-f:*|dhcpcd|dhcpcd:*|dhclient|dhclient:*|dhclient-f|dhclient-f:*) - DHCP_CLIENT=${IPADDR%%:*} - # did they ask for the client to remain? - DHCP_FOREGROUND= - [ "${DHCP_CLIENT%-f}" != "${DHCP_CLIENT}" ] && { - DHCP_FOREGROUND=true - } - DHCP_CLIENT=${DHCP_CLIENT%-f} - if ! installed "$DHCP_CLIENT"; then - die 1 "You asked for DHCP client $DHCP_CLIENT, but I can't find it." - fi - ;; - # Alright, no DHCP? Then let's see if we have a subnet *and* gateway. - */*@*) - GATEWAY="${IPADDR#*@}" GATEWAY="${GATEWAY%%@*}" - IPADDR="${IPADDR%%@*}" - ;; - # No gateway? We need at least a subnet, anyway! - */*) : ;; - # ... No? Then stop right here. - *) - warn "The IP address should include a netmask." - die 1 "Maybe you meant $IPADDR/24 ?" - ;; - esac -} - -# If a DHCP method was specified, extract the DHCP options. -if [ "$DHCP_CLIENT" ]; then - case "$IPADDR" in - *:*) DHCP_OPTIONS="${IPADDR#*:}" ;; - esac -fi - -if [ "$DOCKERPID" ]; then - NSPID=$DOCKERPID -else - NSPID=$(head -n 1 "$(find "$CGROUPMNT" -name "$GUESTNAME" | head -n 1)/tasks") - [ "$NSPID" ] || { - # it is an alternative way to get the pid - NSPID=$(lxc-info -n "$GUESTNAME" | grep PID | grep -Eo '[0-9]+') - [ "$NSPID" ] || { - die 1 "Could not find a process inside container $GUESTNAME." - } - } -fi - -# Check if an incompatible VLAN device already exists -[ "$IFTYPE" = phys ] && [ "$VLAN" ] && [ -d "/sys/class/net/$IFNAME.VLAN" ] && { - ip -d link show "$IFNAME.$VLAN" | grep -q "vlan.*id $VLAN" || { - die 1 "$IFNAME.VLAN already exists but is not a VLAN device for tag $VLAN" - } -} - -[ ! -d /var/run/netns ] && mkdir -p /var/run/netns -rm -f "/var/run/netns/$NSPID" -ln -s "/proc/$NSPID/ns/net" "/var/run/netns/$NSPID" - -# Check if we need to create a bridge. -[ "$IFTYPE" = bridge ] && [ ! -d "/sys/class/net/$IFNAME" ] && { - [ "$BRTYPE" = linux ] && { - (ip link add dev "$IFNAME" type bridge > /dev/null 2>&1) || (brctl addbr "$IFNAME") - ip link set "$IFNAME" up - } - [ "$BRTYPE" = openvswitch ] && { - ovs-vsctl add-br "$IFNAME" - } -} - -[ "$IFTYPE" != "route" ] && [ "$IFTYPE" != "dummy" ] && [ "$IFTYPE" != "rule" ] && [ "$IFTYPE" != "tc" ] && MTU=$(ip link show "$IFNAME" | awk '{print $5}') - -# If it's a bridge, we need to create a veth pair -[ "$IFTYPE" = bridge ] && { - if [ -z "$LOCAL_IFNAME" ]; then - LOCAL_IFNAME="v${CONTAINER_IFNAME}pl${NSPID}" - fi - GUEST_IFNAME="v${CONTAINER_IFNAME}pg${NSPID}" - # Does the link already exist? - if ip link show "$LOCAL_IFNAME" >/dev/null 2>&1; then - # link exists, is it in use? - if ip link show "$LOCAL_IFNAME" up | grep -q "UP"; then - echo "Link $LOCAL_IFNAME exists and is up" - exit 1 - fi - # delete the link so we can re-add it afterwards - ip link del "$LOCAL_IFNAME" - fi - ip link add name "$LOCAL_IFNAME" mtu "$MTU" type veth peer name "$GUEST_IFNAME" mtu "$MTU" - case "$BRTYPE" in - linux) - (ip link set "$LOCAL_IFNAME" master "$IFNAME" > /dev/null 2>&1) || (brctl addif "$IFNAME" "$LOCAL_IFNAME") - ;; - openvswitch) - if ! ovs-vsctl list-ports "$IFNAME" | grep -q "^${LOCAL_IFNAME}$"; then - ovs-vsctl add-port "$IFNAME" "$LOCAL_IFNAME" ${VLAN:+tag="$VLAN"} \ - -- set Interface "$LOCAL_IFNAME" \ - external-ids:pipework.interface="$LOCAL_IFNAME" \ - external-ids:pipework.bridge="$IFNAME" \ - ${DOCKERCID:+external-ids:pipework.containerid="$DOCKERCID"} \ - ${DOCKERCNAME:+external-ids:pipework.containername="$DOCKERCNAME"} \ - ${NSPID:+external-ids:pipework.nspid="$NSPID"} \ - ${VLAN:+external-ids:pipework.vlan="$VLAN"} - fi - ;; - esac - ip link set "$LOCAL_IFNAME" up -} - -# If it's a physical interface, create a macvlan subinterface -[ "$IFTYPE" = phys ] && { - [ "$VLAN" ] && { - [ ! -d "/sys/class/net/${IFNAME}.${VLAN}" ] && { - ip link add link "$IFNAME" name "$IFNAME.$VLAN" mtu "$MTU" type vlan id "$VLAN" - } - ip link set "$IFNAME" up - IFNAME=$IFNAME.$VLAN - } - - if [ ! -z "$DIRECT_PHYS" ]; then - GUEST_IFNAME=$IFNAME - else - GUEST_IFNAME=ph$NSPID$CONTAINER_IFNAME - ip link add link "$IFNAME" dev "$GUEST_IFNAME" mtu "$MTU" type macvlan mode bridge - fi - - ip link set "$IFNAME" up -} - -# If it's an IPoIB interface, create a virtual IPoIB interface (the IPoIB -# equivalent of a macvlan device) -# -# Note: no macvlan subinterface nor Ethernet bridge can be created on top of an -# IPoIB interface. InfiniBand is not Ethernet. IPoIB is an IP layer on top of -# InfiniBand, without an intermediate Ethernet layer. -[ "$IFTYPE" = ipoib ] && { - GUEST_IFNAME="${IFNAME}.${NSPID}" - - # If a partition key is provided, use it - [ "$PKEY" ] && { - GUEST_IFNAME="${IFNAME}.${PKEY}.${NSPID}" - PKEY="pkey 0x$PKEY" - } - - ip link add link "$IFNAME" name "$GUEST_IFNAME" type ipoib $PKEY - ip link set "$IFNAME" up -} - -# If its a dummy interface, create a dummy interface. -[ "$IFTYPE" = dummy ] && { - GUEST_IFNAME=du$NSPID$CONTAINER_IFNAME - ip link add dev "$GUEST_IFNAME" type dummy -} - -# If the `route` command was specified ... -if [ "$IFTYPE" = route ]; then - # ... discard the first two arguments and pass the rest to the route command. - shift 2 - ip netns exec "$NSPID" ip route "$@" -elif [ "$IFTYPE" = rule ] ; then - shift 2 - ip netns exec "$NSPID" ip rule "$@" -elif [ "$IFTYPE" = tc ] ; then - shift 2 - ip netns exec "$NSPID" tc "$@" -else - # Otherwise, run normally. - ip link set "$GUEST_IFNAME" netns "$NSPID" - ip netns exec "$NSPID" ip link set "$GUEST_IFNAME" name "$CONTAINER_IFNAME" - [ "$MACADDR" ] && ip netns exec "$NSPID" ip link set dev "$CONTAINER_IFNAME" address "$MACADDR" - - # When using any of the DHCP methods, we start a DHCP client in the - # network namespace of the container. With the 'dhcp' method, the - # client used is taken from the Docker busybox image (therefore - # requiring no specific client installed on the host). Other methods - # use a locally installed client. - case "$DHCP_CLIENT" in - dhcp) - docker run -d --net container:$GUESTNAME --cap-add NET_ADMIN \ - busybox udhcpc -i "$CONTAINER_IFNAME" -x "hostname:$GUESTNAME" \ - $DHCP_OPTIONS \ - >/dev/null - ;; - udhcpc) - DHCP_Q="-q" - [ "$DHCP_FOREGROUND" ] && { - DHCP_OPTIONS="$DHCP_OPTIONS -f" - } - ip netns exec "$NSPID" "$DHCP_CLIENT" -qi "$CONTAINER_IFNAME" \ - -x "hostname:$GUESTNAME" \ - -p "/var/run/udhcpc.$GUESTNAME.pid" \ - $DHCP_OPTIONS - [ ! "$DHCP_FOREGROUND" ] && { - rm "/var/run/udhcpc.$GUESTNAME.pid" - } - ;; - dhclient) - ip netns exec "$NSPID" "$DHCP_CLIENT" "$CONTAINER_IFNAME" \ - -pf "/var/run/dhclient.$GUESTNAME.pid" \ - -lf "/etc/dhclient/dhclient.$GUESTNAME.leases" \ - $DHCP_OPTIONS - # kill dhclient after get ip address to prevent device be used after container close - [ ! "$DHCP_FOREGROUND" ] && { - kill "$(cat "/var/run/dhclient.$GUESTNAME.pid")" - rm "/var/run/dhclient.$GUESTNAME.pid" - } - ;; - dhcpcd) - ip netns exec "$NSPID" "$DHCP_CLIENT" -q "$CONTAINER_IFNAME" -h "$GUESTNAME" - ;; - "") - if installed ipcalc; then - eval $(ipcalc -b $IPADDR) - ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" brd "$BROADCAST" dev "$CONTAINER_IFNAME" - else - ip netns exec "$NSPID" ip "$FAMILY_FLAG" addr add "$IPADDR" dev "$CONTAINER_IFNAME" - fi - - [ "$GATEWAY" ] && { - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route delete default >/dev/null 2>&1 && true - } - ip netns exec "$NSPID" ip "$FAMILY_FLAG" link set "$CONTAINER_IFNAME" up - [ "$GATEWAY" ] && { - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route get "$GATEWAY" >/dev/null 2>&1 || \ - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route add "$GATEWAY/32" dev "$CONTAINER_IFNAME" - ip netns exec "$NSPID" ip "$FAMILY_FLAG" route replace default via "$GATEWAY" dev "$CONTAINER_IFNAME" - } - ;; - esac - - # Give our ARP neighbors a nudge about the new interface - if installed arping; then - IPADDR=$(echo "$IPADDR" | cut -d/ -f1) - ip netns exec "$NSPID" arping -c 1 -A -I "$CONTAINER_IFNAME" "$IPADDR" > /dev/null 2>&1 || true - else - echo "Warning: arping not found; interface may not be immediately reachable" - fi -fi -# Remove NSPID to avoid `ip netns` catch it. -rm -f "/var/run/netns/$NSPID" - -# vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab :