2 # Copyright (C) 2014 Nicira, Inc.
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:
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 # BASED ON https://github.com/openvswitch/ovs/blob/master/utilities/ovs-docker
20 #set -e #Exit script if a command fails
22 # Check for programs we'll need.
28 if test -x "$dir/$1"; then
33 echo >&2 "$0: $1 not found in \$PATH, please install and try again"
38 sudo ovs-vsctl --timeout=60 "$@"
44 sudo docker exec "$CONTAINER" ovs-vsctl --timeout=60 "$@"
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
58 delete_netns_link () {
59 sudo rm -f /var/run/netns/"$PID"
62 setup_ip_forwarding () {
63 sudo sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
65 sudo iptables -t nat -F
66 sudo iptables -P FORWARD ACCEPT
69 connect_namespace_to_container () {
74 if [ -z "$NAMESPACE" ] || [ -z "$CONTAINER" ]; then
75 echo >&2 "$UTIL add-port: not enough arguments (use --help for help)"
80 while [ $# -ne 0 ]; do
83 ADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
87 MACADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
91 echo >&2 "$UTIL add-port: unknown option \"$1\""
97 if PID=`sudo docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else
98 echo >&2 "$UTIL: Failed to get the PID of the container"
104 CONTAINER_IF="v-$NAMESPACE"
105 NAMESPACE_IF="v-${CONTAINER:0:12}"
108 if [ -z `sudo ip netns list | grep "$NAMESPACE"` ]; then
109 sudo ip netns add "$NAMESPACE"
112 # Create a veth pair in namespace.
113 sudo ip netns exec "$NAMESPACE" ip link add "$NAMESPACE_IF" type veth peer \
115 sudo ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_IF" up
117 # Move one side to container namespace.
118 sudo ip netns exec "$NAMESPACE" ip link set dev "$CONTAINER_IF" netns "$PID"
119 sudo ip netns exec "$PID" ip link set dev "$CONTAINER_IF" up
121 # And put it in integration bridge
122 d_ovs_vsctl "$CONTAINER" add-port br-int "$CONTAINER_IF"
124 if [ -n "$ADDRESS" ]; then
125 sudo ip netns exec "$NAMESPACE" ip addr add "$ADDRESS" dev "$NAMESPACE_IF"
128 if [ -n "$MACADDRESS" ]; then
129 sudo ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_IF" \
130 address "$MACADDRESS"
137 CHECKED_CONTAINER="$1"
143 while [ "$STATUS" != "$CHECKED_STATUS" -a $retry -le 60 ]; do
145 STATUS=`sudo docker exec "$CHECKED_CONTAINER" supervisorctl status "$CHECKED_PROGRAM" |\
149 [ "$STATUS" == "$CHECKED_STATUS" ] || exit 1
156 if [ -z `sudo docker images | awk '/^ovs-docker/ {print $1}'` ]; then
157 echo "$UTIL: Docker image ovs-docker does not exist, creating..."
158 sudo docker build -t ovs-docker .
161 CONTAINER=`sudo docker run -itd --privileged --cap-add ALL --name=ovs-node-"$NODE" ovs-docker`
163 if [ $? -ne 0 ]; then
164 echo >&2 "$UTIL: Failed to start container $NODE"
168 check_status "$CONTAINER" ovsdb-server RUNNING
169 check_status "$CONTAINER" ovs-vswitchd RUNNING
170 check_status "$CONTAINER" configure-ovs EXITED
172 CONTAINER_GW=`sudo docker inspect -f '{{ .NetworkSettings.Gateway }}' "$CONTAINER"`
173 CONTAINER_IP=`sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' "$CONTAINER"`
175 # Create a container bridge as integration for all guests
176 if d_ovs_vsctl "$CONTAINER" br-exists br-int; then :; else
177 d_ovs_vsctl "$CONTAINER" add-br br-int
178 d_ovs_vsctl "$CONTAINER" add-port br-int patch-tun -- \
179 set interface patch-tun type=patch option:peer=patch-int
183 # Create a container bridge as endpoint for all tunnels
184 if d_ovs_vsctl "$CONTAINER" br-exists br-tun; then :; else
185 d_ovs_vsctl "$CONTAINER" add-br br-tun
186 d_ovs_vsctl "$CONTAINER" add-port br-tun patch-int -- \
187 set interface patch-int type=patch option:peer=patch-tun
191 if [ "$TUN" == "vxlan" ]; then
193 elif [ "$TUN" == "vxlan-gpe" ]; then
194 TUN_OPT="type=vxlan option:exts=gpe"
199 if [ -z "$TUN" ]; then :; else
200 ovs_vsctl add-port br-tun vtep-node-"$NODE" -- \
201 set interface vtep-node-"$NODE" $TUN_OPT \
202 option:remote_ip="$CONTAINER_IP" ofport_request="$NODE"
203 d_ovs_vsctl "$CONTAINER" add-port br-tun vtep -- \
204 set interface vtep $TUN_OPT \
205 option:remote_ip="$CONTAINER_GW" ofport_request=10
208 if [ -z "$ODL" ]; then :; else
209 d_ovs_vsctl "$CONTAINER" set-manager "tcp:${ODL}:6640"
213 until [ $DO_GUEST -eq 0 ]; do
214 ADDRESS="10.0.${NODE}.${DO_GUEST}/16"
215 connect_namespace_to_container "ovsnsn${NODE}g$DO_GUEST" "$CONTAINER" \
216 --ipaddress="$ADDRESS"
221 spawn_nodes_and_guests () {
223 while [ $# -ne 0 ]; do
226 NODES=`expr X"$1" : 'X[^=]*=\(.*\)'`
230 GUESTS=`expr X"$1" : 'X[^=]*=\(.*\)'`
234 TUN=`expr X"$1" : 'X[^=]*=\(.*\)'`
238 ODL=`expr X"$1" : 'X[^=]*=\(.*\)'`
242 echo >&2 "$UTIL spawn: unknown option \"$1\""
249 TUN_REGEX="vxlan|vxlan-gpe|^$"
250 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])$"
252 if [[ $NODES =~ $NUM_REGEX ]]; then :; else
253 echo >&2 "$UTIL: NODES has to be a number"
257 if [ $NODES -gt 256 ]; then
258 echo >&2 "$UTIL: NODES has to be less than 256"
262 if [[ $GUESTS =~ $NUM_REGEX ]]; then :; else
263 echo >&2 "$UTIL: GUESTS has to be a number"
267 if [ $GUESTS -gt 256 ]; then
268 echo >&2 "$UTIL: GUESTS has to be less than 256"
272 if [[ $TUN =~ $TUN_REGEX ]]; then :; else
273 echo >&2 "$UTIL: TYPE has to be vxlan or vxlan-gpe"
277 if [[ $ODL =~ $IP_REGEX ]]; then :; else
278 echo >&2 "$UTIL: IP has to be a valid ip address"
282 # Make sure ip forwarding is enabled
285 # Create a host bridge as end point for all tunnels
286 if ovs_vsctl br-exists br-tun; then :; else
287 ovs_vsctl add-br br-tun
288 if [ -z "$ODL" ]; then :; else
289 ovs_vsctl set-manager "tcp:${ODL}:6640"
290 ovs_vsctl set-controller br-tun "tcp:${ODL}:6633"
295 until [ $DO_NODE -eq 0 ]; do
296 spawn_node "$DO_NODE" "$TUN"
303 for ID in `sudo docker ps -a | awk '/ovs-node-[0-9]+$/ {print $1}'`; do
304 sudo docker stop "$ID"
308 for NS in `sudo ip netns list | grep ovsns`; do
309 sudo ip netns del "$NS"
312 ovs_vsctl del-br br-tun
313 ovs_vsctl del-manager
319 ${UTIL}: Perform various tasks related with docker-ovs container.
320 usage: ${UTIL} COMMAND
323 spawn --nodes=NODES --guests=GUESTS --tun=TYPE --odl=IP
324 Runs NODES number of docker-ovs instances and attaches
325 GUESTS number of namespaces to each instance. If tun
326 option is specified, tunnel of such type will be configured
327 between the nodes and a host bridge. Types supported are
330 Stops containers and deletes namespaces
332 -h, --help display this help message.
337 search_path ovs-vsctl
340 #if [[ $EUID -ne 0 ]]; then
341 # echo "This script must be run as root" 1>&2
345 if (sudo ip netns) > /dev/null 2>&1; then :; else
346 echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\
351 if [ $# -eq 0 ]; then
359 spawn_nodes_and_guests "$@"
372 echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"