aboutsummaryrefslogtreecommitdiff
path: root/system/xen/openvswitch/vif-openvswitch-extended
blob: 41a70ca906eced9a11f82328af15bf3410364907 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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