Modified SFC test suite for creating flows in sff's and classifiers
[integration/test.git] / csit / suites / sfc / Full_Deploy / docker-ovs.sh
1 #!/bin/bash
2 # Copyright (C) 2014 Nicira, Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 # BASED ON https://github.com/openvswitch/ovs/blob/master/utilities/ovs-docker
17 # MODIFIED
18
19 set -o xtrace
20 #set -e #Exit script if a command fails
21
22 # Check for programs we'll need.
23 search_path () {
24     save_IFS=$IFS
25     IFS=:
26     for dir in $PATH; do
27         IFS=$save_IFS
28         if test -x "$dir/$1"; then
29             return 0
30         fi
31     done
32     IFS=$save_IFS
33     echo >&2 "$0: $1 not found in \$PATH, please install and try again"
34     exit 1
35 }
36
37 clean_iptables () {
38     sudo iptables -F
39     sudo iptables -t nat -F
40 }
41
42 ovs_vsctl () {
43     sudo ovs-vsctl --timeout=60 "$@"
44 }
45
46 d_ovs_vsctl () {
47     CONTAINER="$1"
48     shift
49     sudo docker exec "$CONTAINER" ovs-vsctl --timeout=60 "$@"
50 }
51
52 create_netns_link () {
53     sudo mkdir -p /var/run/netns
54     if [ ! -e /var/run/netns/"$PID" ]; then
55         sudo ln -s /proc/"$PID"/ns/net /var/run/netns/"$PID"
56         trap 'delete_netns_link' 0
57         for signal in 1 2 3 13 14 15; do
58             trap 'delete_netns_link; trap - $signal; kill -$signal $$' $signal
59         done
60     fi
61 }
62
63 delete_netns_link () {
64     sudo rm -f /var/run/netns/"$PID"
65 }
66
67 connect_namespace_to_container () {
68
69     NAMESPACE="$1"
70     CONTAINER="$2"
71
72     if [ -z "$NAMESPACE" ] || [ -z "$CONTAINER" ]; then
73         echo >&2 "$UTIL add-port: not enough arguments (use --help for help)"
74         exit 1
75     fi
76
77     shift 2
78     while [ $# -ne 0 ]; do
79         case $1 in
80             --ipaddress=*)
81                 ADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
82                 shift
83                 ;;
84             --macaddress=*)
85                 MACADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
86                 shift
87                 ;;
88             *)
89                 echo >&2 "$UTIL add-port: unknown option \"$1\""
90                 exit 1
91                 ;;
92         esac
93     done
94
95     if PID=`sudo docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else
96         echo >&2 "$UTIL: Failed to get the PID of the container"
97         exit 1
98     fi
99
100     create_netns_link
101
102     CONTAINER_IF="v-$NAMESPACE"
103     NAMESPACE_IF="v-${CONTAINER:0:12}"
104
105     # Create namespace
106     if [ -z `sudo ip netns list | grep "$NAMESPACE"` ]; then
107          sudo ip netns add "$NAMESPACE"
108     fi
109
110     # Create a veth pair in namespace.
111     sudo ip netns exec "$NAMESPACE" ip link add "$NAMESPACE_IF" type veth peer \
112        name "$CONTAINER_IF"
113     sudo ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_IF" up
114
115     # Move one side to container namespace.
116     sudo ip netns exec "$NAMESPACE" ip link set dev "$CONTAINER_IF" netns "$PID"
117     sudo ip netns exec "$PID" ip link set dev "$CONTAINER_IF" up
118
119     # And put it in integration bridge
120     d_ovs_vsctl "$CONTAINER" add-port br-int "$CONTAINER_IF"
121
122     if [ -n "$ADDRESS" ]; then
123         sudo ip netns exec "$NAMESPACE" ip addr add "$ADDRESS" dev "$NAMESPACE_IF"
124     fi
125
126     if [ -n "$MACADDRESS" ]; then
127         sudo ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_IF" \
128            address "$MACADDRESS"
129     fi
130
131     delete_netns_link
132 }
133
134 spawn_node () {
135     NODE="$1"
136     TUN="$2"
137
138     if [ -z `sudo docker images | awk '/^ovs-docker/ {print $1}'` ]; then
139         echo "$UTIL: Docker image ovs-docker does not exist, creating..."
140         sudo docker build -t ovs-docker .
141     fi
142
143     CONTAINER=`sudo docker run -itd --privileged --cap-add ALL --name=ovs-node-"$NODE" ovs-docker`
144
145     if [ $? -ne 0 ]; then
146        echo >&2 "$UTIL: Failed to start container $NODE"
147        exit 1
148     fi
149
150     STATUS=""
151     while [ "$STATUS" != "EXITED" ]; do
152        STATUS=`sudo docker exec "$CONTAINER" supervisorctl status configure-ovs |\
153           awk '{print $2}'`
154     done
155     CONTAINER_GW=`sudo docker inspect -f '{{ .NetworkSettings.Gateway }}' "$CONTAINER"`
156     CONTAINER_IP=`sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' "$CONTAINER"`
157
158     # Create a container bridge as integration for all guests
159     if d_ovs_vsctl "$CONTAINER" br-exists br-int; then :; else
160         d_ovs_vsctl "$CONTAINER" add-br br-int
161         d_ovs_vsctl "$CONTAINER" add-port br-int patch-tun -- \
162            set interface patch-tun type=patch option:peer=patch-int
163     fi
164
165
166     # Create a container bridge as endpoint for all tunnels
167     if d_ovs_vsctl "$CONTAINER" br-exists br-tun; then :; else
168         d_ovs_vsctl "$CONTAINER" add-br br-tun
169         d_ovs_vsctl "$CONTAINER" add-port br-tun patch-int -- \
170            set interface patch-int type=patch option:peer=patch-tun
171     fi
172
173     # Setup the tunnel
174     if [ "$TUN" == "vxlan" ]; then
175         TUN_OPT="type=vxlan"
176     elif [ "$TUN" == "vxlan-gpe" ]; then
177         TUN_OPT="type=vxlan option:exts=gpe"
178     else
179         TUN_OPT=""
180     fi
181
182     if [ -z "$TUN" ]; then :; else
183         ovs_vsctl add-port br-tun vtep-node-"$NODE" -- \
184             set interface vtep-node-"$NODE" $TUN_OPT \
185             option:remote_ip="$CONTAINER_IP" ofport_request="$NODE"
186         d_ovs_vsctl "$CONTAINER" add-port br-tun vtep -- \
187             set interface vtep $TUN_OPT \
188             option:remote_ip="$CONTAINER_GW" ofport_request=10
189     fi
190
191     if [ -z "$ODL" ]; then :; else
192         d_ovs_vsctl "$CONTAINER" set-manager "tcp:${ODL}:6640"
193     fi
194
195     DO_GUEST="$GUESTS"
196     until [ $DO_GUEST -eq 0 ]; do
197         ADDRESS="10.0.${NODE}.${DO_GUEST}/16"
198         connect_namespace_to_container "ovsnsn${NODE}g$DO_GUEST" "$CONTAINER" \
199            --ipaddress="$ADDRESS"
200         let DO_GUEST-=1
201     done
202 }
203
204 spawn_nodes_and_guests () {
205
206     while [ $# -ne 0 ]; do
207         case $1 in
208             --nodes=*)
209                 NODES=`expr X"$1" : 'X[^=]*=\(.*\)'`
210                 shift
211                 ;;
212             --guests=*)
213                 GUESTS=`expr X"$1" : 'X[^=]*=\(.*\)'`
214                 shift
215                 ;;
216             --tun=*)
217                 TUN=`expr X"$1" : 'X[^=]*=\(.*\)'`
218                 shift
219                 ;;
220             --odl=*)
221                 ODL=`expr X"$1" : 'X[^=]*=\(.*\)'`
222                 shift
223                 ;;
224             *)
225                 echo >&2 "$UTIL spawn: unknown option \"$1\""
226                 exit 1
227                 ;;
228         esac
229     done
230
231     NUM_REGEX="[0-9]+"
232     TUN_REGEX="vxlan|vxlan-gpe|^$"
233     IP_REGEX="^$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
234
235     if [[ $NODES =~ $NUM_REGEX ]]; then :; else
236          echo >&2 "$UTIL: NODES has to be a number"
237          exit 1
238     fi
239
240     if [ $NODES -gt 256 ]; then
241          echo >&2 "$UTIL: NODES has to be less than 256"
242          exit 1
243     fi
244
245     if [[ $GUESTS =~ $NUM_REGEX ]]; then :; else
246          echo >&2 "$UTIL: GUESTS has to be a number"
247          exit 1
248     fi
249
250     if [ $GUESTS -gt 256 ]; then
251          echo >&2 "$UTIL: GUESTS has to be less than 256"
252          exit 1
253     fi
254
255     if [[ $TUN =~ $TUN_REGEX ]]; then :; else
256          echo >&2 "$UTIL: TYPE has to be vxlan or vxlan-gpe"
257          exit 1
258     fi
259
260     if [[ $ODL =~ $IP_REGEX ]]; then :; else
261          echo >&2 "$UTIL: IP has to be a valid ip address"
262          exit 1
263     fi
264
265     # Create a host bridge as end point for all tunnels
266     if ovs_vsctl br-exists br-tun; then :; else
267         ovs_vsctl add-br br-tun
268         if [ -z "$ODL" ]; then :; else
269             ovs_vsctl set-manager "tcp:${ODL}:6640"
270             ovs_vsctl set-controller br-tun "tcp:${ODL}:6633"
271         fi
272     fi
273
274     DO_NODE="$NODES"
275     until [ $DO_NODE -eq 0 ]; do
276        spawn_node "$DO_NODE" "$TUN"
277        let DO_NODE-=1
278     done
279 }
280
281 clean() {
282
283      for ID in `sudo docker ps -a | awk '/ovs-node-[0-9]+$/ {print $1}'`; do
284          sudo docker stop "$ID"
285          sudo docker rm "$ID"
286      done
287
288      for NS in `sudo ip netns list | grep ovsns`; do
289          sudo ip netns del "$NS"
290      done
291
292      ovs_vsctl del-br br-tun
293      ovs_vsctl del-manager
294 }
295
296
297 usage() {
298     cat << EOF
299 ${UTIL}: Perform various tasks related with docker-ovs container.
300 usage: ${UTIL} COMMAND
301
302 Commands:
303   spawn --nodes=NODES --guests=GUESTS --tun=TYPE --odl=IP
304                     Runs NODES number of docker-ovs instances and attaches
305                     GUESTS number of namespaces to each instance. If tun
306                     option is specified, tunnel of such type will be configured
307                     between the nodes and a host bridge. Types supported are
308                     vxlan or vxlan-gpe
309   clean
310                     Stops containers and deletes namespaces
311 Options:
312   -h, --help        display this help message.
313 EOF
314 }
315
316 UTIL=$(basename $0)
317 search_path ovs-vsctl
318 search_path docker
319 clean_iptables
320
321 #if [[ $EUID -ne 0 ]]; then
322 #   echo "This script must be run as root" 1>&2
323 #   exit 1
324 #fi
325
326 if (sudo ip netns) > /dev/null 2>&1; then :; else
327     echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\
328              "cannot proceed"
329     exit 1
330 fi
331
332 if [ $# -eq 0 ]; then
333     usage
334     exit 0
335 fi
336
337 case $1 in
338     "spawn")
339         shift
340         spawn_nodes_and_guests "$@"
341         exit 0
342         ;;
343     "clean")
344         shift
345         clean
346         exit 0
347         ;;
348     -h | --help)
349         usage
350         exit 0
351         ;;
352     *)
353         echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"
354         exit 1
355         ;;
356 esac
357