# $2 = the sub-host to start or stop
# $3... = the optional chroot-ed command (/startup by default)
+set -x
+
SCRIPT=$0
CMD=$1
NAME=$2
[ -z "$NAME" ] && usage
-: ${ATTIC=/opt/srv}
-: ${BRIDGE=srv_br}
-: ${TARGET=/srv/$NAME}
-: ${LOWER=$ATTIC/daedalus.fs}
-: ${IMAGE=$ATTIC/$NAME/$NAME.img}
-: ${UPPER=$ATTIC/$NAME/root}
-: ${WORK=$ATTIC/$NAME/work}
-: ${MOUNT=$ATTIC/$NAME/mnt}
+: ${SUBHOST=/opt/subhost}
+: ${OSROOT=}
+: ${TOP=$SUBHOST/$NAME}
+: ${TARGET=$TOP/live}
+: ${IMAGE=$TOP/$NAME.img}
+: ${UPPER=$TOP/root}
+: ${WORK=$TOP/work}
+: ${MOUNT=$TOP/mnt}
: ${NSNAME=$NAME}
-: ${NETH=1}
+: ${BRIDGES=lan_br}
+: ${CONFIG=$TOP/config}
+
+[ -e "$CONFIG" ] && . "$CONFIG"
+cd "$SUBHOST" || exit 1
+
+# Create a simple overlay subhost without its own image file
create_subhost() {
mkdir -p $TARGET $MOUNT $UPPER $WORK
+ [ -d "$OSROOT" ] || OSROOT=$SUBHOST/chimaera/base
+ [ -e $CONFIG ] || cat <<EOF > "$CONFIG"
+# Subhost $NAME is an autogenerated overlay subhost with shared filesystem
+OSROOT="$OSROOT"
+BRIDGES="$BRIDGES"
+EOF
}
-setup_network() {
- if [ -n "$BRIDGE" ] ; then
- brctl show $BRIDGE >& /dev/null || brctl addbr $BRIDGE
- fi
+# Generate a mac address for given arguments pass through 40-bit b2sum
+# and with 02: prefix.
+macaddr() {
+ local V="$(b2sum -l 40 <<< "$*" )"
+ V="$( sed 's/\(..\)/\1:/g' <<< "${V}aaaaaaaaaa")"
+ echo "02:${V:0:14}"
+}
+# setup the subhost network namespace and link up the host side
+setup_network() {
E=0
ip netns add $NSNAME
- for I in $(eval echo "{1..$NETH}") ; do
+ for BRIDGE in ${BRIDGES[@]} ; do
IF=$NAME$E
- ip link add $IF type veth peer name eth$E netns $NSNAME
+ B=( ${BRIDGE/:/ } )
+ BRIDGE="${B[0]}"
+ MAC="${B[1]}"
+ [ -z "$MAC" ] && MAC="$(macaddr "$(hostname)" "$NAME" "$IF")"
+ brctl show $BRIDGE >& /dev/null || brctl addbr $BRIDGE
+ ip link add $IF type veth peer name eth$E address $MAC netns $NSNAME
ip link set $IF up
[ -n "$BRIDGE" ] && brctl addif $BRIDGE $IF
E=$((E+1))
done
}
+# check if $1 is mounted
+is_mounted() {
+ grep -qE "^[^ ]+ $1 " /proc/mounts
+}
+
+# Setup or re-setup the subhost filesystem
setup_rootfs() {
- if [ -e "$IMAGE" ] ; then
- mount $IMAGE $MOUNT || exit 1
- LOWER=$MOUNT/root
- WORK=$MOUNT/work
+ if is_mounted $TARGET ; then
+ mount -oremount $TARGET
+ else
+ if [ -e "$IMAGE" ] ; then
+ # $IMAGE is either an image file or a link to a partition,
+ # with /root and /work in it.
+ is_mounted $MOUNT || mount $IMAGE $MOUNT || exit 1
+ UPPER=$MOUNT/root
+ WORK=$MOUNT/work
+ fi
+ if [ -z "$OSROOT" ] ; then
+ # No overlay
+ mount --rbind $UPPER $TARGET
+ else
+ # overlay of $UPPER (+$WORK) over $OSROOT onto $TARGET
+ mount -t overlay $NAME \
+ -olowerdir=$OSROOT,upperdir=$UPPER,workdir=$WORK \
+ $TARGET
+ fi
fi
- mount -t overlay $NAME -olowerdir=$LOWER,upperdir=$UPPER,workdir=$WORK \
- $TARGET
+}
+
+# Set up cgroup CPU accounting (cpuacct)
+accounting() {
+ # 1-- once, system wide
+ grep -q "/sys/fs/cgroup cgroup" /proc/mounts || \
+ mount -t cgroup -ocpuacct none /sys/fs/cgroup
+ if [ -d /sys/fs/cgroup/$NAME ] ; then
+ : # reset?
+ else
+ mkdir /sys/fs/cgroup/$NAME
+ # the following fixes things that sometimes are broken?
+ for f in cpuset.mems cpuset.cpus ; do
+ [ -z "$(cat /sys/fs/cgroups/$NAME/$F)" ] && \
+ echo 0 > /sys/fs/cgroups/$NAME/$F
+ done
+
+ fi
+ # Register this task for subhost accounting
+ echo $$ > /sys/fs/cgroup/$NAME/tasks
}
case "$CMD" in
start)
- cd "$ATTIC" || exit 1
[ -e "/run/netns/$NSNAME" ] || setup_network
[ -d "$MOUNT" ] || create_subhost
- grep -q "^$NAME $TARGET overlay" /proc/mounts || setup_rootfs
+ setup_rootfs
START=/bin/bash
[ -x $TARGET/startup ] && START=/startup
+ accounting
exec ip netns exec $NSNAME unshare \
--fork --pid --mount-proc --kill-child \
--uts --ipc --mount --cgroup \
- "--root=$TARGET" $START
+ chroot $TARGET $START
;;
stop)
umount $TARGET
[ -e $IMAGE ] && umount $MOUNT
ip netns del $NSNAME
+ rmdir /sys/fs/cgroup/$NAME
;;
*)
usage