summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2013-09-28 18:33:26 +0200
committerAlexander Sulfrian <alexander@sulfrian.net>2013-09-28 18:33:26 +0200
commit0d52009f7ea77e739fca105988c01337dfeb04d5 (patch)
treed0bb7a08c2adb941c03e0e976f43912a5a8cdfc3
downloadutil-vserver-netns-0d52009f7ea77e739fca105988c01337dfeb04d5.tar.gz
util-vserver-netns-0d52009f7ea77e739fca105988c01337dfeb04d5.tar.bz2
util-vserver-netns-0d52009f7ea77e739fca105988c01337dfeb04d5.zip
initial commit
-rw-r--r--Makefile17
-rw-r--r--util-vserver-vars25
-rwxr-xr-xvnamespace.netns48
-rw-r--r--vserver-netns.sh8
-rw-r--r--vserver.function129
-rwxr-xr-xvserver.netns141
-rw-r--r--vservers-default33
7 files changed, 401 insertions, 0 deletions
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