Testing FR support in osmo-gbproxy is a bit more complicated as it involves the "hdlc" net-devices privded by the hdlc_fr.ko kernel module. So we need to * run on a host with actual hdlc net-devices (e.g. dahdi_dyamic_loc) * move those net-devices into the containers after starting them * wait for the net-devices to appear in the containers before starting either gbproxy or the test suite Change-Id: Id4b52877db53cb6e59f6d0d3f754aaae633949e8changes/12/21412/1
parent
29f454f2f2
commit
b83c28fc34
@ -0,0 +1,100 @@ |
||||
[ORDERED_INCLUDE] |
||||
# Common configuration, shared between test suites |
||||
"/osmo-ttcn3-hacks/Common.cfg" |
||||
# testsuite specific configuration, not expected to change |
||||
"/osmo-ttcn3-hacks/gbproxy/GBProxy_Tests.default" |
||||
|
||||
# Local configuration below |
||||
|
||||
[LOGGING] |
||||
|
||||
[TESTPORT_PARAMETERS] |
||||
*.GBPVTY.CTRL_HOSTNAME := "172.18.25.10" |
||||
|
||||
[MODULE_PARAMETERS] |
||||
GBProxy_Tests.mp_nsconfig_sgsn := { |
||||
{ |
||||
nsvc := { |
||||
{ |
||||
provider := { |
||||
ip := { |
||||
address_family := AF_INET, |
||||
local_ip := "172.18.25.103", |
||||
local_udp_port := 23000, |
||||
remote_ip := "172.18.25.10" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
GBProxy_Tests.mp_nsconfig_pcu := { |
||||
{ |
||||
nsei := 1, |
||||
role_sgsn := false, |
||||
handle_sns := false, |
||||
nsvc := { |
||||
{ |
||||
provider := { |
||||
fr := { |
||||
netdev := "hdlc1", |
||||
dlci := 16 |
||||
} |
||||
}, |
||||
nsvci := 1 |
||||
}, { |
||||
provider := { |
||||
fr := { |
||||
netdev := "hdlc2", |
||||
dlci := 17 |
||||
} |
||||
}, |
||||
nsvci := 2 |
||||
}, { |
||||
provider := { |
||||
fr := { |
||||
netdev := "hdlc3", |
||||
dlci := 18 |
||||
} |
||||
}, |
||||
nsvci := 3 |
||||
}, { |
||||
provider := { |
||||
fr := { |
||||
netdev := "hdlc4", |
||||
dlci := 19 |
||||
} |
||||
}, |
||||
nsvci := 4 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
GBProxy_Tests.mp_gbconfigs := { |
||||
{ |
||||
nsei := 1, |
||||
sgsn_role := false, |
||||
bvc := { |
||||
{ |
||||
bvci := 196, |
||||
cell_id := { |
||||
ra_id := { |
||||
lai := { |
||||
mcc_mnc := '262F42'H, |
||||
lac := 13135 |
||||
}, |
||||
rac := 0 |
||||
}, |
||||
cell_id := 20960 |
||||
}, |
||||
depth := BSSGP_DECODE_DEPTH_BSSGP |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
[MAIN_CONTROLLER] |
||||
|
||||
[EXECUTE] |
||||
GBProxy_Tests.control |
@ -0,0 +1,95 @@ |
||||
#!/bin/sh |
||||
|
||||
# WARNING: This cannot be executed on any random Linux machine or jenkins slave node! |
||||
# |
||||
# We require a kernel with HLDC net-devices, specifically eight pairs of devices named |
||||
# hdlc1 + hdlcnet1 ... hdlc8 + hdclnet8. |
||||
# |
||||
# Those pairs of netdevices can e.g. be implemented by actually physically looping back |
||||
# the related E1 interfaces, or e.g.by using DAHDI_NET + dahdi_dynamic_loc to create |
||||
# pairs of virtual E1 spans. |
||||
# |
||||
# In addition, we need to use 'sudo' permissions in order to move the hdlc |
||||
# net-devices into the docker containers. So in automatic test execution this means |
||||
# that the user will need sudo privileges without entering a password (NOPASS) |
||||
|
||||
. ../jenkins-common.sh |
||||
IMAGE_SUFFIX="${IMAGE_SUFFIX:-master}" |
||||
docker_images_require \ |
||||
"osmo-gbproxy-$IMAGE_SUFFIX" \ |
||||
"ttcn3-gbproxy-test" |
||||
|
||||
SUBNET=25 |
||||
network_create $SUBNET |
||||
|
||||
mkdir $VOL_BASE_DIR/gbproxy-tester |
||||
cp GBProxy_Tests.cfg $VOL_BASE_DIR/gbproxy-tester/ |
||||
|
||||
mkdir $VOL_BASE_DIR/gbproxy |
||||
cp osmo-gbproxy.cfg $VOL_BASE_DIR/gbproxy/ |
||||
|
||||
# Disable features not in latest yet |
||||
if [ "$IMAGE_SUFFIX" = "latest" ]; then |
||||
true; |
||||
fi |
||||
|
||||
mkdir $VOL_BASE_DIR/unix |
||||
|
||||
echo Starting container with gbproxy |
||||
docker run --rm \ |
||||
--cap-add=NET_RAW --cap-add=SYS_RAWIO \ |
||||
$(docker_network_params $SUBNET 10) \ |
||||
--ulimit core=-1 \ |
||||
-e "WAIT_FOR_NETDEV=hdlcnet8" \ |
||||
-v $VOL_BASE_DIR/gbproxy:/data \ |
||||
--name ${BUILD_TAG}-gbproxy -d \ |
||||
$DOCKER_ARGS \ |
||||
$REPO_USER/osmo-gbproxy-$IMAGE_SUFFIX |
||||
|
||||
# move all hdlcnetX net-devices into container |
||||
for i in `seq 1 8`; do |
||||
DEV="hdlcnet$i" |
||||
#sudo sethdlc ${DEV} fr lmi none |
||||
sudo ./netdev-to-docker.sh ${DEV} ${BUILD_TAG}-gbproxy |
||||
done |
||||
|
||||
echo Starting container with gbproxy testsuite |
||||
docker run --rm \ |
||||
--cap-add=NET_RAW --cap-add=SYS_RAWIO \ |
||||
$(docker_network_params $SUBNET 103) \ |
||||
--ulimit core=-1 \ |
||||
-e "TTCN3_PCAP_PATH=/data" \ |
||||
-e "WAIT_FOR_NETDEV=hdlc8" \ |
||||
-v $VOL_BASE_DIR/gbproxy-tester:/data \ |
||||
--name ${BUILD_TAG}-ttcn3-gbproxy-test -d \ |
||||
$DOCKER_ARGS \ |
||||
$REPO_USER/ttcn3-gbproxy-test $@ |
||||
|
||||
# move all hdlcnetX net-devices into container |
||||
for i in `seq 1 8`; do |
||||
DEV="hdlc$i" |
||||
#sudo sethdlc ${DEV} fr lmi none |
||||
sudo ./netdev-to-docker.sh ${DEV} ${BUILD_TAG}-ttcn3-gbproxy-test |
||||
done |
||||
|
||||
# emulate runnign container in foreground, which is no longer possible as we |
||||
# must shift the net-devices into the container _after_ it is started |
||||
docker logs -f ${BUILD_TAG}-ttcn3-gbproxy-test |
||||
|
||||
|
||||
echo Starting container to merge logs |
||||
docker run --rm \ |
||||
$(docker_network_params $SUBNET 103) \ |
||||
--ulimit core=-1 \ |
||||
-e "TTCN3_PCAP_PATH=/data" \ |
||||
-v $VOL_BASE_DIR/gbproxy-tester:/data \ |
||||
--name ${BUILD_TAG}-ttcn3-gbproxy-test-logmerge \ |
||||
--entrypoint /osmo-ttcn3-hacks/log_merge.sh GBProxy_Tests --rm \ |
||||
$DOCKER_ARGS \ |
||||
$REPO_USER/ttcn3-gbproxy-test |
||||
|
||||
echo Stopping containers |
||||
docker container kill ${BUILD_TAG}-gbproxy |
||||
|
||||
network_remove |
||||
collect_logs |
@ -0,0 +1,33 @@ |
||||
#!/bin/bash |
||||
|
||||
set -e |
||||
|
||||
NETDEV="$1" |
||||
CONTAINER="$2" |
||||
|
||||
die () { |
||||
status="$1" |
||||
shift |
||||
warn "$@" |
||||
exit "$status" |
||||
} |
||||
|
||||
DOCKER_PID=$(docker inspect --format='{{ .State.Pid }}' $2) |
||||
|
||||
[ ! -d /var/run/netns ] && mkdir -p /var/run/netns |
||||
rm -f "/var/run/netns/$DOCKER_PID" |
||||
ln -s "/proc/$DOCKER_PID/ns/net" "/var/run/netns/$DOCKER_PID" |
||||
|
||||
[ "$DOCKERPID" = 0 ] && { |
||||
die 1 "Docker inspect returned invalid PID 0" |
||||
} |
||||
|
||||
[ "$DOCKERPID" = "<no value>" ] && { |
||||
die 1 "Container $GUESTNAME not found, and unknown to Docker." |
||||
} |
||||
|
||||
ip link set "$NETDEV" netns "$DOCKER_PID" |
||||
ip netns exec "$DOCKER_PID" sethdlc "$NETDEV" fr lmi none |
||||
ip netns exec "$DOCKER_PID" ip link set "$NETDEV" up |
||||
|
||||
rm -f "/var/run/netns/$DOCKER_PID" |
@ -0,0 +1,43 @@ |
||||
! |
||||
! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty |
||||
!! |
||||
! |
||||
log gsmtap 172.18.25.103 |
||||
logging level set-all debug |
||||
logging filter all 1 |
||||
! |
||||
log stderr |
||||
logging filter all 1 |
||||
logging color 1 |
||||
logging print category 1 |
||||
logging timestamp 1 |
||||
logging print extended-timestamp 1 |
||||
logging print file 1 |
||||
logging level all everything |
||||
! |
||||
line vty |
||||
no login |
||||
bind 0.0.0.0 |
||||
! |
||||
gbproxy |
||||
sgsn nsei 101 |
||||
ns |
||||
nse 101 nsvci 101 |
||||
nse 101 remote-role sgsn |
||||
nse 101 encapsulation udp |
||||
nse 101 remote-ip 172.18.25.103 |
||||
nse 101 remote-port 23000 |
||||
timer tns-block 3 |
||||
timer tns-block-retries 3 |
||||
timer tns-reset 3 |
||||
timer tns-reset-retries 3 |
||||
timer tns-test 30 |
||||
timer tns-alive 3 |
||||
timer tns-alive-retries 10 |
||||
encapsulation udp local-ip 172.18.25.10 |
||||
encapsulation udp local-port 23000 |
||||
encapsulation framerelay-gre enabled 0 |
||||
nse 1 nsvci 1 frnet hdlcnet1 dlci 16 |
||||
nse 1 nsvci 2 frnet hdlcnet2 dlci 17 |
||||
nse 1 nsvci 3 frnet hdlcnet3 dlci 18 |
||||
nse 1 nsvci 4 frnet hdlcnet4 dlci 19 |
@ -0,0 +1,13 @@ |
||||
#!/bin/bash |
||||
set -eou pipefail |
||||
|
||||
if [[ -n ${WAIT_FOR_NETDEV:-} ]]; then |
||||
/usr/bin/pipework --wait -i ${WAIT_FOR_NETDEV} |
||||
fi |
||||
|
||||
cd /data && /osmo-ttcn3-hacks/start-testsuite.sh /osmo-ttcn3-hacks/gbproxy/GBProxy_Tests; \ |
||||
exit_code=$? |
||||
|
||||
/osmo-ttcn3-hacks/log_merge.sh GBProxy_Tests --rm |
||||
|
||||
exit $exit_code |
@ -0,0 +1,489 @@ |
||||
#!/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 <hostinterface> [-i containerinterface] [-l localinterfacename] [-a addressfamily] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]" |
||||
echo "pipework <hostinterface> [-i containerinterface] [-l localinterfacename] <guest> dhcp [macaddr][@vlan]" |
||||
echo "pipework mac:<hostinterface_macaddress> [-i containerinterface] [-l localinterfacename] [-a addressfamily] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]" |
||||
echo "pipework mac:<hostinterface_macaddress> [-i containerinterface] [-l localinterfacename] <guest> dhcp [macaddr][@vlan]" |
||||
echo "pipework route <guest> <route_command>" |
||||
echo "pipework rule <guest> <rule_command>" |
||||
echo "pipework tc <guest> <tc_command>" |
||||
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" = "<no value>" ] && { |
||||
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 : |
Loading…
Reference in new issue