From 0d52009f7ea77e739fca105988c01337dfeb04d5 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Sat, 28 Sep 2013 18:33:26 +0200 Subject: initial commit --- Makefile | 17 +++++++ util-vserver-vars | 25 ++++++++++ vnamespace.netns | 48 +++++++++++++++++++ vserver-netns.sh | 8 ++++ vserver.function | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ vserver.netns | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vservers-default | 33 +++++++++++++ 7 files changed, 401 insertions(+) create mode 100644 Makefile create mode 100644 util-vserver-vars create mode 100755 vnamespace.netns create mode 100644 vserver-netns.sh create mode 100644 vserver.function create mode 100755 vserver.netns create mode 100644 vservers-default diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f2b257c --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +all: + +clean: + +install: vserver.netns vnamespace.netns util-vserver-vars vserver.function vserver-netns.sh vservers-default + install -d "$(DESTDIR)/usr/lib/util-vserver/netns/" \ + "$(DESTDIR)/usr/sbin/" \ + "$(DESTDIR)/etc/profile.d/" \ + "$(DESTDIR)/etc/default/" + + install vserver.netns "$(DESTDIR)/usr/sbin/" + install vnamespace.netns "$(DESTDIR)/usr/sbin/" + install -m644 util-vserver-vars "$(DESTDIR)/usr/lib/util-vserver/netns/" + install -m644 vserver.function "$(DESTDIR)/usr/lib/util-vserver/netns/" + install -m644 vserver-netns.sh "$(DESTDIR)/etc/profile.d/" + install -m644 vservers-default "$(DESTDIR)/etc/default/" +.PHONY: install diff --git a/util-vserver-vars b/util-vserver-vars new file mode 100644 index 0000000..086e508 --- /dev/null +++ b/util-vserver-vars @@ -0,0 +1,25 @@ +: ${REAL_UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars} +test -e "$REAL_UTIL_VSERVER_VARS" || { + echo $"Can not find util-vserver installation (the file '$REAL_UTIL_VSERVER_VARS' would be expected); aborting..." >&2 + exit 1 +} +. "$REAL_UTIL_VSERVER_VARS" + +# save defaults +__REAL_PKGLIBDIR="${__PKGLIBDIR}" +_REAL_VSERVER="${_VSERVER}" + +case "$0" in + vserver) + # we want to wrap a function from vserver.functions + # so we want to wrap vserver.functions that will be include with: + # . $__PKGLIBDIR/vserver.functions + __PKGLIBDIR="${__PKGLIBDIR}/netns" + ;; + + *) + ;; +esac + +# overwrite _VSERVER for wrapper script +_VSERVER="/usr/sbin/vserver.netns" diff --git a/vnamespace.netns b/vnamespace.netns new file mode 100755 index 0000000..51c6325 --- /dev/null +++ b/vnamespace.netns @@ -0,0 +1,48 @@ +#!/bin/bash + +: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars.netns} +test -e "$UTIL_VSERVER_VARS" || { + echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2 + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$_LIB_FUNCTIONS" +. $__PKGLIBDIR/vserver.functions + +ARGS=( "$@" ) + +while : +do + case "$1" in + -i|--index) + VSERVER_DIR="$($_VSERVER_INFO "$2" ID)" + getFileValue VSERVER_NAME "${VSERVER_DIR}/name" + break + ;; + + -e|--enter) + VSERVER_NAME="$2" + _setVserverDir "$VSERVER_NAME" + break + ;; + + --mask) + shift + shift + ;; + + --) + break + ;; + + *) + shift + ;; + esac +done + +if [[ -n "$VSERVER_NAME" && -d "${VSERVER_DIR}/netns/" ]]; then + exec $_IP netns exec "$VSERVER_NAME" /usr/sbin/vnamespace "${ARGS[@]}" +fi + +exec /usr/sbin/vnamespace "${ARGS[@]}" diff --git a/vserver-netns.sh b/vserver-netns.sh new file mode 100644 index 0000000..f3f7240 --- /dev/null +++ b/vserver-netns.sh @@ -0,0 +1,8 @@ +if command -v vserver.netns >/dev/null; then + alias vserver="vserver.netns" +fi + +if command -v vnamespace.netns >/dev/null; then + alias vnamespace="vnamespace.netns" +fi + diff --git a/vserver.function b/vserver.function new file mode 100644 index 0000000..b8a890f --- /dev/null +++ b/vserver.function @@ -0,0 +1,129 @@ +# source the real file +. ${__REAL_PKGLIBDIR}/vserver.function +__PKGLIBDIR="${__REAL_PKGLIBDIR}" + +# +# own functions +# + +function netnsCreateMac() { + local mac + + getFileValue mac "${1}/mac" + if [ -n "$mac" ]; then + echo "$mac" + return 0 + fi + + getFileValue ctx "$VSERVER_DIR"/context + ( + printf "0200" + printf "%06d" $ctx + printf "%02x" "$(basename "$1")" + )| + sed 's/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/\1:\2:\3:\4:\5:\6/' +} + +function netnsCreateIfaceName() { + local name + + getFileValue name "${1}/name" + if [ -n "$name" ]; then + echo "$name" + return 0 + fi + + printf "%s%d" "$VSERVER_NAME" "$(basename "$1")" +} + +function _netnsProcessSingleGateway() { + local iface + local gw + + getFileValue gw "${2}/gw" "${2}/../gw" + [ -n "$gw" ] || return 0 + + iface="$(netnsCreateIfaceName "$2")" + _addInterfaceCmd IP_ROUTE default via "$gw" dev "$iface" +} + +function _netnsFilterNetnsUmount() { + local args=( "$@" ) + + while : + do + case $1 in + --) shift; break;; + -*) shift;; + net:*|/run/netns/*) return 0;; + *) break;; + esac + done + + ${_REAL_UMOUNT} "${opts[@]}" +} + +function _netnsWaitForDad() { + local waiting + + while ip -6 -o addr show tentative | grep -q ' scope global '; do + sleep 1 + waiting=$((waiting+1)) + if [ $waiting -ge $1 ]; then + echo "Warning: IPv6 addresses still tentative after ${waiting} seconds; continuing..." + return 0 + fi + done +} + + +# +# monkey patching +# + +function save_function() { + local ORIG_FUNC=$(declare -f $1) + local NEWNAME_FUNC="$2${ORIG_FUNC#$1}" + eval "$NEWNAME_FUNC" +} + +save_function _generateInterfaceOptions __netns_realGenerateInterfaceOptions +function _generateInterfaceOptions() { + __netns_realGenerateInterfaceOptions "$@" + ret="$?" + + # add commands for default route + for net in "$VSERVER_DIR/netns/"*; do + test -d "$net" || continue + test ! -e "${net}/disabled" || continue + + _netnsProcessSingleGateway "$net" + done + + return "$ret" +} + +save_function _namespaceCleanup __netns_realNamespaceCleanup +function _namespaceCleanup() { + _REAL_UMOUNT="${_UMOUNT}" + _UMOUNT="_netnsFilterNetnsUmount" + + __netns_realNamespaceCleanup "$@" + ret="$?" + + _UMOUNT="${_REAL_UMOUNT}" + return "$ret" +} + +save_function enableInterfaces __netns_realEnableInterfaces +function enableInterfaces() { + __netns_realEnableInterfaces "$@" + ret="$?" + + # It is unpossible to bind on very recently added IPv6 addresses. + # They have to pass the duplicate address detection (dad) before + # they could be used, so we wait here before continuing. + netnsWaitForDad() + + return "$ret" +} diff --git a/vserver.netns b/vserver.netns new file mode 100755 index 0000000..a3e81eb --- /dev/null +++ b/vserver.netns @@ -0,0 +1,141 @@ +#!/bin/bash + +: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars.netns} +test -e "$UTIL_VSERVER_VARS" || { + echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2 + exit 1 +} +. "$UTIL_VSERVER_VARS" +. "$_LIB_FUNCTIONS" +. $__PKGLIBDIR/vserver.functions + +function _processSingleNetwork() { + local dev + local iface + local vlan + local mac + + getFileValue dev "${2}/dev" "${2}/../dev" + [ -n "$dev" ] || return 1 + + iface="$(netnsCreateIfaceName "$2")" + getFileValue vlan "${2}/vlan" + + case "$1" in + add) + if [ ! -e "${2}/nocleanup" ]; then + $_IP link show dev "$iface" >/dev/null 2>&1 && $_IP link del "$iface" + $_IP netns exec "$VSERVER_NAME" $_IP link show dev "$iface" >/dev/null 2>&1 && $_IP netns exec "$VSERVER_NAME" $_IP link del "$iface" + fi + + if [ -z "$vlan" ]; then + $_IP link add link "$dev" name "$iface" type macvlan mode bridge + else + $_IP link add link "$dev" name "$iface" type vlan id "$vlan" + fi + + getFileValue mac "${2}/mac" + [ -n "$mav" ] || mac="$(netnsCreateMac "$2")" + + $_IP link set dev "$iface" netns "$VSERVER_NAME" + $_IP netns exec "$VSERVER_NAME" $_IP link set dev "$iface" address "$mac" + $_IP netns exec "$VSERVER_NAME" $_VPROCUNHIDE + ;; + + remove) + $_IP netns exec "$VSERVER_NAME" $_IP link del "$iface" + ;; + esac +} + +# preserve args +ARGS=( "$@" ) +SELF=( "$0" ) + +# skip arguments starting with - +while : +do + case "$1" in + --) + SELF=( "${SELF[@]}" "$1" ) + shift + break + ;; + -*) + SELF=( "${SELF[@]}" "$1" ) + shift + ;; + *) + break + ;; + esac +done + +VSERVER_NAME="$1" +ACTION="$2" +NETNS=() + +_setVserverDir "$VSERVER_NAME" + +[ -d "${VSERVER_DIR}/netns/" ] && _USE_NETNS="1" + +if [[ "$ACTION" == "start" && -n "${_USE_NETNS}" ]]; then + pushd "$VSERVER_DIR" >/dev/null + execScriptlets "$VSERVER_DIR" "$VSERVER_NAME" pre-netns + popd >/dev/null + + # create and init netns + $_IP netns list | grep -q "^${VSERVER_NAME}\$" || $_IP netns add "$VSERVER_NAME" + $_IP netns exec "$VSERVER_NAME" $_IP link set dev lo up + + for net in "$VSERVER_DIR/netns/"*; do + test -d "$net" || continue + test ! -e "${net}/disabled" || continue + + _processSingleNetwork add "$net" + done +fi + +if [[ "$ACTION" == "start" || + "$ACTION" == "stop" || + "$ACTION" == "enter" || + "$ACTION" == "exec" || + "$ACTION" == "suexec" ]] +then + if [ -n "${_USE_NETNS}" ]; then + # enter netns + NETNS=( $_IP netns exec "$VSERVER_NAME" ) + fi +fi + +if [[ "$ACTION" == "restart" ]]; then + "${SELF[@]}" --sync "$VSERVER_NAME" stop + exec "${SELF[@]}" "$VSERVER_NAME" start +fi + + +# prepare for executing real _VSERVER +export _USE_NETNS +export UTIL_VSERVER_VARS + +if [[ "$ACTION" != "stop" ]]; then + exec "${NETNS[@]}" "$_REAL_VSERVER" "${ARGS[@]}" +fi + + +# stop need to do something after the stop, so no exec here +"${NETNS[@]}" "$_REAL_VSERVER" "${ARGS[@]}" +ret=$? + +if [ -n "${_USE_NETNS}" ]; then + for net in "${VSERVER_DIR}/netns/"*; do + test -d "$net" || continue + test ! -e "${net}/disabled" || continue + + _processSingleNetwork remove "$net" + done + + $_IP netns delete "$VSERVER_NAME" +fi + +exit $ret diff --git a/vservers-default b/vservers-default new file mode 100644 index 0000000..314bfa0 --- /dev/null +++ b/vservers-default @@ -0,0 +1,33 @@ +# This file gets sourced from /etc/init.d/vservers-default. + +# We want to use our modified version of util-vserver-vars, +# so that we can fire up our modified version of the vserver +# script and do the network namespace setup stuff even for +# vservers that get started up during boot. +if [ -r "/usr/lib/util-vserver/util-vserver-vars.netns" ]; then + UTIL_VSERVER_VARS="/usr/lib/util-vserver/util-vserver-vars.netns" + export UTIL_VSERVER_VARS +fi + +# We also add the possibilities to set other variables without +# modifying this file. So we and some clever sourcing here. +# (This has also the possibility to start other marks without +# copying the script, but symlinking it.) +name="$(basename "$0")" + +# This is a requirement, stated in the init script. So we set it +# here, to not confuse the user. +LOCKFILE="$name" + +function _get_flavor() { + local flavor="" + if [ "$name" = "${name#vserver-default[-.]}" ]; then + + else + fi +} + +# Added the ability to disable a flaver without disabling the +# initscript. (Debian enables all initscripts during installation +# of a package, so that we may want another way to disable it.) +[ "$ENABLE" != "0" ] || exit 0 -- cgit v1.2.3-1-g7c22