On 9/24/26 7:55 AM, Ales Musil wrote: > The ovn-docker files were not updated for a very long time apart > from treewide adjustments. Let's remove the ovn-docker > utility files. > > Signed-off-by: Ales Musil <[email protected]> > ---
Hi Ales, This needs a small adjustment: https://github.com/ovsrobot/ovn/actions/runs/35963558453 This needs to be removed: https://github.com/ovn-kubernetes/ovn-kubernetes/blob/f1d5bcc05077d0f859cf7628aab507e06089b9e3/dist/images/Dockerfile.fedora#L79 And also backported on the ovn-kubernetes stable branch (I'm working on bumping our CI to release-1.4). The rest of this patch looks good to me but I'll skip it for now. Regards, Dumitru > Documentation/automake.mk | 2 - > Documentation/howto/docker.rst | 323 --------- > Documentation/howto/index.rst | 2 - > Documentation/howto/openstack-containers.rst | 135 ---- > Documentation/intro/install/fedora.rst | 2 +- > NEWS | 1 + > debian/.gitignore | 1 - > rhel/ovn-fedora.spec.in | 14 - > utilities/.gitignore | 2 - > utilities/automake.mk | 6 - > utilities/ovn-docker-overlay-driver.in | 442 ------------ > utilities/ovn-docker-underlay-driver.in | 677 ------------------- > 12 files changed, 2 insertions(+), 1605 deletions(-) > delete mode 100644 Documentation/howto/docker.rst > delete mode 100644 Documentation/howto/openstack-containers.rst > delete mode 100755 utilities/ovn-docker-overlay-driver.in > delete mode 100755 utilities/ovn-docker-underlay-driver.in > > diff --git a/Documentation/automake.mk b/Documentation/automake.mk > index b8187607e..79156fae0 100644 > --- a/Documentation/automake.mk > +++ b/Documentation/automake.mk > @@ -38,11 +38,9 @@ DOC_SOURCE = \ > Documentation/topics/vif-plug-providers/index.rst \ > Documentation/topics/vif-plug-providers/vif-plug-providers.rst \ > Documentation/howto/index.rst \ > - Documentation/howto/docker.rst \ > Documentation/howto/firewalld.rst \ > Documentation/howto/ipsec.rst \ > Documentation/howto/ssl.rst \ > - Documentation/howto/openstack-containers.rst \ > Documentation/ref/index.rst \ > Documentation/faq/index.rst \ > Documentation/faq/contributing.rst \ > diff --git a/Documentation/howto/docker.rst b/Documentation/howto/docker.rst > deleted file mode 100644 > index 1ada1fa2c..000000000 > --- a/Documentation/howto/docker.rst > +++ /dev/null > @@ -1,323 +0,0 @@ > -.. > - 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. > - > - Convention for heading levels in OVN documentation: > - > - ======= Heading 0 (reserved for the title in a document) > - ------- Heading 1 > - ~~~~~~~ Heading 2 > - +++++++ Heading 3 > - ''''''' Heading 4 > - > - Avoid deeper levels because they do not render well. > - > -=================================== > -Open Virtual Networking With Docker > -=================================== > - > -This document describes how to use Open Virtual Networking with Docker 1.9.0 > -or later. > - > -.. important:: > - > - Requires Docker version 1.9.0 or later. Only Docker 1.9.0+ comes with > support > - for multi-host networking. Consult www.docker.com for instructions on how > to > - install Docker. > - > -.. note:: > - > - You must build and install Open vSwitch before proceeding with the below > - guide. Refer to :doc:`/intro/install/index` for more information. > - > -Setup > ------ > - > -For multi-host networking with OVN and Docker, Docker has to be started with > a > -distributed key-value store. For example, if you decide to use consul as your > -distributed key-value store and your host IP address is ``$HOST_IP``, start > -your Docker daemon with:: > - > - $ docker daemon --cluster-store=consul://127.0.0.1:8500 \ > - --cluster-advertise=$HOST_IP:0 > - > -OVN provides network virtualization to containers. OVN's integration with > -Docker currently works in two modes - the "underlay" mode or the "overlay" > -mode. > - > -In the "underlay" mode, OVN requires a OpenStack setup to provide container > -networking. In this mode, one can create logical networks and can have > -containers running inside VMs, standalone VMs (without having any containers > -running inside them) and physical machines connected to the same logical > -network. This is a multi-tenant, multi-host solution. > - > -In the "overlay" mode, OVN can create a logical network amongst containers > -running on multiple hosts. This is a single-tenant (extendable to > multi-tenants > -depending on the security characteristics of the workloads), multi-host > -solution. In this mode, you do not need a pre-created OpenStack setup. > - > -For both the modes to work, a user has to install and start Open vSwitch in > -each VM/host that they plan to run their containers on. > - > -.. _docker-overlay: > - > -The "overlay" mode > ------------------- > - > -.. note:: > - > - OVN in "overlay" mode needs a minimum Open vSwitch version of 2.5. > - > -1. Start the central components. > - > - OVN architecture has a central component which stores your networking > intent > - in a database. On one of your machines, with an IP Address of > - ``$CENTRAL_IP``, where you have installed and started Open vSwitch, you > will > - need to start some central components. > - > - Start ovn-northd daemon. This daemon translates networking intent from > Docker > - stored in the OVN\_Northbound database to logical flows in > ``OVN_Southbound`` > - database. For example:: > - > - $ /usr/share/ovn/scripts/ovn-ctl start_northd > - > - With Open vSwitch version of 2.7 or greater, you need to run the following > - additional commands (Please read the manpages of ovn-nb for more control > - on the types of connection allowed.) :: > - > - $ ovn-nbctl set-connection ptcp:6641 > - $ ovn-sbctl set-connection ptcp:6642 > - > -2. One time setup > - > - On each host, where you plan to spawn your containers, you will need to > run > - the below command once. You may need to run it again if your OVS database > - gets cleared. It is harmless to run it again in any case:: > - > - $ ovs-vsctl set Open_vSwitch . \ > - external_ids:ovn-remote="tcp:$CENTRAL_IP:6642" \ > - external_ids:ovn-nb="tcp:$CENTRAL_IP:6641" \ > - external_ids:ovn-encap-ip=$LOCAL_IP \ > - external_ids:ovn-encap-type="$ENCAP_TYPE" > - > - where: > - > - ``$LOCAL_IP`` > - is the IP address via which other hosts can reach this host. This acts > as > - your local tunnel endpoint. > - > - ``$ENCAP_TYPE`` > - is the type of tunnel that you would like to use for overlay networking. > - The options are ``geneve`` or ``vxlan``. Your kernel must have support > for > - your chosen ``$ENCAP_TYPE``. You will need a minimum Linux kernel > version > - of 3.18 for ``geneve``. You can verify whether you have the support in > - your kernel as follows:: > - > - $ lsmod | grep $ENCAP_TYPE > - > - In addition, each Open vSwitch instance in an OVN deployment needs a > unique, > - persistent identifier, called the ``system-id``. If you install OVS from > - distribution packaging for Open vSwitch (e.g. .deb or .rpm packages), or > if > - you use the ovs-ctl utility included with Open vSwitch, it automatically > - configures a system-id. If you start Open vSwitch manually, you should > set > - one up yourself. For example:: > - > - $ id_file=/etc/openvswitch/system-id.conf > - $ test -e $id_file || uuidgen > $id_file > - $ ovs-vsctl set Open_vSwitch . external_ids:system-id=$(cat $id_file) > - > -3. Start the ``ovn-controller``. > - > - You need to run the below command on every boot:: > - > - $ /usr/share/ovn/scripts/ovn-ctl start_controller > - > -4. Start the Open vSwitch network driver. > - > - By default Docker uses Linux bridge for networking. But it has support for > - external drivers. To use Open vSwitch instead of the Linux bridge, you > will > - need to start the Open vSwitch driver. > - > - The Open vSwitch driver uses the Python's flask module to listen to > Docker's > - networking api calls. So, if your host does not have Python's flask > module, > - install it:: > - > - $ sudo pip install Flask > - > - Start the Open vSwitch driver on every host where you plan to create your > - containers. Refer to the note on ``$OVS_PYTHON_LIBS_PATH`` that is used > below > - at the end of this document:: > - > - $ PYTHONPATH=$OVS_PYTHON_LIBS_PATH ovn-docker-overlay-driver --detach > - > - .. note:: > - > - The ``$OVS_PYTHON_LIBS_PATH`` variable should point to the directory > where > - Open vSwitch Python modules are installed. If you installed Open vSwitch > - Python modules via the Debian package of ``python-openvswitch`` or via > pip > - by running ``pip install ovs``, you do not need to specify the PATH. If > - you installed it by following the instructions in > - :doc:`/intro/install/general`, then you should specify the PATH. In this > - case, the PATH depends on the options passed to ``./configure``. It is > - usually either ``/usr/share/openvswitch/python`` or > - ``/usr/local/share/openvswitch/python`` > - > -Docker has inbuilt primitives that closely match OVN's logical switches and > -logical port concepts. Consult Docker's documentation for all the possible > -commands. Here are some examples. > - > -Create a logical switch > -~~~~~~~~~~~~~~~~~~~~~~~ > - > -To create a logical switch with name 'foo', on subnet '192.168.1.0/24', run:: > - > - $ NID=`docker network create -d openvswitch --subnet=192.168.1.0/24 foo` > - > -List all logical switches > -~~~~~~~~~~~~~~~~~~~~~~~~~ > - > -:: > - > - $ docker network ls > - > -You can also look at this logical switch in OVN's northbound database by > -running the following command:: > - > - $ ovn-nbctl --db=tcp:$CENTRAL_IP:6640 ls-list > - > -Delete a logical switch > -~~~~~~~~~~~~~~~~~~~~~~~ > - > -:: > - > - $ docker network rm bar > - > - > -Create a logical port > -~~~~~~~~~~~~~~~~~~~~~ > - > -Docker creates your logical port and attaches it to the logical network in a > -single step. For example, to attach a logical port to network ``foo`` inside > -container busybox, run:: > - > - $ docker run -itd --net=foo --name=busybox busybox > - > -List all logical ports > -~~~~~~~~~~~~~~~~~~~~~~ > - > -Docker does not currently have a CLI command to list all logical ports but > you > -can look at them in the OVN database by running:: > - > - $ ovn-nbctl --db=tcp:$CENTRAL_IP:6640 lsp-list $NID > - > -Create and attach a logical port to a running container > -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > - > -:: > - > - $ docker network create -d openvswitch --subnet=192.168.2.0/24 bar > - $ docker network connect bar busybox > - > -Detach and delete a logical port from a running container > -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > - > -You can delete your logical port and detach it from a running container > -by running: > - > -:: > - > - $ docker network disconnect bar busybox > - > -.. _docker-underlay: > - > -The "underlay" mode > -------------------- > - > -.. note:: > - > - This mode requires that you have a OpenStack setup pre-installed with > - OVN providing the underlay networking. > - > -1. One time setup > - > - A OpenStack tenant creates a VM with a single network interface (or > multiple) > - that belongs to management logical networks. The tenant needs to fetch the > - port-id associated with the interface via which he plans to send the > container > - traffic inside the spawned VM. This can be obtained by running the below > - command to fetch the 'id' associated with the VM:: > - > - $ nova list > - > - and then by running:: > - > - $ neutron port-list --device_id=$id > - > - Inside the VM, download the OpenStack RC file that contains the tenant > - information (henceforth referred to as ``openrc.sh``). Edit the file and > add the > - previously obtained port-id information to the file by appending the > following > - line:: > - > - $ export OS_VIF_ID=$port_id > - > - After this edit, the file will look something like:: > - > - #!/bin/bash > - export OS_AUTH_URL=http://10.33.75.122:5000/v2.0 > - export OS_TENANT_ID=fab106b215d943c3bad519492278443d > - export OS_TENANT_NAME="demo" > - export OS_USERNAME="demo" > - export OS_VIF_ID=e798c371-85f4-4f2d-ad65-d09dd1d3c1c9 > - > -2. Create the Open vSwitch bridge > - > - If your VM has one ethernet interface (e.g.: 'eth0'), you will need to add > - that device as a port to an Open vSwitch bridge 'breth0' and move its IP > - address and route related information to that bridge. (If it has multiple > - network interfaces, you will need to create and attach an Open vSwitch > - bridge for the interface via which you plan to send your container > - traffic.) > - > - If you use DHCP to obtain an IP address, then you should kill the DHCP > - client that was listening on the physical Ethernet interface (e.g. eth0) > and > - start one listening on the Open vSwitch bridge (e.g. breth0). > - > - Depending on your VM, you can make the above step persistent across > reboots. > - For example, if your VM is Debian/Ubuntu-based, read > - `openvswitch-switch.README.Debian` found in `debian` folder. If your VM is > - RHEL-based, refer to :doc:`/intro/install/fedora`. > - > -3. Start the Open vSwitch network driver > - > - The Open vSwitch driver uses the Python's flask module to listen to > Docker's > - networking api calls. The driver also uses OpenStack's > - ``python-neutronclient`` libraries. If your host does not have Python's > - ``flask`` module or ``python-neutronclient`` you must install them. For > - example:: > - > - $ pip install python-neutronclient > - $ pip install Flask > - > - Once installed, source the ``openrc`` file:: > - > - $ . ./openrc.sh > - > - Start the network driver and provide your OpenStack tenant password when > - prompted:: > - > - $ PYTHONPATH=$OVS_PYTHON_LIBS_PATH ovn-docker-underlay-driver \ > - --bridge breth0 --detach > - > -From here-on you can use the same Docker commands as described in > -`docker-overlay`_. > - > -Refer to the ovs-architecture man pages (``man ovn-architecture``) to > -understand OVN's architecture in detail. > diff --git a/Documentation/howto/index.rst b/Documentation/howto/index.rst > index 6f6c59482..dab3058be 100644 > --- a/Documentation/howto/index.rst > +++ b/Documentation/howto/index.rst > @@ -45,6 +45,4 @@ OVN > .. toctree:: > :maxdepth: 1 > > - docker > - openstack-containers > firewalld > diff --git a/Documentation/howto/openstack-containers.rst > b/Documentation/howto/openstack-containers.rst > deleted file mode 100644 > index b6911d19e..000000000 > --- a/Documentation/howto/openstack-containers.rst > +++ /dev/null > @@ -1,135 +0,0 @@ > -.. > - 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. > - > - Convention for heading levels in OVN documentation: > - > - ======= Heading 0 (reserved for the title in a document) > - ------- Heading 1 > - ~~~~~~~ Heading 2 > - +++++++ Heading 3 > - ''''''' Heading 4 > - > - Avoid deeper levels because they do not render well. > - > -================================================ > -Integration of Containers with OVN and OpenStack > -================================================ > - > -Isolation between containers is weaker than isolation between VMs, so some > -environments deploy containers for different tenants in separate VMs as an > -additional security measure. This document describes creation of containers > -inside VMs and how they can be made part of the logical networks securely. > The > -created logical network can include VMs, containers and physical machines as > -endpoints. To better understand the proposed integration of containers with > -OVN and OpenStack, this document describes the end to end workflow with an > -example. > - > -* A OpenStack tenant creates a VM (say VM-A) with a single network interface > - that belongs to a management logical network. The VM is meant to host > - containers. OpenStack Nova chooses the hypervisor on which VM-A is > created. > - > -* A Neutron port may have been created in advance and passed in to Nova with > - the request to create a new VM. If not, Nova will issue a request to > Neutron > - to create a new port. The ID of the logical port from Neutron will also be > - used as the vif-id for the virtual network interface (VIF) of VM-A. > - > -* When VM-A is created on a hypervisor, its VIF gets added to the Open > vSwitch > - integration bridge. This creates a row in the Interface table of the > - ``Open_vSwitch`` database. As explained in the :doc:`integration guide > - </topics/integration>`, the vif-id associated with the VM network interface > - gets added in the ``external_ids:iface-id`` column of the newly created row > - in the Interface table. > - > -* Since VM-A belongs to a logical network, it gets an IP address. This IP > - address is used to spawn containers (either manually or through container > - orchestration systems) inside that VM and to monitor the health of the > - created containers. > - > -* The vif-id associated with the VM's network interface can be obtained by > - making a call to Neutron using tenant credentials. > - > -* This flow assumes a component called a "container network plugin". If you > - take Docker as an example for containers, you could envision the plugin to > be > - either a wrapper around Docker or a feature of Docker itself that > understands > - how to perform part of this workflow to get a container connected to a > - logical network managed by Neutron. The rest of the flow refers to this > - logical component that does not yet exist as the "container network > plugin". > - > -* All the calls to Neutron will need tenant credentials. These calls can > - either be made from inside the tenant VM as part of a container network > - plugin or from outside the tenant VM (if the tenant is not comfortable > using > - temporary Keystone tokens from inside the tenant VMs). For simplicity, > this > - document explains the work flow using the former method. > - > -* The container hosting VM will need Open vSwitch installed in it. The only > - work for Open vSwitch inside the VM is to tag network traffic coming from > - containers. > - > -* When a container needs to be created inside the VM with a container network > - interface that is expected to be attached to a particular logical switch, > the > - network plugin in that VM chooses any unused VLAN (This VLAN tag only needs > - to be unique inside that VM. This limits the number of container > interfaces > - to 4096 inside a single VM). This VLAN tag is stripped out in the > hypervisor > - by OVN and is only useful as a context (or metadata) for OVN. > - > -* The container network plugin then makes a call to Neutron to create a > logical > - port. In addition to all the inputs that a call to create a port in > Neutron > - that are currently needed, it sends the vif-id and the VLAN tag as inputs. > - > -* Neutron in turn will verify that the vif-id belongs to the tenant in > question > - and then uses the OVN specific plugin to create a new row in the > - Logical_Switch_Port table of the OVN Northbound Database. Neutron responds > - back with an IP address and MAC address for that network interface. So > - Neutron becomes the IPAM system and provides unique IP and MAC addresses > - across VMs and containers in the same logical network. > - > -* The Neutron API call above to create a logical port for the container could > - add a relatively significant amount of time to container creation. > However, > - an optimization is possible here. Logical ports could be created in > advance > - and reused by the container system doing container orchestration. > Additional > - Neutron API calls would only be needed if the port needs to be attached to > a > - different logical network. > - > -* When a container is eventually deleted, the network plugin in that VM may > - make a call to Neutron to delete that port. Neutron in turn will delete > the > - entry in the ``Logical_Switch_Port`` table of the OVN Northbound Database. > - > -As an example, consider Docker containers. Since Docker currently does not > -have a network plugin feature, this example uses a hypothetical wrapper > around > -Docker to make calls to Neutron. > - > -* Create a Logical switch:: > - > - $ ovn-docker --cred=cca86bd13a564ac2a63ddf14bf45d37f create network LS1 > - > - The above command will make a call to Neutron with the credentials to > create > - a logical switch. The above is optional if the logical switch has already > - been created from outside the VM. > - > -* List networks available to the tenant:: > - > - $ ovn-docker --cred=cca86bd13a564ac2a63ddf14bf45d37f list networks > - > -* Create a container and attach a interface to the previously created switch > as > - a logical port:: > - > - $ ovn-docker --cred=cca86bd13a564ac2a63ddf14bf45d37f --vif-id=$VIF_ID \ > - --network=LS1 run -d --net=none ubuntu:14.04 /bin/sh -c \ > - "while true; do echo hello world; sleep 1; done" > - > - The above command will make a call to Neutron with all the inputs it > - currently needs to create a logical port. In addition, it passes the > $VIF_ID > - and a unused VLAN. Neutron will add that information in OVN and return > back > - a MAC address and IP address for that interface. ovn-docker will then > create > - a veth pair, insert one end inside the container as 'eth0' and the other > end > - as a port of a local OVS bridge as an access port of the chosen VLAN. > diff --git a/Documentation/intro/install/fedora.rst > b/Documentation/intro/install/fedora.rst > index b1d2ea5df..b6ee88a4f 100644 > --- a/Documentation/intro/install/fedora.rst > +++ b/Documentation/intro/install/fedora.rst > @@ -109,7 +109,7 @@ Then execute the following from the OVN source directory > (in which > $ make rpm-fedora > > This will create the RPMs ``ovn``, ``ovn-central``, ``ovn-host``, > -``ovn-vtep``, ``ovn-docker``, and ``ovn-br-controller``, along with > +``ovn-vtep``, and ``ovn-br-controller``, along with > their debuginfo variants. > > You can also have the above commands automatically run the OVN unit > diff --git a/NEWS b/NEWS > index 3b41042b6..7f94d0b14 100644 > --- a/NEWS > +++ b/NEWS > @@ -18,6 +18,7 @@ Post v26.09.0 > obsolete. > - Removed OVN's ovs-bugtool plugin and helper scripts. > - Removed ovn-sim utility scripts. > + - Removed ovn-docker utility scripts. > > OVN v26.09.0 - xxx xx xxxx > -------------------------- > diff --git a/debian/.gitignore b/debian/.gitignore > index 8873d381c..2fd03d861 100644 > --- a/debian/.gitignore > +++ b/debian/.gitignore > @@ -10,5 +10,4 @@ > /ovn-controller-vtep > /ovn-host > /ovn-central > -/ovn-docker > /tmp > diff --git a/rhel/ovn-fedora.spec.in b/rhel/ovn-fedora.spec.in > index e70c581e7..8c8b96050 100644 > --- a/rhel/ovn-fedora.spec.in > +++ b/rhel/ovn-fedora.spec.in > @@ -111,16 +111,6 @@ Provides: openvswitch-ovn-vtep = > %{?epoch:%{epoch}:}%{version}-%{release} > %description vtep > OVN vtep controller > > -%package docker > -Summary: Open Virtual Network support > -License: ASL 2.0 > -Requires: ovn python3-openvswitch > -Obsoletes: openvswitch-ovn-docker > -Provides: openvswitch-ovn-docker = %{?epoch:%{epoch}:}%{version}-%{release} > - > -%description docker > -Docker network plugins for OVN. > - > %package br-controller > Summary: Open Virtual Network support > License: ASL 2.0 > @@ -528,10 +518,6 @@ fi > %config(noreplace) %{_sysconfdir}/logrotate.d/ovn > %{_unitdir}/[email protected] > > -%files docker > -%{_bindir}/ovn-docker-overlay-driver > -%{_bindir}/ovn-docker-underlay-driver > - > %files central > %{_bindir}/ovn-northd > %{_bindir}/ovn-ic > diff --git a/utilities/.gitignore b/utilities/.gitignore > index eb98594b7..fa1bc272b 100644 > --- a/utilities/.gitignore > +++ b/utilities/.gitignore > @@ -16,6 +16,4 @@ > /ovn-detrace.1 > /ovn-debug > /ovn-debug.8 > -/ovn-docker-overlay-driver > -/ovn-docker-underlay-driver > /ovn-lib > diff --git a/utilities/automake.mk b/utilities/automake.mk > index 7d3f320dc..edf3fe9cd 100644 > --- a/utilities/automake.mk > +++ b/utilities/automake.mk > @@ -18,16 +18,12 @@ MAN_ROOTS += \ > utilities/ovn-detrace.1.in > > bin_SCRIPTS += \ > - utilities/ovn-docker-overlay-driver \ > - utilities/ovn-docker-underlay-driver \ > utilities/ovn_detrace.py > > EXTRA_DIST += \ > utilities/ovn-ctl \ > utilities/ovn-lib.in \ > utilities/ovn-ctl.8.xml \ > - utilities/ovn-docker-overlay-driver.in \ > - utilities/ovn-docker-underlay-driver.in \ > utilities/ovn-nbctl.8.xml \ > utilities/ovn-sbctl.8.xml \ > utilities/ovn-ic-nbctl.8.xml \ > @@ -48,8 +44,6 @@ EXTRA_DIST += \ > CLEANFILES += \ > utilities/ovn-ctl.8 \ > utilities/ovn-lib \ > - utilities/ovn-docker-overlay-driver \ > - utilities/ovn-docker-underlay-driver \ > utilities/ovn-nbctl.8 \ > utilities/ovn-sbctl.8 \ > utilities/ovn-ic-nbctl.8 \ > diff --git a/utilities/ovn-docker-overlay-driver.in > b/utilities/ovn-docker-overlay-driver.in > deleted file mode 100755 > index f408bbdd8..000000000 > --- a/utilities/ovn-docker-overlay-driver.in > +++ /dev/null > @@ -1,442 +0,0 @@ > -#! @PYTHON3@ > -# Copyright (C) 2015 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. > - > -import argparse > -import ast > -import atexit > -import json > -import os > -import random > -import re > -import shlex > -import subprocess > -import sys > - > -import ovs.dirs > -import ovs.util > -import ovs.daemon > -import ovs.vlog > - > -from flask import Flask, jsonify > -from flask import request, abort > - > -app = Flask(__name__) > -vlog = ovs.vlog.Vlog("ovn-docker-overlay-driver") > - > -OVN_BRIDGE = "br-int" > -OVN_NB = "" > -PLUGIN_DIR = "/etc/docker/plugins" > -PLUGIN_FILE = "/etc/docker/plugins/openvswitch.spec" > - > - > -def call_popen(cmd): > - child = subprocess.Popen(cmd, stdout=subprocess.PIPE) > - output = child.communicate() > - if child.returncode: > - raise RuntimeError("Fatal error executing %s" % (cmd)) > - if len(output) == 0 or output[0] == None: > - output = "" > - else: > - output = output[0].strip() > - return output > - > - > -def call_prog(prog, args_list): > - cmd = [prog, "--timeout=5", "-vconsole:off"] + args_list > - return call_popen(cmd) > - > - > -def ovs_vsctl(*args): > - return call_prog("ovs-vsctl", list(args)) > - > - > -def ovn_nbctl(*args): > - args_list = list(args) > - database_option = "%s=%s" % ("--db", OVN_NB) > - args_list.insert(0, database_option) > - return call_prog("ovn-nbctl", args_list) > - > - > -def cleanup(): > - if os.path.isfile(PLUGIN_FILE): > - os.remove(PLUGIN_FILE) > - > - > -def ovn_init_overlay(): > - br_list = ovs_vsctl("list-br").split() > - if OVN_BRIDGE not in br_list: > - ovs_vsctl("--", "--may-exist", "add-br", OVN_BRIDGE, > - "--", "set", "bridge", OVN_BRIDGE, > - "external_ids:bridge-id=" + OVN_BRIDGE, > - "other-config:disable-in-band=true", "fail-mode=secure") > - > - global OVN_NB > - OVN_NB = ovs_vsctl("get", "Open_vSwitch", ".", > - "external_ids:ovn-nb").strip('"') > - if not OVN_NB: > - sys.exit("OVN central database's ip address not set") > - > - ovs_vsctl("set", "open_vswitch", ".", > - "external_ids:ovn-bridge=" + OVN_BRIDGE) > - > - > -def prepare(): > - parser = argparse.ArgumentParser() > - > - ovs.vlog.add_args(parser) > - ovs.daemon.add_args(parser) > - args = parser.parse_args() > - ovs.vlog.handle_args(args) > - ovs.daemon.handle_args(args) > - ovn_init_overlay() > - > - if not os.path.isdir(PLUGIN_DIR): > - os.makedirs(PLUGIN_DIR) > - > - ovs.daemon.daemonize() > - try: > - fo = open(PLUGIN_FILE, "w") > - fo.write("tcp://0.0.0.0:5000") > - fo.close() > - except Exception as e: > - ovs.util.ovs_fatal(0, "Failed to write to spec file (%s)" % str(e), > - vlog) > - > - atexit.register(cleanup) > - > - > [email protected]('/Plugin.Activate', methods=['POST']) > -def plugin_activate(): > - return jsonify({"Implements": ["NetworkDriver"]}) > - > - > [email protected]('/NetworkDriver.GetCapabilities', methods=['POST']) > -def get_capability(): > - return jsonify({"Scope": "global"}) > - > - > [email protected]('/NetworkDriver.DiscoverNew', methods=['POST']) > -def new_discovery(): > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.DiscoverDelete', methods=['POST']) > -def delete_discovery(): > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.CreateNetwork', methods=['POST']) > -def create_network(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - # NetworkID will have docker generated network uuid and it > - # becomes 'name' in a OVN Logical switch record. > - network = data.get("NetworkID", "") > - if not network: > - abort(400) > - > - # Limit subnet handling to ipv4 till ipv6 usecase is clear. > - ipv4_data = data.get("IPv4Data", "") > - if not ipv4_data: > - error = "create_network: No ipv4 subnet provided" > - return jsonify({'Err': error}) > - > - subnet = ipv4_data[0].get("Pool", "") > - if not subnet: > - error = "create_network: no subnet in ipv4 data from libnetwork" > - return jsonify({'Err': error}) > - > - gateway_ip = ipv4_data[0].get("Gateway", "").rsplit('/', 1)[0] > - if not gateway_ip: > - error = "create_network: no gateway in ipv4 data from libnetwork" > - return jsonify({'Err': error}) > - > - try: > - ovn_nbctl("ls-add", network, "--", "set", "Logical_Switch", > - network, "external_ids:subnet=" + subnet, > - "external_ids:gateway_ip=" + gateway_ip) > - except Exception as e: > - error = "create_network: ls-add %s" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.DeleteNetwork', methods=['POST']) > -def delete_network(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - try: > - ovn_nbctl("ls-del", nid) > - except Exception as e: > - error = "delete_network: ls-del %s" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.CreateEndpoint', methods=['POST']) > -def create_endpoint(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - interface = data.get("Interface", "") > - if not interface: > - error = "create_endpoint: no interfaces structure supplied by " \ > - "libnetwork" > - return jsonify({'Err': error}) > - > - ip_address_and_mask = interface.get("Address", "") > - if not ip_address_and_mask: > - error = "create_endpoint: ip address not provided by libnetwork" > - return jsonify({'Err': error}) > - > - ip_address = ip_address_and_mask.rsplit('/', 1)[0] > - mac_address_input = interface.get("MacAddress", "") > - mac_address_output = "" > - > - try: > - ovn_nbctl("lsp-add", nid, eid) > - except Exception as e: > - error = "create_endpoint: lsp-add (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - if not mac_address_input: > - mac_address = "02:%02x:%02x:%02x:%02x:%02x" % (random.randint(0, > 255), > - random.randint(0, > 255), > - random.randint(0, > 255), > - random.randint(0, > 255), > - random.randint(0, > 255)) > - else: > - mac_address = mac_address_input > - > - try: > - ovn_nbctl("lsp-set-addresses", eid, > - mac_address + " " + ip_address) > - except Exception as e: > - error = "create_endpoint: lsp-set-addresses (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - # Only return a mac address if one did not come as request. > - mac_address_output = "" > - if not mac_address_input: > - mac_address_output = mac_address > - > - return jsonify({"Interface": { > - "Address": "", > - "AddressIPv6": "", > - "MacAddress": mac_address_output > - }}) > - > - > -def get_lsp_addresses(eid): > - ret = ovn_nbctl("--if-exists", "get", "Logical_Switch_Port", eid, > - "addresses") > - if not ret: > - error = "endpoint not found in OVN database" > - return (None, None, error) > - addresses = ast.literal_eval(ret) > - if len(addresses) == 0: > - error = "unexpected return while fetching addresses" > - return (None, None, error) > - (mac_address, ip_address) = addresses[0].split() > - return (mac_address, ip_address, None) > - > - > [email protected]('/NetworkDriver.EndpointOperInfo', methods=['POST']) > -def show_endpoint(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - try: > - (mac_address, ip_address, error) = get_lsp_addresses(eid) > - if error: > - jsonify({'Err': error}) > - except Exception as e: > - error = "show_endpoint: get Logical_Switch_Port addresses. (%s)" \ > - % (str(e)) > - return jsonify({'Err': error}) > - > - veth_outside = eid[0:15] > - return jsonify({"Value": {"ip_address": ip_address, > - "mac_address": mac_address, > - "veth_outside": veth_outside > - }}) > - > - > [email protected]('/NetworkDriver.DeleteEndpoint', methods=['POST']) > -def delete_endpoint(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - try: > - ovn_nbctl("lsp-del", eid) > - except Exception as e: > - error = "delete_endpoint: lsp-del %s" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.Join', methods=['POST']) > -def network_join(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - sboxkey = data.get("SandboxKey", "") > - if not sboxkey: > - abort(400) > - > - # sboxkey is of the form: /var/run/docker/netns/CONTAINER_ID > - vm_id = sboxkey.rsplit('/')[-1] > - > - try: > - (mac_address, ip_address, error) = get_lsp_addresses(eid) > - if error: > - jsonify({'Err': error}) > - except Exception as e: > - error = "network_join: %s" % (str(e)) > - return jsonify({'Err': error}) > - > - veth_outside = eid[0:15] > - veth_inside = eid[0:13] + "_c" > - command = "ip link add %s type veth peer name %s" \ > - % (veth_inside, veth_outside) > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_join: failed to create veth pair (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - command = "ip link set dev %s address %s" \ > - % (veth_inside, mac_address) > - > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_join: failed to set veth mac address (%s)" % > (str(e)) > - return jsonify({'Err': error}) > - > - command = "ip link set %s up" % (veth_outside) > - > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_join: failed to up the veth interface (%s)" % > (str(e)) > - return jsonify({'Err': error}) > - > - try: > - ovs_vsctl("add-port", OVN_BRIDGE, veth_outside) > - ovs_vsctl("set", "interface", veth_outside, > - "external_ids:attached-mac=" + mac_address, > - "external_ids:iface-id=" + eid, > - "external_ids:vm-id=" + vm_id, > - "external_ids:iface-status=active") > - except Exception as e: > - error = "network_join: failed to create a port (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({"InterfaceName": { > - "SrcName": veth_inside, > - "DstPrefix": "eth" > - }, > - "Gateway": "", > - "GatewayIPv6": ""}) > - > - > [email protected]('/NetworkDriver.Leave', methods=['POST']) > -def network_leave(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - veth_outside = eid[0:15] > - command = "ip link delete %s" % (veth_outside) > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_leave: failed to delete veth pair (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - ovs_vsctl("--if-exists", "del-port", veth_outside) > - except Exception as e: > - error = "network_leave: failed to delete port (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > -if __name__ == '__main__': > - prepare() > - app.run(host='0.0.0.0') > diff --git a/utilities/ovn-docker-underlay-driver.in > b/utilities/ovn-docker-underlay-driver.in > deleted file mode 100755 > index 229418500..000000000 > --- a/utilities/ovn-docker-underlay-driver.in > +++ /dev/null > @@ -1,677 +0,0 @@ > -#! @PYTHON3@ > -# Copyright (C) 2015 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. > - > -import argparse > -import atexit > -import getpass > -import json > -import os > -import re > -import shlex > -import subprocess > -import sys > -import time > -import uuid > - > -import ovs.dirs > -import ovs.util > -import ovs.daemon > -import ovs.unixctl.server > -import ovs.vlog > - > -from neutronclient.v2_0 import client > -from flask import Flask, jsonify > -from flask import request, abort > - > -app = Flask(__name__) > -vlog = ovs.vlog.Vlog("ovn-docker-underlay-driver") > - > -AUTH_STRATEGY = "" > -AUTH_URL = "" > -ENDPOINT_URL = "" > -OVN_BRIDGE = "" > -PASSWORD = "" > -PLUGIN_DIR = "/etc/docker/plugins" > -PLUGIN_FILE = "/etc/docker/plugins/openvswitch.spec" > -TENANT_ID = "" > -USERNAME = "" > -VIF_ID = "" > - > - > -def call_popen(cmd): > - child = subprocess.Popen(cmd, stdout=subprocess.PIPE) > - output = child.communicate() > - if child.returncode: > - raise RuntimeError("Fatal error executing %s" % (cmd)) > - if len(output) == 0 or output[0] == None: > - output = "" > - else: > - output = output[0].strip() > - return output > - > - > -def call_prog(prog, args_list): > - cmd = [prog, "--timeout=5", "-vconsole:off"] + args_list > - return call_popen(cmd) > - > - > -def ovs_vsctl(*args): > - return call_prog("ovs-vsctl", list(args)) > - > - > -def cleanup(): > - if os.path.isfile(PLUGIN_FILE): > - os.remove(PLUGIN_FILE) > - > - > -def ovn_init_underlay(args): > - global USERNAME, PASSWORD, TENANT_ID, AUTH_URL, AUTH_STRATEGY, VIF_ID > - global OVN_BRIDGE > - > - if not args.bridge: > - sys.exit("OVS bridge name not provided") > - OVN_BRIDGE = args.bridge > - > - VIF_ID = os.environ.get('OS_VIF_ID', '') > - if not VIF_ID: > - sys.exit("env OS_VIF_ID not set") > - USERNAME = os.environ.get('OS_USERNAME', '') > - if not USERNAME: > - sys.exit("env OS_USERNAME not set") > - TENANT_ID = os.environ.get('OS_TENANT_ID', '') > - if not TENANT_ID: > - sys.exit("env OS_TENANT_ID not set") > - AUTH_URL = os.environ.get('OS_AUTH_URL', '') > - if not AUTH_URL: > - sys.exit("env OS_AUTH_URL not set") > - AUTH_STRATEGY = "keystone" > - > - PASSWORD = os.environ.get('OS_PASSWORD', '') > - if not PASSWORD: > - PASSWORD = getpass.getpass() > - > - > -def prepare(): > - parser = argparse.ArgumentParser() > - parser.add_argument('--bridge', help="The Bridge to which containers " > - "interfaces connect to.") > - > - ovs.vlog.add_args(parser) > - ovs.daemon.add_args(parser) > - args = parser.parse_args() > - ovs.vlog.handle_args(args) > - ovs.daemon.handle_args(args) > - ovn_init_underlay(args) > - > - if not os.path.isdir(PLUGIN_DIR): > - os.makedirs(PLUGIN_DIR) > - > - ovs.daemon.daemonize() > - try: > - fo = open(PLUGIN_FILE, "w") > - fo.write("tcp://127.0.0.1:5000") > - fo.close() > - except Exception as e: > - ovs.util.ovs_fatal(0, "Failed to write to spec file (%s)" % str(e), > - vlog) > - > - atexit.register(cleanup) > - > - > [email protected]('/Plugin.Activate', methods=['POST']) > -def plugin_activate(): > - return jsonify({"Implements": ["NetworkDriver"]}) > - > - > [email protected]('/NetworkDriver.GetCapabilities', methods=['POST']) > -def get_capability(): > - return jsonify({"Scope": "global"}) > - > - > [email protected]('/NetworkDriver.DiscoverNew', methods=['POST']) > -def new_discovery(): > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.DiscoverDelete', methods=['POST']) > -def delete_discovery(): > - return jsonify({}) > - > - > -def neutron_login(): > - try: > - neutron = client.Client(username=USERNAME, > - password=PASSWORD, > - tenant_id=TENANT_ID, > - auth_url=AUTH_URL, > - endpoint_url=ENDPOINT_URL, > - auth_strategy=AUTH_STRATEGY) > - except Exception as e: > - raise RuntimeError("Failed to login into Neutron(%s)" % str(e)) > - return neutron > - > - > -def get_networkuuid_by_name(neutron, name): > - param = {'fields': 'id', 'name': name} > - ret = neutron.list_networks(**param) > - if len(ret['networks']) > 1: > - raise RuntimeError("More than one network for the given name") > - elif len(ret['networks']) == 0: > - network = None > - else: > - network = ret['networks'][0]['id'] > - return network > - > - > -def get_subnetuuid_by_name(neutron, name): > - param = {'fields': 'id', 'name': name} > - ret = neutron.list_subnets(**param) > - if len(ret['subnets']) > 1: > - raise RuntimeError("More than one subnet for the given name") > - elif len(ret['subnets']) == 0: > - subnet = None > - else: > - subnet = ret['subnets'][0]['id'] > - return subnet > - > - > [email protected]('/NetworkDriver.CreateNetwork', methods=['POST']) > -def create_network(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - # NetworkID will have docker generated network uuid and it > - # becomes 'name' in a neutron network record. > - network = data.get("NetworkID", "") > - if not network: > - abort(400) > - > - # Limit subnet handling to ipv4 till ipv6 usecase is clear. > - ipv4_data = data.get("IPv4Data", "") > - if not ipv4_data: > - error = "create_network: No ipv4 subnet provided" > - return jsonify({'Err': error}) > - > - subnet = ipv4_data[0].get("Pool", "") > - if not subnet: > - error = "create_network: no subnet in ipv4 data from libnetwork" > - return jsonify({'Err': error}) > - > - gateway_ip = ipv4_data[0].get("Gateway", "").rsplit('/', 1)[0] > - if not gateway_ip: > - error = "create_network: no gateway in ipv4 data from libnetwork" > - return jsonify({'Err': error}) > - > - try: > - neutron = neutron_login() > - except Exception as e: > - error = "create_network: neutron login. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - if get_networkuuid_by_name(neutron, network): > - error = "create_network: network has already been created" > - return jsonify({'Err': error}) > - except Exception as e: > - error = "create_network: neutron network uuid by name. (%s)" % > (str(e)) > - return jsonify({'Err': error}) > - > - try: > - body = {'network': {'name': network, 'admin_state_up': True}} > - ret = neutron.create_network(body) > - network_id = ret['network']['id'] > - except Exception as e: > - error = "create_network: neutron net-create call. (%s)" % str(e) > - return jsonify({'Err': error}) > - > - subnet_name = "docker-%s" % (network) > - > - try: > - body = {'subnet': {'network_id': network_id, > - 'ip_version': 4, > - 'cidr': subnet, > - 'gateway_ip': gateway_ip, > - 'name': subnet_name}} > - created_subnet = neutron.create_subnet(body) > - except Exception as e: > - error = "create_network: neutron subnet-create call. (%s)" % str(e) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.DeleteNetwork', methods=['POST']) > -def delete_network(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - try: > - neutron = neutron_login() > - except Exception as e: > - error = "delete_network: neutron login. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - network = get_networkuuid_by_name(neutron, nid) > - if not network: > - error = "delete_network: failed in network by name. (%s)" % (nid) > - return jsonify({'Err': error}) > - except Exception as e: > - error = "delete_network: network uuid by name. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - neutron.delete_network(network) > - except Exception as e: > - error = "delete_network: neutron net-delete. (%s)" % str(e) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > - > -def reserve_vlan(): > - reserved_vlan = 0 > - vlans = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", > - "external_ids:vlans").strip('"') > - if not vlans: > - reserved_vlan = 1 > - ovs_vsctl("set", "Open_vSwitch", ".", > - "external_ids:vlans=" + str(reserved_vlan)) > - return reserved_vlan > - > - vlan_set = str(vlans).split(',') > - > - for vlan in range(1, 4095): > - if str(vlan) not in vlan_set: > - vlan_set.append(str(vlan)) > - reserved_vlan = vlan > - vlans = re.sub(r'[ \[\]\']', '', str(vlan_set)) > - ovs_vsctl("set", "Open_vSwitch", ".", > - "external_ids:vlans=" + vlans) > - return reserved_vlan > - > - if not reserved_vlan: > - raise RuntimeError("No more vlans available on this host") > - > - > -def unreserve_vlan(reserved_vlan): > - vlans = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", > - "external_ids:vlans").strip('"') > - if not vlans: > - return > - > - vlan_set = str(vlans).split(',') > - if str(reserved_vlan) not in vlan_set: > - return > - > - vlan_set.remove(str(reserved_vlan)) > - vlans = re.sub(r'[ \[\]\']', '', str(vlan_set)) > - if vlans: > - ovs_vsctl("set", "Open_vSwitch", ".", "external_ids:vlans=" + vlans) > - else: > - ovs_vsctl("remove", "Open_vSwitch", ".", "external_ids", "vlans") > - > - > -def create_port_underlay(neutron, network, eid, ip_address, mac_address): > - reserved_vlan = reserve_vlan() > - if mac_address: > - body = {'port': {'network_id': network, > - 'binding:profile': {'parent_name': VIF_ID, > - 'tag': int(reserved_vlan)}, > - 'mac_address': mac_address, > - 'fixed_ips': [{'ip_address': ip_address}], > - 'name': eid, > - 'admin_state_up': True}} > - else: > - body = {'port': {'network_id': network, > - 'binding:profile': {'parent_name': VIF_ID, > - 'tag': int(reserved_vlan)}, > - 'fixed_ips': [{'ip_address': ip_address}], > - 'name': eid, > - 'admin_state_up': True}} > - > - try: > - ret = neutron.create_port(body) > - mac_address = ret['port']['mac_address'] > - except Exception as e: > - unreserve_vlan(reserved_vlan) > - raise RuntimeError("Failed in creation of neutron port (%s)." % > str(e)) > - > - ovs_vsctl("set", "Open_vSwitch", ".", > - "external_ids:" + eid + "_vlan=" + str(reserved_vlan)) > - > - return mac_address > - > - > -def get_endpointuuid_by_name(neutron, name): > - param = {'fields': 'id', 'name': name} > - ret = neutron.list_ports(**param) > - if len(ret['ports']) > 1: > - raise RuntimeError("More than one endpoint for the given name") > - elif len(ret['ports']) == 0: > - endpoint = None > - else: > - endpoint = ret['ports'][0]['id'] > - return endpoint > - > - > [email protected]('/NetworkDriver.CreateEndpoint', methods=['POST']) > -def create_endpoint(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - interface = data.get("Interface", "") > - if not interface: > - error = "create_endpoint: no interfaces supplied by libnetwork" > - return jsonify({'Err': error}) > - > - ip_address_and_mask = interface.get("Address", "") > - if not ip_address_and_mask: > - error = "create_endpoint: ip address not provided by libnetwork" > - return jsonify({'Err': error}) > - > - ip_address = ip_address_and_mask.rsplit('/', 1)[0] > - mac_address_input = interface.get("MacAddress", "") > - mac_address_output = "" > - > - try: > - neutron = neutron_login() > - except Exception as e: > - error = "create_endpoint: neutron login. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - endpoint = get_endpointuuid_by_name(neutron, eid) > - if endpoint: > - error = "create_endpoint: Endpoint has already been created" > - return jsonify({'Err': error}) > - except Exception as e: > - error = "create_endpoint: endpoint uuid by name. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - network = get_networkuuid_by_name(neutron, nid) > - if not network: > - error = "Failed to get neutron network record for (%s)" % (nid) > - return jsonify({'Err': error}) > - except Exception as e: > - error = "create_endpoint: network uuid by name. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - mac_address = create_port_underlay(neutron, network, eid, ip_address, > - mac_address_input) > - except Exception as e: > - error = "create_endpoint: neutron port-create (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - if not mac_address_input: > - mac_address_output = mac_address > - > - return jsonify({"Interface": { > - "Address": "", > - "AddressIPv6": "", > - "MacAddress": mac_address_output > - }}) > - > - > [email protected]('/NetworkDriver.EndpointOperInfo', methods=['POST']) > -def show_endpoint(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - try: > - neutron = neutron_login() > - except Exception as e: > - error = "%s" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - endpoint = get_endpointuuid_by_name(neutron, eid) > - if not endpoint: > - error = "show_endpoint: Failed to get endpoint by name" > - return jsonify({'Err': error}) > - except Exception as e: > - error = "show_endpoint: get endpoint by name. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - ret = neutron.show_port(endpoint) > - mac_address = ret['port']['mac_address'] > - ip_address = ret['port']['fixed_ips'][0]['ip_address'] > - except Exception as e: > - error = "show_endpoint: show port (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - veth_outside = eid[0:15] > - return jsonify({"Value": {"ip_address": ip_address, > - "mac_address": mac_address, > - "veth_outside": veth_outside > - }}) > - > - > [email protected]('/NetworkDriver.DeleteEndpoint', methods=['POST']) > -def delete_endpoint(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - try: > - neutron = neutron_login() > - except Exception as e: > - error = "delete_endpoint: neutron login (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - endpoint = get_endpointuuid_by_name(neutron, eid) > - if not endpoint: > - return jsonify({}) > - > - reserved_vlan = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", > - "external_ids:" + eid + "_vlan").strip('"') > - if reserved_vlan: > - unreserve_vlan(reserved_vlan) > - ovs_vsctl("remove", "Open_vSwitch", ".", "external_ids", > - eid + "_vlan") > - > - try: > - neutron.delete_port(endpoint) > - except Exception as e: > - error = "delete_endpoint: neutron port-delete. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > - > [email protected]('/NetworkDriver.Join', methods=['POST']) > -def network_join(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - sboxkey = data.get("SandboxKey", "") > - if not sboxkey: > - abort(400) > - > - # sboxkey is of the form: /var/run/docker/netns/CONTAINER_ID > - vm_id = sboxkey.rsplit('/')[-1] > - > - try: > - neutron = neutron_login() > - except Exception as e: > - error = "network_join: neutron login. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - subnet_name = "docker-%s" % (nid) > - try: > - subnet = get_subnetuuid_by_name(neutron, subnet_name) > - if not subnet: > - error = "network_join: can't find subnet in neutron" > - return jsonify({'Err': error}) > - except Exception as e: > - error = "network_join: subnet uuid by name. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - ret = neutron.show_subnet(subnet) > - gateway_ip = ret['subnet']['gateway_ip'] > - if not gateway_ip: > - error = "network_join: no gateway_ip for the subnet" > - return jsonify({'Err': error}) > - except Exception as e: > - error = "network_join: neutron show subnet. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - endpoint = get_endpointuuid_by_name(neutron, eid) > - if not endpoint: > - error = "network_join: Failed to get endpoint by name" > - return jsonify({'Err': error}) > - except Exception as e: > - error = "network_join: neutron endpoint by name. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - ret = neutron.show_port(endpoint) > - mac_address = ret['port']['mac_address'] > - except Exception as e: > - error = "network_join: neutron show port. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - veth_outside = eid[0:15] > - veth_inside = eid[0:13] + "_c" > - command = "ip link add %s type veth peer name %s" \ > - % (veth_inside, veth_outside) > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_join: failed to create veth pair. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - command = "ip link set dev %s address %s" \ > - % (veth_inside, mac_address) > - > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_join: failed to set veth mac address. (%s)" % > (str(e)) > - return jsonify({'Err': error}) > - > - command = "ip link set %s up" % (veth_outside) > - > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_join: failed to up the veth iface. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - reserved_vlan = ovs_vsctl("--if-exists", "get", "Open_vSwitch", ".", > - "external_ids:" + eid + "_vlan").strip('"') > - if not reserved_vlan: > - error = "network_join: no reserved vlan for this endpoint" > - return jsonify({'Err': error}) > - ovs_vsctl("add-port", OVN_BRIDGE, veth_outside, "tag=" + > reserved_vlan) > - except Exception as e: > - error = "network_join: failed to create a OVS port. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({"InterfaceName": { > - "SrcName": veth_inside, > - "DstPrefix": "eth" > - }, > - "Gateway": gateway_ip, > - "GatewayIPv6": ""}) > - > - > [email protected]('/NetworkDriver.Leave', methods=['POST']) > -def network_leave(): > - if not request.data: > - abort(400) > - > - data = json.loads(request.data) > - > - nid = data.get("NetworkID", "") > - if not nid: > - abort(400) > - > - eid = data.get("EndpointID", "") > - if not eid: > - abort(400) > - > - veth_outside = eid[0:15] > - command = "ip link delete %s" % (veth_outside) > - try: > - call_popen(shlex.split(command)) > - except Exception as e: > - error = "network_leave: failed to delete veth pair. (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - try: > - ovs_vsctl("--if-exists", "del-port", veth_outside) > - except Exception as e: > - error = "network_leave: Failed to delete port (%s)" % (str(e)) > - return jsonify({'Err': error}) > - > - return jsonify({}) > - > -if __name__ == '__main__': > - prepare() > - app.run(host='127.0.0.1') _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
