198 lines
6.6 KiB
Bash
198 lines
6.6 KiB
Bash
#!/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
|