--- /dev/null
+ How to Use Open vSwitch with Docker
+ ====================================
+
+This document describes how to use Open vSwitch with Docker 1.2.0 or
+later. This document assumes that you followed INSTALL or installed
+Open vSwitch from distribution packaging such as a .deb or .rpm.
+Consult www.docker.com for instructions on how to install Docker.
+
+Limitations
+-----------
+Currently there is no native integration of Open vSwitch in Docker, i.e.,
+one cannot use the Docker client to automatically add a container's
+network interface to an Open vSwitch bridge during the creation of the
+container. This document describes addition of new network interfaces to an
+already created container and in turn attaching that interface as a port to an
+Open vSwitch bridge.
+
+Setup
+-----
+* Create your container, e.g.:
+
+% docker run -d ubuntu:14.04 /bin/sh -c \
+"while true; do echo hello world; sleep 1; done"
+
+The above command creates a container with one network interface 'eth0'
+and attaches it to a Linux bridge called 'docker0'. 'eth0' by default
+gets an IP address in the 172.17.0.0/16 space. Docker sets up iptables
+NAT rules to let this interface talk to the outside world. Also since
+it is connected to 'docker0' bridge, it can talk to all other containers
+connected to the same bridge. If you prefer that no network interface be
+created by default, you can start your container with
+the option '--net=none', e,g.:
+
+% docker run -d --net=none ubuntu:14.04 /bin/sh -c \
+"while true; do echo hello world; sleep 1; done"
+
+The above commands will return a container id. You will need to pass this
+value to the utility 'ovs-docker' to create network interfaces attached to an
+Open vSwitch bridge as a port. This document will reference this value
+as $CONTAINER_ID in the next steps.
+
+* Add a new network interface to the container and attach it to an Open vSwitch
+ bridge. e.g.:
+
+% ovs-docker add-port br-int eth1 $CONTAINER_ID
+
+The above command will create a network interface 'eth1' inside the container
+and then attaches it to the Open vSwitch bridge 'br-int'. This is done by
+creating a veth pair. One end of the interface becomes 'eth1' inside the
+container and the other end attaches to 'br-int'.
+
+The script also lets one to add an IP address to the interface. e.g.:
+
+% ovs-docker add-port br-int eth1 $CONTAINER_ID 192.168.1.1/24
+
+* A previously added network interface can be deleted. e.g.:
+
+% ovs-docker del-port br-int eth1 $CONTAINER_ID
+
+All the previously added Open vSwitch interfaces inside a container can be
+deleted. e.g.:
+
+% ovs-docker del-ports br-int $CONTAINER_ID
+
+It is important that the same $CONTAINER_ID be passed to both add-port
+and del-port[s] commands.
+
+* More network control.
+
+Once a container interface is added to an Open vSwitch bridge, one can
+set VLANs, create Tunnels, add OpenFlow rules etc for more network control.
+Please read the man pages of ovs-vsctl, ovs-ofctl, ovs-vswitchd,
+ovsdb-server ovs-vswitchd.conf.db etc for more details.
+
+Docker networking is quite flexible and can be used in multiple ways. For more
+information, please read:
+https://docs.docker.com/articles/networking
+
+Bug Reporting
+-------------
+
+Please report problems to bugs@openvswitch.org.
--- /dev/null
+#!/bin/bash
+# Copyright (C) 2014 Nicira, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+check_command_avail () {
+ while [ $# -ne 0 ]; do
+ if ("$1" --version) > /dev/null 2>&1; then :; else
+ echo >&2 "$UTIL: missing $1, cannot proceed"
+ exit 1
+ fi
+ shift
+ done
+}
+
+ovs_vsctl () {
+ ovs-vsctl --timeout=60 "$@"
+}
+
+create_netns_link () {
+ mkdir -p /var/run/netns
+ if [ ! -e /var/run/netns/"$PID" ]; then
+ ln -s /proc/"$PID"/ns/net /var/run/netns/"$PID"
+ trap 'delete_netns_link' 0
+ for signal in 1 2 3 13 14 15; do
+ trap 'delete_netns_link; trap - $signal; kill -$signal $$' $signal
+ done
+ fi
+}
+
+delete_netns_link () {
+ rm -f /var/run/netns/"$PID"
+}
+
+add_port () {
+ BRIDGE="$1"
+ INTERFACE="$2"
+ CONTAINER="$3"
+ ADDRESS="$4"
+
+ if [ "$#" -lt 3 ]; then
+ usage
+ exit 1
+ fi
+
+ if ovs_vsctl --may-exist add-br "$BRIDGE"; then :; else
+ echo >&2 "$UTIL: Failed to create bridge $BRIDGE"
+ exit 1
+ fi
+
+ if PID=`docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else
+ echo >&2 "$UTIL: Failed to get the PID of the container"
+ exit 1
+ fi
+
+ create_netns_link
+
+ # Create a veth pair.
+ ID=`uuidgen | sed 's/-//g'`
+ PORTNAME="${ID:0:13}"
+ ip link add "${PORTNAME}_l" type veth peer name "${PORTNAME}_c"
+
+ # Add one end of veth to OVS bridge.
+ if ovs_vsctl --may-exist add-port "$BRIDGE" "${PORTNAME}_l" \
+ -- set interface "${PORTNAME}_l" \
+ external_ids:container_id="$CONTAINER" \
+ external_ids:container_iface="$INTERFACE"; then :; else
+ echo >&2 "$UTIL: Failed to add "${PORTNAME}_l" port to bridge $BRIDGE"
+ ip link delete "${PORTNAME}_l"
+ exit 1
+ fi
+
+ ip link set "${PORTNAME}_l" up
+
+ # Move "${PORTNAME}_c" inside the container and changes its name.
+ ip link set "${PORTNAME}_c" netns "$PID"
+ ip netns exec "$PID" ip link set dev "${PORTNAME}_c" name "$INTERFACE"
+ ip netns exec "$PID" ip link set "$INTERFACE" up
+
+ if [ -n "$ADDRESS" ]; then
+ ip netns exec "$PID" ip addr add "$ADDRESS" dev "$INTERFACE"
+ fi
+}
+
+del_port () {
+ BRIDGE="$1"
+ INTERFACE="$2"
+ CONTAINER="$3"
+
+ if [ "$#" -lt 3 ]; then
+ usage
+ exit 1
+ fi
+
+ PORT=`ovs_vsctl --data=bare --no-heading --columns=name find interface \
+ external_ids:container_id="$CONTAINER" \
+ external_ids:container_iface="$INTERFACE"`
+ if [ -z "$PORT" ]; then
+ echo >&2 "$UTIL: Failed to find any attached port in $BRIDGE" \
+ "for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE"
+ exit 1
+ fi
+
+ ovs_vsctl --if-exists del-port "$PORT"
+
+ ip link delete "$PORT"
+}
+
+del_ports () {
+ BRIDGE="$1"
+ CONTAINER="$2"
+ if [ "$#" -lt 2 ]; then
+ usage
+ exit 1
+ fi
+
+ PORTS=`ovs_vsctl --data=bare --no-heading --columns=name find interface \
+ external_ids:container_id="$CONTAINER"`
+ if [ -z "$PORTS" ]; then
+ exit 0
+ fi
+
+ for PORT in $PORTS; do
+ ovs_vsctl --if-exists del-port "$PORT"
+ ip link delete "$PORT"
+ done
+}
+
+usage() {
+ cat << EOF
+${UTIL}: Performs integration of Open vSwitch with Docker.
+usage: ${UTIL} COMMAND
+
+Commands:
+ add-port BRIDGE INTERFACE CONTAINER [ADDRESS]
+ Adds INTERFACE inside CONTAINER and connects it as a port
+ in Open vSwitch BRIDGE. Optionally, sets ADDRESS on
+ INTERFACE. ADDRESS can include a '/' to represent network
+ prefix length. e.g.:
+ ${UTIL} add-port br-int eth1 c474a0e2830e 192.168.1.2/24
+ del-port BRIDGE INTERFACE CONTAINER
+ Deletes INTERFACE inside CONTAINER and removes its
+ connection to Open vSwitch BRIDGE. e.g.:
+ ${UTIL} del-port br-int eth1 c474a0e2830e
+ del-ports BRIDGE CONTAINER
+ Removes all Open vSwitch interfaces from CONTAINER. e.g.:
+ ${UTIL} del-ports br-int c474a0e2830e
+Options:
+ -h, --help display this help message.
+EOF
+}
+
+UTIL=$(basename $0)
+check_command_avail ovs-vsctl docker uuidgen
+
+if (ip netns) > /dev/null 2>&1; then :; else
+ echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\
+ "cannot proceed"
+ exit 1
+fi
+
+if [ $# -eq 0 ]; then
+ usage
+ exit 0
+fi
+
+case $1 in
+ "add-port")
+ shift
+ add_port "$@"
+ exit 0
+ ;;
+ "del-port")
+ shift
+ del_port "$@"
+ exit 0
+ ;;
+ "del-ports")
+ shift
+ del_ports "$@"
+ exit 0
+ ;;
+ -h | --help)
+ usage
+ exit 0
+ ;;
+ *)
+ echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"
+ exit 1
+ ;;
+esac