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