diff --git a/INSTALL.Docker b/INSTALL.Docker new file mode 100644 index 00000000000..1c492f3fe27 --- /dev/null +++ b/INSTALL.Docker @@ -0,0 +1,82 @@ + 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. diff --git a/Makefile.am b/Makefile.am index 77ceec6c0e8..43cc42069da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,6 +68,7 @@ EXTRA_DIST = \ FAQ \ INSTALL \ INSTALL.Debian \ + INSTALL.Docker \ INSTALL.DPDK \ INSTALL.Fedora \ INSTALL.KVM \ diff --git a/NEWS b/NEWS index 3307754ee67..abcb5257179 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,8 @@ Post-v2.3.0 still needed, so this should not be enabled on production environments. - Stats are no longer updated on fake bond interface. - Keep active bond slave selection across OVS restart. + - A simple wrapper script, 'ovs-docker', to integrate OVS with Docker + containers. v2.3.0 - 14 Aug 2014 diff --git a/README.md b/README.md index e4bc75a4ada..53861306229 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ platform, please see one of these files: To use Open vSwitch... +- ...with Docker on Linux, read INSTALL.Docker. + - ...with KVM on Linux, read INSTALL, read INSTALL.KVM. - ...with Libvirt, read INSTALL.Libvirt. diff --git a/debian/openvswitch-common.install b/debian/openvswitch-common.install index f2a0d48d7cf..11bb596708b 100644 --- a/debian/openvswitch-common.install +++ b/debian/openvswitch-common.install @@ -1,5 +1,6 @@ usr/bin/ovs-appctl usr/bin/ovs-benchmark +usr/bin/ovs-docker usr/bin/ovs-ofctl usr/bin/ovs-parse-backtrace usr/bin/ovs-pki diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in index c5e99ef9fa7..d3b0ecb1f2a 100644 --- a/rhel/openvswitch-fedora.spec.in +++ b/rhel/openvswitch-fedora.spec.in @@ -173,6 +173,7 @@ systemctl start openvswitch.service /usr/sbin/ovs-vswitchd /usr/sbin/ovsdb-server /usr/bin/ovs-appctl +/usr/bin/ovs-docker /usr/bin/ovs-dpctl /usr/bin/ovs-dpctl-top /usr/bin/ovs-ofctl diff --git a/rhel/openvswitch.spec.in b/rhel/openvswitch.spec.in index 5e99ccbc6e3..5d26d5940fd 100644 --- a/rhel/openvswitch.spec.in +++ b/rhel/openvswitch.spec.in @@ -130,6 +130,7 @@ exit 0 /usr/bin/ovs-benchmark /usr/bin/ovs-dpctl /usr/bin/ovs-dpctl-top +/usr/bin/ovs-docker /usr/bin/ovs-ofctl /usr/bin/ovs-parse-backtrace /usr/bin/ovs-pcap diff --git a/utilities/automake.mk b/utilities/automake.mk index 87ccb98c77f..9ddbbe20192 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -4,7 +4,8 @@ bin_PROGRAMS += \ utilities/ovs-dpctl \ utilities/ovs-ofctl \ utilities/ovs-vsctl -bin_SCRIPTS += utilities/ovs-pki +bin_SCRIPTS += utilities/ovs-docker \ + utilities/ovs-pki if HAVE_PYTHON bin_SCRIPTS += \ utilities/ovs-dpctl-top \ @@ -27,6 +28,7 @@ EXTRA_DIST += \ utilities/ovs-check-dead-ifs.in \ utilities/ovs-ctl.in \ utilities/ovs-dev.py \ + utilities/ovs-docker \ utilities/ovs-dpctl-top.in \ utilities/ovs-l3ping.in \ utilities/ovs-lib.in \ diff --git a/utilities/ovs-docker b/utilities/ovs-docker new file mode 100755 index 00000000000..4a43a15dec7 --- /dev/null +++ b/utilities/ovs-docker @@ -0,0 +1,201 @@ +#!/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