summaryrefslogtreecommitdiff
path: root/system/xen/openvswitch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/openvswitch')
-rw-r--r--system/xen/openvswitch/README.openvswitch-extended23
-rw-r--r--system/xen/openvswitch/openvswitch-clean.sh127
-rw-r--r--system/xen/openvswitch/openvswitch.conf15
-rw-r--r--system/xen/openvswitch/vif-openvswitch-extended197
4 files changed, 362 insertions, 0 deletions
diff --git a/system/xen/openvswitch/README.openvswitch-extended b/system/xen/openvswitch/README.openvswitch-extended
new file mode 100644
index 0000000000..399a7d37ad
--- /dev/null
+++ b/system/xen/openvswitch/README.openvswitch-extended
@@ -0,0 +1,23 @@
+vif-openvswitch-extended: This script extends vif-openvswitch features.
+
+The original vif-openvswitch script, which can also be found in this package,
+was used as a template for this "extended" script. The main purpose here is to
+add HTB rate limiting and IP/ARP address spoof prevention between domU guests.
+
+Until openvswitch.conf is present and configured in XEN_CONFIG_DIR path, this
+script will behave just like the original one. This package uses /etc/xen config
+path by default.
+
+To enable this script for all guests by default, set xl.conf variable like this:
+
+ vif.default.script="vif-openvswitch-extended"
+
+Additionally, included is an openvswitch-clean.sh helper script; it can be used
+to clean up and (re)apply configuration options found in openvswitch.conf file.
+Due to the fact that this script is based on the original script, which you
+might already be using, it is easy to switch over. You can start by configuring
+openvswitch.conf, xl.conf and finally run helper script to set everything up.
+
+These scripts were written for my own use, and its possible they have some bugs
+or unforeseen deficiencies on your system. In either case, feel free to write
+me an email about it.
diff --git a/system/xen/openvswitch/openvswitch-clean.sh b/system/xen/openvswitch/openvswitch-clean.sh
new file mode 100644
index 0000000000..2d02d0ea44
--- /dev/null
+++ b/system/xen/openvswitch/openvswitch-clean.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+
+# This script applies configuration found in /etc/xen/openvswitch.conf to
+# all running domains and removes orphan entries from openvswitch database.
+# Written by Mario Preksavec <mario@slackware.hr>
+
+if [ -f /etc/xen/openvswitch.conf ]; then
+ declare -A rate ipv4 ipv6
+ . /etc/xen/openvswitch.conf
+ for domid in $(xenstore-list /local/domain); do
+ # Skip dom0
+ if [ $domid -eq 0 ]; then continue; fi
+
+ # Take settings from config file
+ name=$(xenstore-read /local/domain/$domid/name)
+ if [ ! -z ${rate[$name]} ]; then
+ rate=${rate[$name]}
+ elif [ ! -z ${rate[::default]} ]; then
+ rate=${rate[::default]}
+ else
+ rate=0
+ fi
+
+ if [ ! -z ${ipv4[$name]} ]; then
+ ipv4=${ipv4[$name]}
+ elif [ ! -z ${ipv4[::default]} ]; then
+ ipv4=${ipv4[::default]}
+ fi
+
+ if [ ! -z ${ipv6[$name]} ]; then
+ ipv6=${ipv6[$name]}
+ elif [ ! -z ${ipv6[::default]} ]; then
+ ipv6=${ipv6[::default]}
+ fi
+
+ # Domain can have more then one vif
+ for vif in $(xenstore-list /local/domain/$domid/device/vif); do
+ dev=vif$domid.$vif
+ # Handle qemu device names
+ if [ -e /sys/class/net/${dev}-emu ]; then dev=${dev}-emu; fi
+
+ bridge=$(xenstore-read /local/domain/0/backend/vif/$domid/$vif/bridge)
+ port=$(ovs-vsctl get interface $dev ofport)
+
+ # Remove flows and qos
+ ovs-ofctl del-flows $bridge in_port=$port
+ ovs-vsctl --timeout=30 -- --if-exists clear port $dev qos
+
+ if [ $rate -gt 0 ]; then
+ echo "Domain $name -- added ${rate}MB/s rate restriction to dev $dev"
+ policing_rate=$((rate * 1000))
+ policing_burst=$((rate * 100))
+ min_rate=$((rate * 1000000))
+ max_rate=$((rate * 1000000))
+ qos_id="@qos_$dev"
+ que_id="@que_$dev"
+ ovs-vsctl -- set interface $dev \
+ ingress_policing_rate=$policing_rate \
+ ingress_policing_burst=$policing_burst \
+ -- set port $dev qos=$qos_id \
+ -- --id=$qos_id create qos type=linux-htb \
+ other-config:max-rate=$max_rate queues=0=$que_id \
+ -- --id=$que_id create queue other-config:min-rate=$min_rate \
+ other-config:max-rate=$max_rate >/dev/null 2>&1
+ fi
+
+ if [ ! -z "$ipv4" ] || [ ! -z "$ipv6" ]; then
+ mac=$(xenstore-read /local/domain/$domid/device/vif/$vif/mac)
+
+ if [ ! -z "$ipv4" ]; then
+ echo "Domain $name -- added IPv4 $ipv4 restriction to dev $dev"
+ ovs-ofctl add-flow $bridge "in_port=$port priority=39000 \
+ dl_type=0x0800 nw_src=$ipv4 dl_src=$mac idle_timeout=0 \
+ action=normal" >/dev/null 2>&1
+ fi
+
+ if [ ! -z "$ipv6" ]; then
+ echo "Domain $name -- added IPv6 $ipv6 restriction to dev $dev"
+ ovs-ofctl add-flow $bridge "in_port=$port priority=39000 \
+ dl_type=0x86dd ipv6_src=$ipv6 dl_src=$mac idle_timeout=0 \
+ action=normal" >/dev/null 2>&1
+ fi
+
+ echo "Domain $name -- added ARP $mac restriction to dev $dev"
+ ovs-ofctl add-flow $bridge "in_port=$port priority=38500 \
+ dl_type=0x0806 dl_src=$mac idle_timeout=0 action=normal" \
+ >/dev/null 2>&1
+ ovs-ofctl add-flow $bridge "in_port=$port priority=38000 \
+ idle_timeout=0 action=drop" >/dev/null 2>&1
+
+ fi
+ done
+ done
+
+ # Behold, the garbage collector!
+ for bridge in $(ovs-vsctl list-br); do
+ # Remove unused ports -- unexistent devices
+ for dev in $(ovs-vsctl list-ports $bridge); do
+ if [ ! -e /sys/class/net/$dev ]; then
+ ovs-vsctl -- del-port $bridge $dev
+ fi
+ done
+ # Remove unused flows -- unexistent ports
+ for port in $(ovs-ofctl dump-flows $bridge \
+ | awk 'match($0, /in_port=([0-9]+)/, a) {print a[1]}' \
+ | sort -n | uniq); do
+ dev=$(ovs-vsctl --bare -- --columns=name find interface ofport=$port)
+ if [ -z "$dev" ]; then
+ ovs-ofctl del-flows $bridge in_port=$port
+ fi
+ done
+ done
+
+ # Remove unused qos
+ for qos in $(ovs-vsctl list qos | awk '/^_uuid/ {print $NF}'); do
+ if [ $(ovs-vsctl list port | grep -cF $qos) -eq 0 ]; then
+ ovs-vsctl -- destroy qos $qos
+ fi
+ done
+
+ # Remove unused queues
+ for queue in $(ovs-vsctl list queue | awk '/^_uuid/ {print $NF}'); do
+ if [ $(ovs-vsctl list qos | grep -cF $queue) -eq 0 ]; then
+ ovs-vsctl -- destroy queue $queue
+ fi
+ done
+fi
diff --git a/system/xen/openvswitch/openvswitch.conf b/system/xen/openvswitch/openvswitch.conf
new file mode 100644
index 0000000000..4d6a43e06f
--- /dev/null
+++ b/system/xen/openvswitch/openvswitch.conf
@@ -0,0 +1,15 @@
+# This is a very simple configuration file written in bash and sourced by
+# vif-openvswitch-extended script. Setting either IPv4 or IPv6 vars enables full
+# ARP restriction on the interface. Things get even more restrictive when one or
+# more defaults are set and applied to all guests. Rate limits are specified in
+# megabytes per second and ip address can have a netmask. For individual domain
+# configuration, use dom_name config as a starting point and replace it with the
+# actual domain name.
+
+#rate[::default]="10"
+#ipv4[::default]="169.254.0.0/16"
+#ipv6[::default]="fe80::/64"
+
+#rate[dom_name]="100"
+#ipv4[dom_name]="10.0.0.2"
+#ipv6[dom_name]="fd00::2"
diff --git a/system/xen/openvswitch/vif-openvswitch-extended b/system/xen/openvswitch/vif-openvswitch-extended
new file mode 100644
index 0000000000..41a70ca906
--- /dev/null
+++ b/system/xen/openvswitch/vif-openvswitch-extended
@@ -0,0 +1,197 @@
+#!/bin/bash
+#============================================================================
+# ${XEN_SCRIPT_DIR}/vif-openvswitch-extended
+#
+# Script for configuring a vif in openvswitch mode, extended to support
+# HTB rate limiting and IP/ARP spoof prevention.
+# Some inspiration drawn from:
+# http://openvswitch.org/support/config-cookbooks/qos-rate-limiting/
+# http://openvswitch.org/pipermail/discuss/2011-May/005178.html
+# Original script modified by Mario Preksavec <mario@slackware.hr>
+#
+# Rate limiting and antispoof config file:
+# XEN_CONFIG_DIR/openvswitch.conf
+#
+# Usage:
+# vif-openvswitch-extended (add|remove|online|offline)
+#
+# Environment vars:
+# vif vif interface name (required).
+# XENBUS_PATH path to this device's details in the XenStore (required).
+#
+# Read from the store:
+# bridge openvswitch to add the vif to (required).
+# ip list of IP networks for the vif, space-separated (optional).
+#
+# up:
+# Enslaves the vif interface to the bridge and adds iptables rules
+# for its ip addresses (if any).
+#
+# down:
+# Removes the vif interface from the bridge and removes the iptables
+# rules for its ip addresses (if any).
+#============================================================================
+
+dir=$(dirname "$0")
+. "$dir/vif-common.sh"
+
+check_tools()
+{
+ if ! command -v ovs-vsctl > /dev/null 2>&1; then
+ fatal "Unable to find ovs-vsctl tool"
+ fi
+ if ! command -v ip > /dev/null 2>&1; then
+ fatal "Unable to find ip tool"
+ fi
+}
+openvswitch_external_id() {
+ local dev=$1
+ local key=$2
+ local value=$3
+
+ echo "-- set interface $dev external-ids:\"$key\"=\"$value\""
+}
+
+openvswitch_external_id_all() {
+ local dev=$1
+ local frontend_id=$(xenstore_read "$XENBUS_PATH/frontend-id")
+ local vm_path=$(xenstore_read "/local/domain/${frontend_id}/vm")
+ local name=$(xenstore_read "${vm_path}/name")
+ openvswitch_external_id $dev "xen-vm-name" "$name"
+ local uuid=$(xenstore_read "${vm_path}/uuid")
+ openvswitch_external_id $dev "xen-vm-uuid" "$uuid"
+ local mac=$(xenstore_read "$XENBUS_PATH/mac")
+ openvswitch_external_id $dev "attached-mac" "$mac"
+}
+
+add_to_openvswitch () {
+ local dev=$1
+ local bridge="$(xenstore_read_default "$XENBUS_PATH/bridge" "$bridge")"
+ local tag trunk
+
+ if [[ $bridge =~ ^([^.:]+)(\.([[:digit:]]+))?(:([[:digit:]]+(:[[:digit:]]+)*))?$ ]]; then
+ bridge="${BASH_REMATCH[1]}"
+ tag="${BASH_REMATCH[3]}"
+ trunk="${BASH_REMATCH[5]//:/,}"
+ else
+ fatal "No valid bridge was specified"
+ fi
+
+ if [ $trunk ]; then
+ local trunk_arg="trunk=$trunk"
+ fi
+
+ if [ $tag ]; then
+ local tag_arg="tag=$tag"
+ fi
+
+ local vif_details="$(openvswitch_external_id_all $dev)"
+
+ do_or_die ovs-vsctl --timeout=30 \
+ -- --if-exists del-port $dev \
+ -- add-port "$bridge" $dev $tag_arg $trunk_arg $vif_details
+ do_or_die ip link set $dev up
+
+ if [ -f ${XEN_CONFIG_DIR}/openvswitch.conf ]; then
+ declare -A rate ipv4 ipv6
+ . ${XEN_CONFIG_DIR}/openvswitch.conf
+ local frontend_id=$(xenstore_read "$XENBUS_PATH/frontend-id")
+ local name=$(xenstore_read "/local/domain/${frontend_id}/name")
+
+ if [ ! -z ${rate[$name]} ]; then
+ local rate=${rate[$name]}
+ elif [ ! -z ${rate[::default]} ]; then
+ local rate=${rate[::default]}
+ else
+ local rate=0
+ fi
+
+ if [ $rate -gt 0 ]; then
+ local policing_rate=$((rate * 1000))
+ local policing_burst=$((rate * 100))
+ local min_rate=$((rate * 1000000))
+ local max_rate=$((rate * 1000000))
+ local qos_id="@qos_$dev"
+ local que_id="@que_$dev"
+ do_or_die ovs-vsctl -- set interface $dev \
+ ingress_policing_rate=$policing_rate \
+ ingress_policing_burst=$policing_burst \
+ -- set port $dev qos=$qos_id \
+ -- --id=$qos_id create qos type=linux-htb \
+ other-config:max-rate=$max_rate queues=0=$que_id \
+ -- --id=$que_id create queue other-config:min-rate=$min_rate \
+ other-config:max-rate=$max_rate > /dev/null
+ fi
+
+ if [ ! -z ${ipv4[$name]} ]; then
+ local ipv4=${ipv4[$name]}
+ elif [ ! -z ${ipv4[::default]} ]; then
+ local ipv4=${ipv4[::default]}
+ fi
+
+ if [ ! -z ${ipv6[$name]} ]; then
+ local ipv6=${ipv6[$name]}
+ elif [ ! -z ${ipv6[::default]} ]; then
+ local ipv6=${ipv6[::default]}
+ fi
+
+ if [ ! -z "$ipv4" ] || [ ! -z "$ipv6" ]; then
+ local mac=$(xenstore_read "$XENBUS_PATH/mac")
+ local port=$(ovs-vsctl get interface $dev ofport)
+
+ if [ ! -z "$ipv4" ]; then
+ do_or_die ovs-ofctl add-flow $bridge "in_port=$port priority=39000 \
+ dl_type=0x0800 nw_src=$ipv4 dl_src=$mac idle_timeout=0 \
+ action=normal" > /dev/null
+ fi
+
+ if [ ! -z "$ipv6" ]; then
+ do_or_die ovs-ofctl add-flow $bridge "in_port=$port priority=39000 \
+ dl_type=0x86dd ipv6_src=$ipv6 dl_src=$mac idle_timeout=0 \
+ action=normal" > /dev/null
+ fi
+
+ do_or_die ovs-ofctl add-flow $bridge "in_port=$port priority=38500 \
+ dl_type=0x0806 dl_src=$mac idle_timeout=0 action=normal" > /dev/null
+
+ do_or_die ovs-ofctl add-flow $bridge "in_port=$port priority=38000 \
+ idle_timeout=0 action=drop" > /dev/null
+ fi
+ fi
+}
+
+case "$command" in
+ add|online)
+ check_tools
+ setup_virtual_bridge_port $dev
+ add_to_openvswitch $dev
+ ;;
+
+ remove|offline)
+ if [ -f ${XEN_CONFIG_DIR}/openvswitch.conf ]; then
+ bridge=$(xenstore_read_default "$XENBUS_PATH/bridge" "$bridge")
+ queues=$(ovs-vsctl -- --if-exists get qos $dev queues \
+ | sed 's/[0-9]\+=//g;s/[{,}]//g')
+ # Remove flows
+ do_without_error ovs-ofctl del-flows $bridge in_port=$(ovs-vsctl \
+ -- --if-exists get interface $dev ofport)
+ # Remove queues & qos
+ do_without_error ovs-vsctl --timeout=30 \
+ -- --if-exists destroy queue $queues \
+ -- --if-exists destroy qos $dev \
+ -- --if-exists clear port $dev qos
+ fi
+ do_without_error ovs-vsctl --timeout=30 \
+ -- --if-exists del-port $dev
+ do_without_error ip link set $dev down
+ ;;
+esac
+
+if [ "$type_if" = vif ]; then
+ handle_iptable
+fi
+
+log debug "Successful vif-openvswitch $command for $dev."
+if [ "$type_if" = vif -a "$command" = "online" ]; then
+ success
+fi