2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 22:35:15 +00:00

xenserver: Remove xenserver.

Remove the current xenserver implementation - it is obsolete and
since 3.0 we do not support kernel module builds [1].

1. https://mail.openvswitch.org/pipermail/ovs-dev/2022-July/395789.html

[i.maximets]
Can be added back if people willing to maintain it will be found.

Signed-off-by: Greg Rose <gvrose8192@gmail.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
Greg Rose
2022-08-08 13:36:02 -07:00
committed by Ilya Maximets
parent ac1332216e
commit 83c9518e7c
47 changed files with 55 additions and 7794 deletions

View File

@@ -21,7 +21,6 @@ DOC_SOURCE = \
Documentation/intro/install/rhel.rst \
Documentation/intro/install/userspace.rst \
Documentation/intro/install/windows.rst \
Documentation/intro/install/xenserver.rst \
Documentation/tutorials/index.rst \
Documentation/tutorials/faucet.rst \
Documentation/tutorials/ovs-advanced.rst \

View File

@@ -44,11 +44,11 @@ Q: What is Open vSwitch?
Q: What virtualization platforms can use Open vSwitch?
A: Open vSwitch can currently run on any Linux-based virtualization
platform (kernel 3.10 and newer), including: KVM, VirtualBox, Xen, Xen
Cloud Platform, XenServer. As of Linux 3.3 it is part of the mainline
kernel. The bulk of the code is written in platform- independent C and is
easily ported to other environments. We welcome inquires about integrating
Open vSwitch with other virtualization platforms.
platform (kernel 3.10 and newer), including: KVM and VirtualBox.
As of Linux 3.3 it is part of the mainline kernel. The bulk of the
code is written in platform- independent C and is easily ported to
other environments. We welcome inquires about integrating Open
vSwitch with other virtualization platforms.
Q: How can I try Open vSwitch?
@@ -58,8 +58,7 @@ Q: How can I try Open vSwitch?
Debian, Ubuntu, Fedora.
You may also download and run a virtualization platform that already has
Open vSwitch integrated. For example, download a recent ISO for XenServer
or Xen Cloud Platform. Be aware that the version integrated with a
Open vSwitch integrated. Be aware that the version integrated with a
particular platform may not be the most recent Open vSwitch release.
Q: Does Open vSwitch only work on Linux?

View File

@@ -72,8 +72,7 @@ Both VMs (`vm1` and `vm2`) run on `host1`.
Each VM has a single interface that appears as a Linux device (e.g., ``tap0``) on the physical host.
.. note::
For Xen/XenServer, VM interfaces appears as Linux devices with names like
``vif1.0``. Other Linux systems may present these interfaces as ``vnet0``,
VM interfaces may appear as Linux devices with names like ``vnet0``,
``vnet1``, etc.
Configuration Steps

View File

@@ -76,8 +76,7 @@ Two Virtual Machines
This guide uses two virtual machines - `vm1` and `vm2`- running on `host1`.
.. note::
For Xen/XenServer, VM interfaces appears as Linux devices with names like
``vif1.0``. Other Linux systems may present these interfaces as ``vnet0``,
VM interfaces may appear as Linux devices with names like ``vnet0``,
``vnet1``, etc.
Configuration Steps

View File

@@ -83,8 +83,7 @@ Each VM has a single interface that appears as a Linux device (e.g., ``tap0``)
on the physical host.
.. note::
For Xen/XenServer, VM interfaces appears as Linux devices with names like
``vif1.0``. Other Linux systems may present these interfaces as ``vnet0``,
VM interfaces may appear as Linux devices with names like ``vnet0``,
``vnet1``, etc.
Configuration Steps

View File

@@ -75,8 +75,7 @@ Each VM has a single interface that appears as a Linux device (e.g., ``tap0``)
on the physical host.
.. note::
For Xen/XenServer, VM interfaces appears as Linux devices with names like
``vif1.0``. Other Linux systems may present these interfaces as ``vnet0``,
VM interfaces may appear as Linux devices with names like ``vnet0``,
``vnet1``, etc.
Configuration Steps

View File

@@ -598,8 +598,8 @@ userspace flows using the ovs-ofctl utility and also uses the
``other_config:flow-restore-wait`` column to keep the traffic downtime to the
minimum. The ovs-ctl utility's ``force-reload-kmod`` function does all of the
above, but also replaces the old kernel module with the new one. Open vSwitch
startup scripts for Debian, XenServer and RHEL use ovs-ctl's functions and it
is recommended that these functions be used for other software platforms too.
startup scripts for Debian and RHEL use ovs-ctl's functions and it is
recommended that these functions be used for other software platforms too.
Reporting Bugs
--------------

View File

@@ -42,7 +42,6 @@ Installation from Source
general
netbsd
windows
xenserver
userspace
dpdk
afxdp

View File

@@ -1,229 +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 Open vSwitch 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 vSwitch on Citrix XenServer
================================
This document describes how to build and install Open vSwitch on a Citrix
XenServer host. If you want to install Open vSwitch on a generic Linux or BSD
host, refer to :doc:`general` instead.
Open vSwitch should work with XenServer 5.6.100 and later. However, Open
vSwitch requires Python 3.4 or later, so using Open vSwitch with XenServer 6.5
or earlier requires installing Python 3.x.
Building
--------
You may build from an Open vSwitch distribution tarball or from an Open vSwitch
Git tree. The recommended build environment to build RPMs for Citrix XenServer
is the DDK VM available from Citrix.
1. If you are building from an Open vSwitch Git tree, then you will need to
first create a distribution tarball by running::
$ ./boot.sh
$ ./configure
$ make dist
You cannot run this in the DDK VM, because it lacks tools that are necessary
to bootstrap the Open vSwitch distribution. Instead, you must run this on a
machine that has the tools listed in :ref:`general-install-reqs` as
prerequisites for building from a Git tree.
2. Copy the distribution tarball into ``/usr/src/redhat/SOURCES`` inside
the DDK VM.
3. In the DDK VM, unpack the distribution tarball into a temporary directory
and "cd" into the root of the distribution tarball.
4. To build Open vSwitch userspace, run::
$ rpmbuild -bb xenserver/openvswitch-xen.spec
This produces three RPMs in ``/usr/src/redhat/RPMS/i386``:
- ``openvswitch``
- ``openvswitch-modules-xen``
- ``openvswitch-debuginfo``
The above command automatically runs the Open vSwitch unit tests. To
disable the unit tests, run::
$ rpmbuild -bb --without check xenserver/openvswitch-xen.spec
Build Parameters
----------------
``openvswitch-xen.spec`` needs to know a number of pieces of information about
the XenServer kernel. Usually, it can figure these out for itself, but if it
does not do it correctly then you can specify them yourself as parameters to
the build. Thus, the final ``rpmbuild`` step above can be elaborated as::
$ VERSION=<Open vSwitch version>
$ KERNEL_NAME=<Xen Kernel name>
$ KERNEL_VERSION=<Xen Kernel version>
$ KERNEL_FLAVOR=<Xen Kernel flavor(suffix)>
$ rpmbuild \
-D "openvswitch_version $VERSION" \
-D "kernel_name $KERNEL_NAME" \
-D "kernel_version $KERNEL_VERSION" \
-D "kernel_flavor $KERNEL_FLAVOR" \
-bb xenserver/openvswitch-xen.spec
where:
``<openvswitch version>``
is the version number that appears in the name of the Open vSwitch tarball,
e.g. 0.90.0.
``<Xen Kernel name>``
is the name of the XenServer kernel package, e.g. ``kernel-xen`` or
``kernel-NAME-xen``, without the ``kernel-`` prefix.
``<Xen Kernel version>``
is the output of::
$ rpm -q --queryformat "%{Version}-%{Release}" <kernel-devel-package>,
e.g. ``2.6.32.12-0.7.1.xs5.6.100.323.170596``, where
``<kernel-devel-package>`` is the name of the ``-devel`` package
corresponding to ``<Xen Kernel name>``.
``<Xen Kernel flavor (suffix)>``
is either ``xen`` or ``kdump``, where ``xen`` flavor is the main running
kernel flavor and the ``kdump`` flavor is the crashdump kernel flavor.
Commonly, one would specify ``xen`` here.
For XenServer 6.5 or above, the kernel version naming no longer contains
KERNEL_FLAVOR. In fact, only providing the ``uname -r`` output is enough. So,
the final ``rpmbuild`` step changes to::
$ KERNEL_UNAME=<`uname -r` output>
$ rpmbuild \
-D "kenel_uname $KERNEL_UNAME" \
-bb xenserver/openvswitch-xen.spec
Installing Open vSwitch for XenServer
-------------------------------------
To install Open vSwitch on a XenServer host, or to upgrade to a newer version,
copy the ``openvswitch`` and ``openvswitch-modules-xen`` RPMs to that host with
``scp``, then install them with ``rpm -U``, e.g.::
$ scp openvswitch-$VERSION-1.i386.rpm \
openvswitch-modules-xen-$XEN_KERNEL_VERSION-$VERSION-1.i386.rpm \
root@<host>:
# Enter <host>'s root password.
$ ssh root@<host>
# Enter <host>'s root password again.
$ rpm -U openvswitch-$VERSION-1.i386.rpm \
openvswitch-modules-xen-$XEN_KERNEL_VERSION-$VERSION-1.i386.rpm
To uninstall Open vSwitch from a XenServer host, remove the packages::
$ ssh root@<host>
# Enter <host>'s root password again.
$ rpm -e openvswitch openvswitch-modules-xen-$XEN_KERNEL_VERSION
After installing or uninstalling Open vSwitch, the XenServer should be rebooted
as soon as possible.
Open vSwitch Boot Sequence on XenServer
---------------------------------------
When Open vSwitch is installed on XenServer, its startup script
``/etc/init.d/openvswitch`` runs early in boot. It does roughly the following:
* Loads the OVS kernel module, openvswitch.
* Starts ovsdb-server, the OVS configuration database.
* XenServer expects there to be no bridges configured at startup, but the OVS
configuration database likely still has bridges configured from before
reboot. To match XenServer expectations, the startup script deletes all
configured bridges from the database.
* Starts ovs-vswitchd, the OVS switching daemon.
At this point in the boot process, then, there are no Open vSwitch bridges,
even though all of the Open vSwitch daemons are running. Later on in boot,
``/etc/init.d/management-interface`` (part of XenServer, not Open vSwitch)
creates the bridge for the XAPI management interface by invoking
``/opt/xensource/libexec/interface-reconfigure``. Normally this program
consults XAPI's database to obtain information about how to configure the
bridge, but XAPI is not running yet(\*) so it instead consults
``/var/xapi/network.dbcache``, which is a cached copy of the most recent
network configuration.
(\*) Even if XAPI were running, if this XenServer node is a pool slave then the
query would have to consult the master, which requires network access,
which begs the question of how to configure the management interface.
XAPI starts later on in the boot process. XAPI can then create other bridges
on demand using ``/opt/xensource/libexec/interface-reconfigure``. Now that
XAPI is running, that program consults XAPI directly instead of reading the
cache.
As part of its own startup, XAPI invokes the Open vSwitch XAPI plugin script
``/etc/xapi.d/openvswitch-cfg-update`` passing the ``update`` command. The
plugin script does roughly the following:
* Calls ``/opt/xensource/libexec/interface-reconfigure`` with the ``rewrite``
command, to ensure that the network cache is up-to-date.
* Queries the Open vSwitch manager setting (named ``vswitch_controller``) from
the XAPI database for the XenServer pool.
* If XAPI and OVS are configured for different managers, or if OVS is
configured for a manager but XAPI is not, runs ``ovs-vsctl emer-reset`` to
bring the Open vSwitch configuration to a known state. One effect of
emer-reset is to deconfigure any manager from the OVS database.
* If XAPI is configured for a manager, configures the OVS manager to match with
``ovs-vsctl set-manager``.
Notes
-----
* The Open vSwitch boot sequence only configures an OVS configuration database
manager. There is no way to directly configure an OpenFlow controller on
XenServer and, as a consequence of the step above that deletes all of the
bridges at boot time, controller configuration only persists until XenServer
reboot. The configuration database manager can, however, configure
controllers for bridges. See the BUGS section of ovs-testcontroller(8) for
more information on this topic.
* The Open vSwitch startup script automatically adds a firewall rule to allow
GRE traffic. This rule is needed for the XenServer feature called "Cross-Host
Internal Networks" (CHIN) that uses GRE. If a user configures tunnels other
than GRE (ex: Geneve, VXLAN, LISP), they will have to either manually add a
iptables firewall rule to allow the tunnel traffic or add it through a
startup script (Please refer to the "enable-protocol" command in the
ovs-ctl(8) manpage).
Reporting Bugs
--------------
Please report problems to bugs@openvswitch.org.

View File

@@ -481,9 +481,8 @@ Files
Example
=======
The files ``debian/openvswitch-switch.init`` and
``xenserver/etc_init.d_openvswitch`` in the Open vSwitch source
distribution are good examples of how to use ``ovs-ctl``.
The file ``debian/openvswitch-switch.init`` in the Open vSwitch source
distribution is a good example of how to use ``ovs-ctl``.
See Also
========

View File

@@ -152,11 +152,11 @@ special handling of received packets.
Several of the physical switches that support LACP block all traffic for ports
that are configured to use LACP, until LACP is negotiated with the host. When
configuring a LACP bond on a OVS host (eg: XenServer), this means that there
will be an interruption of the network connectivity between the time the ports
on the physical switch and the bond on the OVS host are configured. The
interruption may be relatively long, if different people are responsible for
managing the switches and the OVS host.
configuring a LACP bond on a OVS host, this means that there will be an
interruption of the network connectivity between the time the ports on the
physical switch and the bond on the OVS host are configured. The interruption
may be relatively long, if different people are responsible for managing the
switches and the OVS host.
Such network connectivity failure can be avoided if LACP can be configured on
the OVS host before configuring the physical switch, and having the OVS host

View File

@@ -29,9 +29,7 @@ This document describes how to integrate Open vSwitch onto a new platform to
expose the state of the switch and attached devices for centralized control.
(If you are looking to port the switching components of Open vSwitch to a new
platform, refer to :doc:`porting`) The focus of this guide is on hypervisors,
but many of the interfaces are useful for hardware switches, as well. The
XenServer integration is the most mature implementation, so most of the
examples are drawn from it.
but many of the interfaces are useful for hardware switches, as well.
The externally visible interface to this integration is platform-agnostic. We
encourage anyone who integrates Open vSwitch to use the same interface, because
@@ -48,18 +46,15 @@ ensure that these values are correctly populated and maintained.
An integrator sets the columns in the database by talking to the ovsdb-server
daemon. A few of the columns can be set during startup by calling the ovs-ctl
tool from inside the startup scripts. The ``xenserver/etc_init.d_openvswitch``
tool from inside the startup scripts. The ``rhel/etc_init.d_openvswitch``
script provides examples of its use, and the ovs-ctl(8) manpage contains
complete documentation. At runtime, ovs-vsctl can be used to set columns in
the database. The script ``xenserver/etc_xensource_scripts_vif`` contains
examples of its use, and ovs-vsctl(8) manpage contains complete documentation.
the database.
Python and C bindings to the database are provided if deeper integration with a
program are needed. The XenServer ovs-xapi-sync daemon
(``xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync``) provides an example
of using the Python bindings. More information on the python bindings is
available at ``python/ovs/db/idl.py``. Information on the C bindings is
available at ``lib/ovsdb-idl.h``.
program are needed. More information on the python bindings is available at
``python/ovs/db/idl.py``. Information on the C bindings is available at
``lib/ovsdb-idl.h``.
The following diagram shows how integration scripts fit into the Open vSwitch
architecture:
@@ -83,7 +78,6 @@ architecture:
| | | |
| +---------------------+ | |
| | Integration scripts | | |
| | (ex: ovs-xapi-sync) | | |
| +---------------------+ | |
| | Userspace |
|----------------------------------------------------------|
@@ -105,8 +99,7 @@ individual column, please refer to the ovs-vswitchd.conf.db(5) manpage.
The ``Open_vSwitch`` table describes the switch as a whole. The
``system_type`` and ``system_version`` columns identify the platform to the
controller. The ``external_ids:system-id`` key uniquely identifies the
physical host. In XenServer, the system-id will likely be the same as the UUID
returned by ``xe host-list``. This key allows controllers to distinguish
physical host. This key allows controllers to distinguish
between multiple hypervisors.
Most of this configuration can be done with the ovs-ctl command at startup.
@@ -114,7 +107,7 @@ For example:
::
$ ovs-ctl --system-type="XenServer" --system-version="6.0.0-50762p" \
$ ovs-ctl --system-type="KVM" --system-version="4.18.el8_6" \
--system-id="${UUID}" "${other_options}" start
Alternatively, the ovs-vsctl command may be used to set a particular value at
@@ -132,9 +125,7 @@ Bridge table
------------
The Bridge table describes individual bridges within an Open vSwitch instance.
The ``external-ids:bridge-id`` key uniquely identifies a particular bridge. In
XenServer, this will likely be the same as the UUID returned by ``xe
network-list`` for that particular bridge.
The ``external-ids:bridge-id`` key uniquely identifies a particular bridge.
For example, to set the identifier for bridge "br0", the following command can
be used:
@@ -161,18 +152,14 @@ attached-mac
This field contains the MAC address of the device attached to the interface.
On a hypervisor, this is the MAC address of the interface as seen inside a
VM. It does not necessarily correlate to the host-side MAC address. For
example, on XenServer, the MAC address on a VIF in the hypervisor is always
FE:FF:FF:FF:FF:FF, but inside the VM a normal MAC address is seen.
VM. It does not necessarily correlate to the host-side MAC address.
iface-id
This field uniquely identifies the interface. In hypervisors, this allows
the controller to follow VM network interfaces as VMs migrate. A well-chosen
identifier should also allow an administrator or a controller to associate
the interface with the corresponding object in the VM management system. For
example, the Open vSwitch integration with XenServer by default uses the
XenServer assigned UUID for a VIF record as the iface-id.
the interface with the corresponding object in the VM management system.
iface-status

View File

@@ -29,12 +29,6 @@ Tutorials
Getting started with Open vSwitch (OVS).
.. TODO(stephenfin): We could really do with a few basic tutorials, along with
some more specialized ones (DPDK, XenServer, Windows). The latter could
probably be formed from the install guides, but the former will need to be
produced from scratch or reproduced from blogs (with permission of the
author)
.. toctree::
:maxdepth: 2

View File

@@ -482,7 +482,6 @@ include ipsec/automake.mk
include vswitchd/automake.mk
include ovsdb/automake.mk
include rhel/automake.mk
include xenserver/automake.mk
include python/automake.mk
include tutorial/automake.mk
include vtep/automake.mk

2
NEWS
View File

@@ -86,6 +86,8 @@ v3.0.0 - xx xxx xxxx
- Previously deprecated Linux kernel module is now fully removed from
the OVS source tree. The version provided with the Linux kernel
should be used instead.
- XenServer: Support for integration with XenServer has been removed due to
lack of maintenance and bitrot.
v2.17.0 - 17 Feb 2022

View File

@@ -588,32 +588,6 @@ AC_DEFUN([OVS_CONDITIONAL_CC_OPTION_DEFINE],
[Define to 1 if compiler supports the '$1' option.])
fi])
dnl Check for too-old XenServer.
AC_DEFUN([OVS_CHECK_XENSERVER_VERSION],
[AC_CACHE_CHECK([XenServer release], [ovs_cv_xsversion],
[if test -e /etc/redhat-release; then
ovs_cv_xsversion=`sed -n 's/^XenServer DDK release \([[^-]]*\)-.*/\1/p' /etc/redhat-release`
fi
if test -z "$ovs_cv_xsversion"; then
ovs_cv_xsversion=none
fi])
case $ovs_cv_xsversion in
none)
;;
[[1-9]][[0-9]]* | dnl XenServer 10 or later
[[6-9]]* | dnl XenServer 6 or later
5.[[7-9]]* | dnl XenServer 5.7 or later
5.6.[[1-9]][[0-9]][[0-9]][[0-9]]* | dnl XenServer 5.6.1000 or later
5.6.[[2-9]][[0-9]][[0-9]]* | dnl XenServer 5.6.200 or later
5.6.1[[0-9]][[0-9]]) dnl Xenserver 5.6.100 or later
;;
*)
AC_MSG_ERROR([This appears to be XenServer $ovs_cv_xsversion, but only XenServer 5.6.100 or later is supported. (If you are really using a supported version of XenServer, you may override this error message by specifying 'ovs_cv_xsversion=5.6.100' on the "configure" command line.)])
;;
esac])
dnl OVS_CHECK_SPARSE_TARGET
dnl
dnl The "cgcc" script from "sparse" isn't very good at detecting the

View File

@@ -11,7 +11,6 @@
^lib/strsep\.c$
^third-party/
^windows/
^xenserver/
^debian/README.Debian$
^debian/copyright.in$
^debian/openvswitch-switch.init$

View File

@@ -124,7 +124,6 @@ OVS_CHECK_BACKTRACE
OVS_CHECK_PERF_EVENT
OVS_CHECK_VALGRIND
OVS_CHECK_SOCKET_LIBS
OVS_CHECK_XENSERVER_VERSION
OVS_CHECK_GROFF
OVS_CHECK_TLS
OVS_CHECK_ATOMIC_LIBS

View File

@@ -1,117 +0,0 @@
# Copyright (c) 2011, 2012 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 re
def xapi_local():
return Session()
class Session(object):
def __init__(self):
self.xenapi = XenAPI()
class Failure(Exception):
pass
class XenAPI(object):
def __init__(self):
self.network = Network()
self.pool = Pool()
self.VIF = VIF()
self.VM = VM()
def login_with_password(self, unused_username, unused_password):
pass
class RecordRef(object):
def __init__(self, attrs):
self.attrs = attrs
class Table(object):
def __init__(self, records):
self.records = records
def get_all(self):
return [RecordRef(rec) for rec in self.records]
def get_all_records_where(self, condition):
k, v = re.match(r'field "([^"]*)"="([^"]*)"$', condition).groups()
d = {}
# I'm sure that the keys used in the dictionary below are wrong
# but I can't find any documentation on get_all_records_where
# and this satisfies the current test case.
i = 0
for rec in self.records:
if rec[k] == v:
d[i] = rec
i += 1
return d
def get_by_uuid(self, uuid):
recs = [rec for rec in self.records if rec["uuid"] == uuid]
if len(recs) != 1:
raise Failure("No record with UUID %s" % uuid)
return RecordRef(recs[0])
def get_record(self, record_ref):
return record_ref.attrs
class Network(Table):
__records = ({"uuid": "9b66c68b-a74e-4d34-89a5-20a8ab352d1e",
"bridge": "xenbr0",
"other_config":
{"vswitch-controller-fail-mode": "secure",
"nicira-bridge-id": "custom bridge ID"}},
{"uuid": "e1c9019d-375b-45ac-a441-0255dd2247de",
"bridge": "xenbr1",
"other_config":
{"vswitch-disable-in-band": "true"}})
def __init__(self):
Table.__init__(self, Network.__records)
class Pool(Table):
__records = ({"uuid": "7a793edf-e5f4-4994-a0f9-cee784c0cda3",
"other_config":
{"vswitch-controller-fail-mode": "secure"}},)
def __init__(self):
Table.__init__(self, Pool.__records)
class VIF(Table):
__records = ({"uuid": "6ab1b260-398e-49ba-827b-c7696108964c",
"other_config":
{"nicira-iface-id": "custom iface ID"}},)
def __init__(self):
Table.__init__(self, VIF.__records)
class VM(Table):
__records = ({"uuid": "fcb8a3f6-dc04-41d2-8b8a-55afd2b755b8",
"other_config":
{"nicira-vm-id": "custom vm ID"}},)
def __init__(self):
Table.__init__(self, VM.__records)

View File

@@ -99,11 +99,9 @@ TESTSUITE_AT = \
tests/ovsdb-lock.at \
tests/ovsdb-rbac.at \
tests/ovs-vsctl.at \
tests/ovs-xapi-sync.at \
tests/pytest.at \
tests/stp.at \
tests/rstp.at \
tests/interface-reconfigure.at \
tests/vlog.at \
tests/vtep-ctl.at \
tests/auto-attach.at \
@@ -526,7 +524,6 @@ CHECK_PYFILES = \
tests/test-ovsdb.py \
tests/test-reconnect.py \
tests/test-stream.py \
tests/MockXenAPI.py \
tests/test-unix-socket.py \
tests/test-unixctl.py \
tests/test-vlog.py \

File diff suppressed because it is too large Load Diff

View File

@@ -1,74 +0,0 @@
AT_BANNER([ovs-xapi-sync])
AT_SETUP([ovs-xapi-sync])
# Mock up the XenAPI.
cp "$top_srcdir/tests/MockXenAPI.py" XenAPI.py
PYTHONPATH=`pwd`:$PYTHONPATH
export PYTHONPATH
cp "$top_srcdir/vswitchd/vswitch.ovsschema" .
cp "$top_srcdir/xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync" \
ovs-xapi-sync
on_exit 'kill `cat pid ovs-xapi-sync.pid`'
mkdir var var/run
touch var/run/xapi_init_complete.cookie
ovs_vsctl () {
ovs-vsctl --no-wait -vreconnect:emer "$@"
}
# Start ovsdb-server.
OVS_VSCTL_SETUP
# Start ovs-xapi-sync.
AT_CHECK([$PYTHON3 ./ovs-xapi-sync "--pidfile=ovs-xapi-sync.pid" \
"--root-prefix=`pwd`" unix:db.sock >log 2>&1 &])
AT_CAPTURE_FILE([log])
# Add bridges and check ovs-xapi-sync's work.
AT_CHECK([ovs_vsctl -- add-br xenbr0 -- add-br xenbr1])
OVS_WAIT_UNTIL([test "X`ovs_vsctl get bridge xenbr0 fail-mode`" != "X[[]]"])
AT_CHECK([ovs_vsctl \
-- get bridge xenbr0 fail-mode other-config external-ids \
-- get bridge xenbr1 fail-mode other-config external-ids], [0],
[[secure
{}
{bridge-id="custom bridge ID"}
secure
{disable-in-band="true"}
{}
]])
# Add vif and check daemon's work.
AT_CHECK([ovs_vsctl \
-- add-port xenbr0 vif1.0 \
-- set Interface vif1.0 'external-ids={attached-mac="00:11:22:33:44:55", xs-network-uuid="9b66c68b-a74e-4d34-89a5-20a8ab352d1e", xs-vif-uuid="6ab1b260-398e-49ba-827b-c7696108964c", xs-vm-uuid="fcb8a3f6-dc04-41d2-8b8a-55afd2b755b8"'}])
OVS_WAIT_UNTIL([ovs_vsctl get interface vif1.0 external-ids:iface-id >/dev/null 2>&1])
AT_CHECK([ovs_vsctl get interface vif1.0 external-ids], [0],
[{attached-mac="00:11:22:33:44:55", iface-id="custom iface ID", iface-status=active, vm-id="custom vm ID", xs-network-uuid="9b66c68b-a74e-4d34-89a5-20a8ab352d1e", xs-vif-uuid="6ab1b260-398e-49ba-827b-c7696108964c", xs-vm-uuid="fcb8a3f6-dc04-41d2-8b8a-55afd2b755b8"}
])
# Add corresponding tap and check daemon's work.
AT_CHECK([ovs_vsctl add-port xenbr0 tap1.0])
OVS_WAIT_UNTIL([ovs_vsctl get interface tap1.0 external-ids:iface-id >/dev/null 2>&1])
AT_CHECK([ovs_vsctl \
-- get interface vif1.0 external-ids \
-- get interface tap1.0 external-ids], [0],
[{attached-mac="00:11:22:33:44:55", iface-id="custom iface ID", iface-status=inactive, vm-id="custom vm ID", xs-network-uuid="9b66c68b-a74e-4d34-89a5-20a8ab352d1e", xs-vif-uuid="6ab1b260-398e-49ba-827b-c7696108964c", xs-vm-uuid="fcb8a3f6-dc04-41d2-8b8a-55afd2b755b8"}
{attached-mac="00:11:22:33:44:55", iface-id="custom iface ID", iface-status=active, vm-id="custom vm ID", xs-network-uuid="9b66c68b-a74e-4d34-89a5-20a8ab352d1e", xs-vif-uuid="6ab1b260-398e-49ba-827b-c7696108964c", xs-vm-uuid="fcb8a3f6-dc04-41d2-8b8a-55afd2b755b8"}
])
# Remove corresponding tap and check daemon's work.
AT_CHECK([ovs_vsctl del-port tap1.0])
OVS_WAIT_UNTIL([test `ovs_vsctl get interface vif1.0 external-ids:iface-status` = active])
AT_CHECK([ovs_vsctl get interface vif1.0 external-ids], [0],
[{attached-mac="00:11:22:33:44:55", iface-id="custom iface ID", iface-status=active, vm-id="custom vm ID", xs-network-uuid="9b66c68b-a74e-4d34-89a5-20a8ab352d1e", xs-vif-uuid="6ab1b260-398e-49ba-827b-c7696108964c", xs-vm-uuid="fcb8a3f6-dc04-41d2-8b8a-55afd2b755b8"}
])
OVSDB_SERVER_SHUTDOWN
AT_CLEANUP

View File

@@ -67,8 +67,6 @@ m4_include([tests/bridge.at])
m4_include([tests/netdev-type.at])
m4_include([tests/ovsdb.at])
m4_include([tests/ovs-vsctl.at])
m4_include([tests/ovs-xapi-sync.at])
m4_include([tests/interface-reconfigure.at])
m4_include([tests/stp.at])
m4_include([tests/rstp.at])
m4_include([tests/vlog.at])

View File

@@ -1205,3 +1205,21 @@ Datapath actions: push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),1
OVS_VSWITCHD_STOP
AT_CLEANUP
dnl This test configures two tunnels, then deletes the second and re-uses its
dnl name for different types of ports. This was introduced to detect errors
dnl where port configuration persists even when the port is deleted and
dnl readded.
AT_SETUP([tunnel - re-create port with different types])
OVS_VSWITCHD_START(
[add-port br0 p0 -- set int p0 type=gre options:remote_ip=127.0.0.1 -- \
add-port br0 p1 -- set int p1 type=dummy -- \
add-port br0 p2 -- set int p2 type=dummy])
AT_CHECK([ovs-vsctl set int p1 type=gre options:remote_ip=127.0.0.1])
AT_CHECK([ovs-vsctl del-port p1])
AT_CHECK([ovs-vsctl add-port br0 p1 -- set int p1 type=dummy])
OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
OVS_APP_EXIT_AND_WAIT([ovsdb-server])]
AT_CLEANUP

View File

@@ -8,9 +8,7 @@ vswitchd_ovs_vswitchd_SOURCES = \
vswitchd/bridge.h \
vswitchd/ovs-vswitchd.c \
vswitchd/system-stats.c \
vswitchd/system-stats.h \
vswitchd/xenserver.c \
vswitchd/xenserver.h
vswitchd/system-stats.h
vswitchd_ovs_vswitchd_LDADD = \
ofproto/libofproto.la \
lib/libsflow.la \

View File

@@ -70,7 +70,6 @@
#include "util.h"
#include "unixctl.h"
#include "lib/vswitch-idl.h"
#include "xenserver.h"
#include "vlan-bitmap.h"
VLOG_DEFINE_THIS_MODULE(bridge);
@@ -299,9 +298,7 @@ static void bridge_configure_remotes(struct bridge *,
static void bridge_pick_local_hw_addr(struct bridge *, struct eth_addr *ea,
struct iface **hw_addr_iface);
static uint64_t bridge_pick_datapath_id(struct bridge *,
const struct eth_addr bridge_ea,
struct iface *hw_addr_iface);
static uint64_t dpid_from_hash(const void *, size_t nbytes);
const struct eth_addr bridge_ea);
static bool bridge_has_bond_fake_iface(const struct bridge *,
const char *name);
static bool port_is_bond_fake_iface(const struct port *);
@@ -1329,7 +1326,7 @@ bridge_configure_datapath_id(struct bridge *br)
}
br->ea = ea;
dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface);
dpid = bridge_pick_datapath_id(br, ea);
if (dpid != ofproto_get_datapath_id(br->ofproto)) {
VLOG_INFO("bridge %s: using datapath ID %016"PRIx64, br->name, dpid);
ofproto_set_datapath_id(br->ofproto, dpid);
@@ -2362,14 +2359,10 @@ bridge_pick_local_hw_addr(struct bridge *br, struct eth_addr *ea,
}
/* Choose and returns the datapath ID for bridge 'br' given that the bridge
* Ethernet address is 'bridge_ea'. If 'bridge_ea' is the Ethernet address of
* an interface on 'br', then that interface must be passed in as
* 'hw_addr_iface'; if 'bridge_ea' was derived some other way, then
* 'hw_addr_iface' must be passed in as a null pointer. */
* Ethernet address is 'bridge_ea'. */
static uint64_t
bridge_pick_datapath_id(struct bridge *br,
const struct eth_addr bridge_ea,
struct iface *hw_addr_iface)
const struct eth_addr bridge_ea)
{
/*
* The procedure for choosing a bridge MAC address will, in the most
@@ -2391,46 +2384,9 @@ bridge_pick_datapath_id(struct bridge *br,
return dpid;
}
if (!hw_addr_iface) {
/*
* A purely internal bridge, that is, one that has no non-virtual
* network devices on it at all, is difficult because it has no
* natural unique identifier at all.
*
* When the host is a XenServer, we handle this case by hashing the
* host's UUID with the name of the bridge. Names of bridges are
* persistent across XenServer reboots, although they can be reused if
* an internal network is destroyed and then a new one is later
* created, so this is fairly effective.
*
* When the host is not a XenServer, we punt by using a random MAC
* address on each run.
*/
const char *host_uuid = xenserver_get_host_uuid();
if (host_uuid) {
char *combined = xasprintf("%s,%s", host_uuid, br->name);
dpid = dpid_from_hash(combined, strlen(combined));
free(combined);
return dpid;
}
}
return eth_addr_to_uint64(bridge_ea);
}
static uint64_t
dpid_from_hash(const void *data, size_t n)
{
union {
uint8_t bytes[SHA1_DIGEST_SIZE];
struct eth_addr ea;
} hash;
sha1_bytes(data, n, hash.bytes);
eth_addr_mark_random(&hash.ea);
return eth_addr_to_uint64(hash.ea);
}
static void
iface_refresh_netdev_status(struct iface *iface)
{

View File

@@ -1,79 +0,0 @@
/* Copyright (c) 2009, 2010, 2013 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.
*/
#include <config.h>
#include "xenserver.h"
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "openvswitch/dynamic-string.h"
#include "process.h"
#include "util.h"
#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(xenserver);
/* If running on a XenServer, the XenServer host UUID as a 36-character string,
* otherwise null. */
static char *host_uuid;
static void
read_host_uuid(void)
{
static const char filename[] = "/etc/xensource-inventory";
char line[128];
FILE *file;
file = fopen(filename, "r");
if (!file) {
if (errno == ENOENT) {
VLOG_DBG("not running on a XenServer");
} else {
VLOG_INFO("%s: open: %s", filename, ovs_strerror(errno));
}
return;
}
while (fgets(line, sizeof line, file)) {
static const char leader[] = "INSTALLATION_UUID='";
const int leader_len = strlen(leader);
const int uuid_len = 36;
static const char trailer[] = "'\n";
const int trailer_len = strlen(trailer);
if (strlen(line) == leader_len + uuid_len + trailer_len
&& !memcmp(line, leader, leader_len)
&& !memcmp(line + leader_len + uuid_len, trailer, trailer_len)) {
host_uuid = xmemdup0(line + leader_len, uuid_len);
VLOG_INFO("running on XenServer, host-uuid %s", host_uuid);
fclose(file);
return;
}
}
fclose(file);
VLOG_ERR("%s: INSTALLATION_UUID not found", filename);
}
const char *
xenserver_get_host_uuid(void)
{
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, read_host_uuid);
return host_uuid;
}

View File

@@ -1,21 +0,0 @@
/* Copyright (c) 2009 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.
*/
#ifndef VSWITCHD_XENSERVER_H
#define VSWITCHD_XENSERVER_H 1
const char *xenserver_get_host_uuid(void);
#endif /* xenserver.h */

View File

@@ -1 +0,0 @@
/openvswitch-xen.spec

View File

@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,518 +0,0 @@
As a special exception to the GNU Lesser General Public License, you
may link, statically or dynamically, a "work that uses the Library"
with a publicly distributed version of the Library to produce an
executable file containing portions of the Library, and distribute
that executable file under terms of your choice, without any of the
additional requirements listed in clause 6 of the GNU Lesser General
Public License. By "a publicly distributed version of the Library",
we mean either the unmodified Library as distributed, or a
modified version of the Library that is distributed under the
conditions defined in clause 3 of the GNU Library General Public
License. This exception does not however invalidate any other reasons
why the executable file might be covered by the GNU Lesser General
Public License.
------------
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -1,175 +0,0 @@
..
Copyright (C) 2009, 2010, 2011 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.
Convention for heading levels in Open vSwitch 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.
================
XenServer README
================
This directory contains files for seamless integration of Open vSwitch on
Citrix XenServer hosts managed by the Citrix management tools.
Files in this directory are licensed on a file-by-file basis. Refer to each
file for details.
Most of the files in this directory are installed on a XenServer system under
the same name; underscores are replaced by slashes. The files are:
etc_init.d_openvswitch
Initializes Open vSwitch at boot and shuts it down at shutdown.
etc_init.d_openvswitch-xapi-update
Init script to ensure openvswitch-cfg-update is called for the current host
at boot.
etc_logrotate.d_openvswitch
Ensures that logs in /var/log/openvswitch are rotated periodically and that
appropriate daemons reopen their log files at that point.
etc_profile.d_openvswitch.sh
Open vSwitch-related shell functions for the administrator's convenience.
etc_xapi.d_plugins_openvswitch-cfg-update
xapi plugin script to update the cache of configuration items in the
ovs-vswitchd configuration that are managed in the xapi database when
integrated with Citrix management tools.
etc_xensource_scripts_vif
Open vSwitch-aware replacement for Citrix script of the same name.
openvswitch-xen.spec
spec file for building RPMs to install on a XenServer host.
opt_xensource_libexec_interface-reconfigure
Open vSwitch-aware replacements for Citrix script of the same names.
opt_xensource_libexec_InterfaceReconfigureBridge.py
See above.
opt_xensource_libexec_InterfaceReconfigure.py
See above.
opt_xensource_libexec_InterfaceReconfigureVswitch.py
See above.
usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py
xsconsole plugin to configure the pool-wide configuration keys used to
control Open vSwitch when integrated with Citrix management tools.
usr_share_openvswitch_scripts_ovs-xapi-sync
Daemon to monitor the external_ids columns of the Bridge and Interface OVSDB
tables for changes that require interrogating XAPI.
usr_share_openvswitch_scripts_sysconfig.template
Template for Open vSwitch's /etc/sysconfig/openvswitch configuration file.
Open vSwitch installs a number of xen-bugtool extensions in
``/etc/xensource/bugtool`` to gather additional information useful for
debugging. The sources for the extensions are in
``../utilities/bugtool/plugins``:
kernel-info/openvswitch.xml
Collect kernel information relevant to Open vSwitch, such as slabinfo.
network-status/openvswitch.xml
Collect networking information relevant to Open vSwitch. Runs the following
scripts, which are described below:
* ovs-bugtool-bfd-show
* ovs-bugtool-cfm-show
* ovs-bugtool-fdb-show
* ovs-bugtool-lacp-show
* ovs-bugtool-list-dbs
* ovs-bugtool-ovsdb-dump
* ovs-bugtool-tc-class-show
* ovs-bugtool-bond-show
* ovs-bugtool-ovs-ofctl-show
* ovs-bugtool-ovs-ofctl-dump-flows
* ovs-bugtool-ovs-appctl-dpif
* ovs-bugtool-coverage-show
* ovs-bugtool-memory-show
* ovs-bugtool-vsctl-show
* ovs-bugtool-conntrack-dump
system-configuration/openvswitch.xml
Collect system configuration information relevant to Open vSwitch, including
timezone. Runs the following script which is described below:
* ovs-bugtool-daemons-ver
system-configuration.xml
Collect system configuration data. This category is configured to collect up
to 1Mb of data, take up to 60 seconds to collect data, run every time and is
hidden from display in XenCenter.
A number of scripts are installed in ``/usr/share/openvswitch/scripts`` to
assist Open vSwitch's xen-bugtool extensions. The sources for the scripts are
located in ``../utilities/bugtool``:
ovs-bugtool-bfd-show
Script to dump detailed BFD information for all enabled interfaces.
ovs-bugtool-cfm-show
Script to dump detailed CFM information for all enabled interfaces.
ovs-bugtool-fdb-show
Script to collect a summary of learned MACs for each bridge.
ovs-bugtool-lacp-show
Script to dump detailed LACP information for all enabled ports.
ovs-bugtool-list-dbs
Script to list the databases controlled by ovsdb-server.
ovs-bugtool-ovsdb-dump
Script to dump contents of Open vSwitch configuration database in
comma-separated value format.
ovs-bugtool-tc-class-show
Script to dump tc class configuration for all network interfaces.
ovs-bugtool-ovs-ofctl-show
Script to dump information about flow tables and ports of each bridge.
ovs-bugtool-ovs-ofctl-dump-flows
Script to dump openflow flows of each bridge.
ovs-bugtool-ovs-appctl-dpif
Script to collect a summary of configured datapaths and datapath flows.
ovs-bugtool-coverage-show
Script to count the number of times particular events occur during
ovs-vswitchd's runtime.
ovs-bugtool-memory-show
Script to show some basic statistics about ovs-vswitchd's memory usage.
ovs-bugtool-vsctl-show
Script to show a brief overview of the database contents.
ovs-bugtool-conntrack-dump
Script to show all the connection entries in the tracker.
ovs-bugtool-daemons-ver
Script to dump version information for all Open vSwitch daemons.

View File

@@ -1,35 +0,0 @@
# Copyright (C) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without warranty of any kind.
EXTRA_DIST += \
xenserver/GPLv2 \
xenserver/LICENSE \
xenserver/README.rst \
xenserver/automake.mk \
xenserver/etc_init.d_openvswitch \
xenserver/etc_init.d_openvswitch-xapi-update \
xenserver/etc_logrotate.d_openvswitch \
xenserver/etc_profile.d_openvswitch.sh \
xenserver/etc_xapi.d_plugins_openvswitch-cfg-update \
xenserver/etc_xensource_scripts_vif \
xenserver/openvswitch-xen.spec \
xenserver/openvswitch-xen.spec.in \
xenserver/opt_xensource_libexec_InterfaceReconfigure.py \
xenserver/opt_xensource_libexec_InterfaceReconfigureBridge.py \
xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py \
xenserver/opt_xensource_libexec_interface-reconfigure \
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync \
xenserver/usr_share_openvswitch_scripts_sysconfig.template
FLAKE8_PYFILES += \
xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync
$(srcdir)/xenserver/openvswitch-xen.spec: xenserver/openvswitch-xen.spec.in $(top_builddir)/config.status
$(AM_V_GEN)($(ro_shell) && sed -e 's,[@]VERSION[@],$(VERSION),g') \
< $(srcdir)/xenserver/$(@F).in > $(@F).tmp || exit 1; \
if cmp -s $(@F).tmp $@; then touch $@; rm $(@F).tmp; else mv $(@F).tmp $@; fi

View File

@@ -1,154 +0,0 @@
#!/bin/sh
#
# openvswitch
#
# chkconfig: 2345 09 91
# description: Manage Open vSwitch kernel modules and user-space daemons
# Copyright (C) 2009, 2010, 2011 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.
### BEGIN INIT INFO
# Provides: openvswitch-switch
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Open vSwitch switch
### END INIT INFO
. /usr/share/openvswitch/scripts/ovs-lib || exit 1
. /etc/xensource-inventory
test -e /etc/sysconfig/openvswitch && . /etc/sysconfig/openvswitch
case `cat /etc/xensource/network.conf` in
vswitch|openvswitch)
;;
bridge)
exit 0
;;
*)
echo "Open vSwitch disabled (/etc/xensource/network.conf is invalid)" >&2
exit 0
;;
esac
start_ovs_xapi_sync () {
if daemon_is_running ovs-xapi-sync; then
log_success_msg "ovs-xapi-sync is already running"
else
PYTHONPATH=/usr/share/openvswitch/python \
/usr/share/openvswitch/scripts/ovs-xapi-sync \
--log-file --pidfile --detach --monitor unix:/var/run/openvswitch/db.sock
fi
}
start () {
set ovs_ctl ${1-start}
set "$@" --system-id="$INSTALLATION_UUID"
set "$@" --system-type="$PRODUCT_BRAND"
set "$@" --system-version="$PRODUCT_VERSION-$BUILD_NUMBER"
set "$@" --external-id=xs-system-uuid="$INSTALLATION_UUID"
set "$@" --daemon-cwd=/var/xen/openvswitch
if test X"$FORCE_COREFILES" != X; then
set "$@" --force-corefiles="$FORCE_COREFILES"
fi
if test X"$OVSDB_SERVER_PRIORITY" != X; then
set "$@" --ovsdb-server-priority="$OVSDB_SERVER_PRIORITY"
fi
if test X"$VSWITCHD_PRIORITY" != X; then
set "$@" --ovs-vswitchd-priority="$VSWITCHD_PRIORITY"
fi
if test X"$VSWITCHD_MLOCKALL" != X; then
set "$@" --mlockall="$VSWITCHD_MLOCKALL"
fi
if test ! -e /var/run/openvswitch.booted; then
touch /var/run/openvswitch.booted
set "$@" --delete-bridges
fi
set "$@" $OVS_CTL_OPTS
"$@"
start_ovs_xapi_sync
ovs_ctl --protocol=gre enable-protocol
touch /var/lock/subsys/openvswitch
}
force_reload_kmod () {
start force-reload-kmod
# Restart the high-availability daemon if it is running. Otherwise
# it loses its heartbeat and reboots the system after a few minutes.
if pidof xhad >/dev/null && test -e /etc/xensource/xhad.conf; then
PATH=$PATH:/opt/xensource/xha
action "Stopping HA daemon" ha_stop_daemon
action "Starting HA daemon" ha_start_daemon
fi
action "Stopping ovs-xapi-sync" stop_daemon ovs-xapi-sync
action "Starting ovs-xapi-sync" start_ovs_xapi_sync
}
stop () {
ovs_ctl stop
stop_daemon ovs-xapi-sync
rm -f /var/lock/subsys/openvswitch
}
restart () {
if [ "$1" = "--save-flows=yes" ]; then
stop_daemon ovs-xapi-sync
start restart
else
stop
start
fi
}
case $1 in
start)
start
;;
stop)
stop
;;
restart)
shift
restart "$@"
;;
reload|force-reload)
# The main OVS daemons keep up-to-date, but ovs-xapi-sync needs help.
if daemon_is_running ovs-xapi-sync; then
action "Configuring Open vSwitch external IDs" \
ovs-appctl -t ovs-xapi-sync flush-cache
fi
;;
status)
ovs_ctl status && daemon_status ovs-xapi-sync
;;
version)
ovs_ctl version
;;
force-reload-kmod)
force_reload_kmod
;;
help)
printf "openvswitch [start|stop|restart|reload|force-reload|status|version]\n"
;;
*)
printf "Unknown command: $1\n"
exit 1
;;
esac

View File

@@ -1,80 +0,0 @@
#!/bin/bash
#
# openvswitch-xapi-update
#
# chkconfig: 2345 95 01
# description: Update Open vSwitch configuration from XAPI database at boot
# Copyright (C) 2009, 2010 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.
### BEGIN INIT INFO
# Provides: openvswitch-xapi-update
# Required-Start: $network $remote_fs
# Required-Stop: $network
# Default-Start: 3 5
# Default-Stop:
# Short-Description: openvswitch-xapi-update
# Description: reconfigures Open vSwitch based on XAPI configuration
### END INIT INFO
. /etc/init.d/functions
function do_host_call {
xe host-call-plugin host-uuid="$INSTALLATION_UUID" plugin="openvswitch-cfg-update" fn="update" >/dev/null
}
function start {
if [ ! -f /etc/xensource-inventory ]; then
printf "openvswitch-xapi-update ERROR: XenSource inventory not present in /etc/xensource-inventory\n"
exit 1
fi
if test -e /etc/xensource/network.conf; then
NETWORK_MODE=$(cat /etc/xensource/network.conf)
fi
case ${NETWORK_MODE:=openvswitch} in
vswitch|openvswitch)
;;
bridge)
exit 0
;;
*)
echo "Open vSwitch disabled (/etc/xensource/network.conf is invalid)" >&2
exit 0
;;
esac
source /etc/xensource-inventory
action "Updating configuration" do_host_call
}
case "$1" in
start)
start
;;
stop)
# Nothing to do here.
;;
restart)
start
;;
help)
printf "openvswitch-xapi-update [start|stop|restart]\n"
;;
*)
printf "Unknown command: $1\n"
exit 1
;;
esac

View File

@@ -1,21 +0,0 @@
# Copyright (C) 2009, 2010, 2011, 2012, 2017 Nicira, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without warranty of any kind.
/var/log/openvswitch/*.log {
daily
compress
sharedscripts
missingok
postrotate
# Tell Open vSwitch daemons to reopen their log files
if [ -d /var/run/openvswitch ]; then
for pidfile in `cd /var/run/openvswitch && echo *.pid`; do
ovs-appctl -t "${pidfile%%.pid}" vlog/reopen 2>/dev/null || :
done
fi
endscript
}

View File

@@ -1,48 +0,0 @@
# Copyright (C) 2009, 2010, 2011 Nicira, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without warranty of any kind.
alias vswitch='service openvswitch'
alias openvswitch='service openvswitch'
function watchdp {
watch ovs-dpctl show "$@"
}
function watchdpflows {
local grep=""
local dp=$1
shift
if [ $# -gt 0 ]; then
grep="| grep $@"
fi
watch "ovs-dpctl dump-flows $dp $grep"
}
function watchflows {
local grep=""
local dp=$1
shift
bridge=$(ovs-dpctl show $dp | grep 'port 0:' | cut -d' ' -f 3)
if [ $# -gt 0 ]; then
grep="| grep $@"
fi
watch "ovs-ofctl dump-flows unix:/var/run/$bridge.mgmt $grep"
}
function monitorlogs {
local grep=""
if [ $# -gt 0 ]; then
grep="| grep --line-buffered '^==> .* <==$"
for i in "$@"; do
grep="$grep\|$i"
done
grep="$grep'"
fi
cmd="tail -F /var/log/messages /var/log/openvswitch/ovs-vswitchd.log /var/log/openvswitch/ovsdb-server /var/log/xensource.log $grep | tee /var/log/monitorlogs.out"
printf "cmd: $cmd\n"
eval "$cmd"
}

View File

@@ -1,269 +0,0 @@
#!/usr/bin/env python3
#
# xapi plugin script to update the cache of configuration items in the
# ovs-vswitchd configuration that are managed in the xapi database when
# integrated with Citrix management tools.
# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2020 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.
# TBD: - error handling needs to be improved. Currently this can leave
# TBD: the system in a bad state if anything goes wrong.
import XenAPIPlugin
import os
import subprocess
import syslog
import re
vsctl = '/usr/bin/ovs-vsctl'
ofctl = '/usr/bin/ovs-ofctl'
cacert_filename = '/etc/openvswitch/vswitchd.cacert'
ovsdb_port = '6640'
# Delete the CA certificate, so that we go back to boot-strapping mode
def delete_cacert():
try:
os.remove(cacert_filename)
except OSError:
# Ignore error if file doesn't exist
pass
def update(session, args):
# Refresh bridge network UUIDs in case this host joined or left a pool.
script = '/opt/xensource/libexec/interface-reconfigure'
try:
retval = subprocess.call([script, 'rewrite'])
if retval != 0:
syslog.syslog('%s exited with status %d' % (script, retval))
except OSError, e:
syslog.syslog('%s: failed to execute (%s)' % (script, e.strerror))
pools = session.xenapi.pool.get_all()
# We assume there is only ever one pool...
if len(pools) == 0:
raise XenAPIPlugin.Failure('NO_POOL_FOR_HOST', [])
if len(pools) > 1:
raise XenAPIPlugin.Failure('MORE_THAN_ONE_POOL_FOR_HOST', [])
new_controller = False
pool = session.xenapi.pool.get_record(pools[0])
controller = pool.get('vswitch_controller')
ret_str = ''
currentControllers = vswitchCurrentControllers()
if not controller and currentControllers:
delete_cacert()
try:
emergency_reset(session, None)
except:
pass
removeControllerCfg()
ret_str += 'Successfully removed controller config. '
# controller cannot be empty, otherwise, this will always be True.
elif controller and controller not in currentControllers:
delete_cacert()
try:
emergency_reset(session, None)
except:
pass
setControllerCfg(controller)
new_controller = True
ret_str += 'Successfully set controller to %s. ' % controller
try:
pool_fail_mode = pool['other_config']['vswitch-controller-fail-mode']
except KeyError, e:
pool_fail_mode = None
bton = {}
for rec in session.xenapi.network.get_all_records().values():
try:
bton[rec['bridge']] = rec
except KeyError:
pass
# If new controller, get management MAC addresses from XAPI now
# in case fail_mode set to secure which may affect XAPI access
mgmt_bridge = None
host_mgmt_mac = None
host_mgmt_device = None
pool_mgmt_macs = {}
if new_controller:
query = 'field "management"="true"'
recs = session.xenapi.PIF.get_all_records_where(query)
for rec in recs.itervalues():
pool_mgmt_macs[rec.get('MAC')] = rec.get('device')
dib_changed = False
fail_mode_changed = False
for bridge in vswitchCfgQuery(['list-br']).split():
network = bton[bridge]
bridge = vswitchCfgQuery(['br-to-parent', bridge])
xapi_dib = network['other_config'].get('vswitch-disable-in-band')
if not xapi_dib:
xapi_dib = ''
ovs_dib = vswitchCfgQuery(['--', '--if-exists', 'get', 'Bridge',
bridge,
'other_config:disable-in-band']).strip('"')
# Do nothing if setting is invalid, and warn the user.
if xapi_dib not in ['true', 'false', '']:
ret_str += '"' + xapi_dib + '"' + \
' is an invalid value for vswitch-disable-in-band on ' + \
bridge + ' '
# Change bridge disable-in-band option if XAPI and OVS states differ.
elif xapi_dib != ovs_dib:
# 'true' or 'false'
if xapi_dib:
vswitchCfgMod(['--', 'set', 'Bridge', bridge,
'other_config:disable-in-band=' + xapi_dib])
# '' or None
else:
vswitchCfgMod(['--', 'remove', 'Bridge', bridge,
'other_config', 'disable-in-band'])
dib_changed = True
# Change bridge fail_mode if XAPI state differs from OVS state.
bridge_fail_mode = vswitchCfgQuery(['get', 'Bridge',
bridge, 'fail_mode']).strip('[]"')
try:
other_config = bton[bridge]['other_config']
fail_mode = other_config['vswitch-controller-fail-mode']
except KeyError, e:
fail_mode = None
if fail_mode not in ['secure', 'standalone']:
fail_mode = pool_fail_mode
if fail_mode != 'secure':
fail_mode = 'standalone'
if bridge_fail_mode != fail_mode:
vswitchCfgMod(['--', 'set', 'Bridge', bridge,
'fail_mode=%s' % fail_mode])
fail_mode_changed = True
# Determine local mgmt MAC address if host being added to secure
# pool so we can add default flows to allow management traffic
if new_controller and fail_mode_changed and pool_fail_mode == 'secure':
oc = vswitchCfgQuery(['get', 'Bridge', bridge, 'other-config'])
m = re.match('.*hwaddr="([0-9a-fA-F:].*)".*', oc)
if m and m.group(1) in pool_mgmt_macs.keys():
mgmt_bridge = bridge
host_mgmt_mac = m.group(1)
host_mgmt_device = pool_mgmt_macs[host_mgmt_mac]
if (host_mgmt_mac is not None and mgmt_bridge is not None and
host_mgmt_device is not None):
tp = 'idle_timeout=0,priority=0'
port = vswitchCfgQuery(['get', 'interface', host_mgmt_device,
'ofport'])
addFlow(mgmt_bridge, '%s,in_port=%s,arp,nw_proto=1,actions=local' %
(tp, port))
addFlow(mgmt_bridge, '%s,in_port=local,arp,dl_src=%s,actions=%s' %
(tp, host_mgmt_mac, port))
addFlow(mgmt_bridge, '%s,in_port=%s,dl_dst=%s,actions=local' %
(tp, port, host_mgmt_mac))
addFlow(mgmt_bridge, '%s,in_port=local,dl_src=%s,actions=%s' %
(tp, host_mgmt_mac, port))
if dib_changed:
ret_str += 'Updated in-band management. '
if fail_mode_changed:
ret_str += 'Updated fail_mode. '
if ret_str != '':
return ret_str
else:
return 'No change to configuration'
def vswitchCurrentControllers():
controllers = vswitchCfgQuery(['get-manager'])
def parse_controller(controller):
if controller.startswith('ssl:'):
return controller.split(':')[1]
return controller.split(':')[0]
return [parse_controller(controller)
for controller in controllers.split('\n')
if controller]
def removeControllerCfg():
vswitchCfgMod(['--', 'del-manager',
'--', 'del-ssl'])
def setControllerCfg(controller):
# /etc/xensource/xapi-ssl.pem is mentioned twice below because it
# contains both the private key and the certificate.
vswitchCfgMod(['--', 'del-manager',
'--', 'del-ssl',
'--', '--bootstrap', 'set-ssl',
'/etc/xensource/xapi-ssl.pem',
'/etc/xensource/xapi-ssl.pem',
cacert_filename,
'--', 'set-manager', 'ssl:' + controller + ':' + ovsdb_port])
def vswitchCfgQuery(action_args):
cmd = [vsctl, '-vconsole:off'] + action_args
output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()
if len(output) == 0 or output[0] is None:
output = ''
else:
output = output[0].strip()
return output
def vswitchCfgMod(action_args):
cmd = [vsctl, '--timeout=5', '-vconsole:off'] + action_args
exitcode = subprocess.call(cmd)
if exitcode != 0:
raise XenAPIPlugin.Failure('VSWITCH_CONFIG_MOD_FAILURE',
[str(exitcode), str(action_args)])
def emergency_reset(session, args):
cmd = [vsctl, '--timeout=5', 'emer-reset']
exitcode = subprocess.call(cmd)
if exitcode != 0:
raise XenAPIPlugin.Failure('VSWITCH_EMER_RESET_FAILURE',
[str(exitcode)])
return 'Successfully reset configuration'
def addFlow(switch, flow):
cmd = [ofctl, 'add-flow', switch, flow]
exitcode = subprocess.call(cmd)
if exitcode != 0:
raise XenAPIPlugin.Failure('VSWITCH_ADD_FLOW_FAILURE',
[str(exitcode), str(switch), str(flow)])
if __name__ == '__main__':
XenAPIPlugin.dispatch({'update': update,
'emergency_reset': emergency_reset})

View File

@@ -1,265 +0,0 @@
#!/bin/sh
# Copyright (C) 2008,2009 Citrix Systems, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; version 2.1 only. with the special
# exception on linking described in file LICENSE.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# CA-23900: Warning: when VIFs are added to windows guests with PV drivers the backend vif device is registered,
# unregistered and then registered again. This causes the udev event to fire twice and this script runs twice.
# Since the first invocation of the script races with the device unregistration, spurious errors are possible
# which will be logged but are safe to ignore since the second script invocation should complete the operation.
# Note that each script invocation is run synchronously from udev and so the scripts don't race with each other.
# Keep other-config/ keys in sync with device.ml:vif_udev_keys
BRCTL="/usr/sbin/brctl"
IP="/sbin/ip"
vsctl="/usr/bin/ovs-vsctl"
handle_promiscuous()
{
local arg=$(xenstore-read "${PRIVATE}/other-config/promiscuous" 2>/dev/null)
if [ $? -eq 0 -a -n "${arg}" ] ; then
case $NETWORK_MODE in
bridge)
case "${arg}" in
true|on) echo 1 > /sys/class/net/${dev}/brport/promisc ;;
*) echo 0 > /sys/class/net/${dev}/brport/promisc ;;
esac
;;
openvswitch)
logger -t script-vif "${dev}: Promiscuous ports are not supported via Open vSwitch."
;;
esac
fi
}
handle_ethtool()
{
local opt=$1
local arg=$(xenstore-read "${PRIVATE}/other-config/ethtool-${opt}" 2>/dev/null)
if [ $? -eq 0 -a -n "${arg}" ] ; then
case "${arg}" in
true|on) /sbin/ethtool -K "${dev}" "${opt}" on ;;
false|off) /sbin/ethtool -K "${dev}" "${opt}" off ;;
*) logger -t scripts-vif "Unknown ethtool argument ${opt}=${arg} on ${dev}/${VIFUUID}" ;;
esac
fi
}
handle_mtu()
{
local mtu=$(xenstore-read "${PRIVATE}/MTU" 2>/dev/null)
if [ $? -eq 0 -a -n "${mtu}" ]; then
logger -t scripts-vif "Setting ${dev} MTU ${mtu}"
${IP} link set "${dev}" mtu ${mtu} || logger -t scripts-vif "Failed to ip link set ${dev} mtu ${mtu}. Error code $?"
fi
}
set_vif_external_id()
{
local key=$1
local value=$2
logger -t scripts-vif "vif${DOMID}.${DEVID} external-ids:\"${key}\"=\"${value}\""
echo "-- set interface vif${DOMID}.${DEVID} external-ids:\"${key}\"=\"${value}\""
}
handle_vswitch_vif_details()
{
local vm=$(xenstore-read "/local/domain/$DOMID/vm" 2>/dev/null)
if [ $? -eq 0 -a -n "${vm}" ] ; then
local vm_uuid=$(xenstore-read "$vm/uuid" 2>/dev/null)
fi
if [ -n "${vm_uuid}" ] ; then
set_vif_external_id "xs-vm-uuid" "${vm_uuid}"
fi
local vif_uuid=$(xenstore-read "${PRIVATE}/vif-uuid" 2>/dev/null)
if [ -n "${vif_uuid}" ] ; then
set_vif_external_id "xs-vif-uuid" "${vif_uuid}"
fi
local vif_details=
local net_uuid=$(xenstore-read "${PRIVATE}/network-uuid" 2>/dev/null)
if [ -n "${net_uuid}" ] ; then
set_vif_external_id "xs-network-uuid" "${net_uuid}"
fi
local address=$(xenstore-read "/local/domain/$DOMID/device/vif/$DEVID/mac" 2>/dev/null)
if [ -n "${address}" ] ; then
set_vif_external_id "attached-mac" "${address}"
fi
}
add_to_bridge()
{
local address=$(xenstore-read "${PRIVATE}/bridge-MAC")
if [ $? -ne 0 -o -z "${address}" ]; then
logger -t scripts-vif "Failed to read ${PRIVATE}/bridge-MAC from xenstore"
exit 1
fi
local bridge=$(xenstore-read "${PRIVATE}/bridge")
if [ $? -ne 0 -o -z "${bridge}" ]; then
logger -t scripts-vif "Failed to read ${PRIVATE}/bridge from xenstore"
exit 1
fi
logger -t scripts-vif "Adding ${dev} to ${bridge} with address ${address}"
${IP} link set "${dev}" down || logger -t scripts-vif "Failed to ip link set ${dev} down"
${IP} link set "${dev}" arp off || logger -t scripts-vif "Failed to ip link set ${dev} arp off"
${IP} link set "${dev}" multicast off || logger -t scripts-vif "Failed to ip link set ${dev} multicast off"
${IP} link set "${dev}" address "${address}" || logger -t scripts-vif "Failed to ip link set ${dev} address ${address}"
${IP} addr flush "${dev}" || logger -t scripts-vif "Failed to ip addr flush ${dev}"
case $NETWORK_MODE in
bridge)
${BRCTL} setfd "${bridge}" 0 || logger -t scripts-vif "Failed to brctl setfd ${bridge} 0"
${BRCTL} addif "${bridge}" "${dev}" || logger -t scripts-vif "Failed to brctl addif ${bridge} ${dev}"
;;
openvswitch)
if [ "$TYPE" = "vif" ] ; then
local vif_details=$(handle_vswitch_vif_details $bridge)
fi
$vsctl --timeout=30 -- --if-exists del-port $dev -- add-port $bridge $dev $vif_details
;;
esac
${IP} link set "${dev}" up || logger -t scripts-vif "Failed to ip link set ${dev} up"
}
remove_from_bridge()
{
case $NETWORK_MODE in
bridge)
# Nothing to do
;;
openvswitch)
$vsctl --timeout=30 -- del-port $dev
;;
esac
}
call_hook_script() {
local domid=$1
local action=$2
# Call the VIF hotplug hook if present
if [ -x /etc/xapi.d/vif-hotplug ]; then
local vm=$(xenstore-read "/local/domain/$domid/vm" 2>/dev/null)
if [ $? -eq 0 -a -n "${vm}" ] ; then
local vm_uuid=$(xenstore-read "$vm/uuid" 2>/dev/null)
fi
if [ -n "${vm_uuid}" ] ; then
logger -t scripts-vif "VM UUID ${vm_uuid}"
fi
local vif_uuid=$(xenstore-read "${PRIVATE}/vif-uuid" 2>/dev/null)
if [ -n "${vif_uuid}" ] ; then
logger -t scripts-vif "VIF UUID ${vif_uuid}"
fi
if [ -n "${vif_uuid}" -a -n "${vm_uuid}" ] ; then
logger -t scripts-vif "Calling VIF hotplug hook for VM ${vm_uuid}, VIF ${vif_uuid}"
/etc/xapi.d/vif-hotplug -action "${action}" -vifuuid "${vif_uuid}" -vmuuid "${vm_uuid}"
fi
fi
}
NETWORK_MODE=$(cat /etc/xensource/network.conf)
ACTION=$1
# Older versions of XenServer do not pass in the type as an argument
if [[ $# -lt 2 ]]; then
TYPE=vif
else
TYPE=$2
fi
case $NETWORK_MODE in
bridge|openvswitch) ;;
vswitch) NETWORK_MODE=openvswitch ;;
*)
logger -t scripts-vif "Unknown network mode $NETWORK_MODE"
exit 1
;;
esac
case ${TYPE} in
vif)
if [ -z ${XENBUS_PATH} ]; then
DOMID=$3
DEVID=$4
else
DOMID=`echo ${XENBUS_PATH} | cut -f 3 -d '/'`
DEVID=`echo ${XENBUS_PATH} | cut -f 4 -d '/'`
fi
dev=vif${DOMID}.${DEVID}
;;
tap)
dev=$INTERFACE
DOMID=`echo ${dev#tap} | cut -f 1 -d '.'`
DEVID=`echo ${dev#tap} | cut -f 2 -d '.'`
;;
*)
logger -t scripts-vif "unknown interface type ${TYPE}"
exit 1
;;
esac
XAPI=/xapi/${DOMID}/hotplug/vif/${DEVID}
HOTPLUG=/xapi/${DOMID}/hotplug/vif/${DEVID}
PRIVATE=/xapi/${DOMID}/private/vif/${DEVID}
logger -t scripts-vif "Called as \"$@\" domid:$DOMID devid:$DEVID mode:$NETWORK_MODE"
case "${ACTION}" in
online)
if [ "${TYPE}" = "vif" ] ; then
handle_ethtool rx
handle_ethtool tx
handle_ethtool sg
handle_ethtool tso
handle_ethtool ufo
handle_ethtool gso
handle_mtu
add_to_bridge
handle_promiscuous
xenstore-write "${HOTPLUG}/vif" "${dev}"
xenstore-write "${HOTPLUG}/hotplug" "online"
# xs-xen.pq.hq:91e986b8e49f netback-wait-for-hotplug
xenstore-write "/local/domain/0/backend/vif/${DOMID}/${DEVID}/hotplug-status" "connected"
call_hook_script $DOMID "${ACTION}"
fi
;;
add)
if [ "${TYPE}" = "tap" ] ; then
add_to_bridge
fi
;;
remove)
if [ "${TYPE}" = "vif" ] ;then
xenstore-rm "${HOTPLUG}/hotplug"
call_hook_script $DOMID "${ACTION}"
fi
logger -t scripts-vif "${dev} has been removed"
remove_from_bridge
;;
move)
if [ "${TYPE}" = "vif" ] ;then
add_to_bridge
fi
esac

View File

@@ -1,512 +0,0 @@
# Spec file for Open vSwitch.
# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without warranty of any kind.
# For XenServer version < 6.5, when building, the rpmbuild command line
# should define openvswitch_version, kernel_name, kernel_version and
# kernel_flavor using -D arguments.
# for example:
#
# rpmbuild -D "openvswitch_version 1.1.0+build123"
# -D "kernel_name NAME-xen"
# -D "kernel_version 2.6.32.12-0.7.1.xs5.6.100.323.170596"
# -D "kernel_flavor xen"
# -bb /usr/src/redhat/SPECS/openvswitch-xen.spec
#
# For XenServer version >= 6.5, use kernel_uname which should be
# the `uname -r` output.
# for example:
#
# rpmbuild -D "openvswitch_version 2.3.0+build123"
# -D "kernel_uname 3.10.0+2"
# -bb /usr/src/redhat/SPECS/openvswitch-xen.spec
#
# If tests have to be skipped while building, specify the '--without check'
# option. For example:
# rpmbuild -bb --without check xenserver/openvswitch-xen.spec
%if %{?openvswitch_version:0}%{!?openvswitch_version:1}
%define openvswitch_version @VERSION@
%endif
%if %{?kernel_uname:1}%{!?kernel_uname:0}
%define kernel_name kernel
%define kernel_version %{kernel_uname}
%endif
%if %{?kernel_name:0}%{!?kernel_name:1}
%define kernel %(rpm -qa 'kernel*xen-devel' | head -1)
%define kernel_name %(rpm -q --queryformat "%%{Name}" %{kernel} | sed 's/-devel//' | sed 's/kernel-//')
%define kernel_version %(rpm -q --queryformat "%%{Version}-%%{Release}" %{kernel})
%define kernel_flavor xen
%endif
%if %{?xen_version:0}%{!?xen_version:1}
%define xen_version %{kernel_version}%{?kernel_flavor:%{kernel_flavor}}
%endif
# bump this when breaking compatibility with userspace
%define module_abi_version 0
# build-supplemental-pack.sh requires this naming for kernel module packages
%define module_package modules%{?kernel_flavor:-%{kernel_flavor}}-%{kernel_version}
%bcond_without check
Name: openvswitch
Summary: Open vSwitch daemon/database/utilities
Group: System Environment/Daemons
URL: http://www.openvswitch.org/
Vendor: Nicira, Inc.
Version: %{openvswitch_version}
License: ASL 2.0
Release: 1
Source: openvswitch-%{openvswitch_version}.tar.gz
Buildroot: /tmp/openvswitch-xen-rpm
Requires: openvswitch.ko.%{module_abi_version}
%description
Open vSwitch provides standard network bridging functions augmented with
support for the OpenFlow protocol for remote per-flow control of
traffic.
%package %{module_package}
Summary: Open vSwitch kernel module
Group: System Environment/Kernel
License: GPLv2
Provides: %{name}-modules%{?kernel_flavor:-%{kernel_flavor}} = %{kernel_version}, openvswitch.ko.%{module_abi_version}
%if %{?kernel_uname:0}%{!?kernel_uname:1}
Requires: kernel%{?kernel_flavor:-%{kernel_flavor}} = %{kernel_version}
%endif
%if %{?kernel_uname:1}%{!?kernel_uname:0}
Requires: kernel-uname-r = %{kernel_version}
%endif
%description %{module_package}
Open vSwitch Linux kernel module compiled against kernel version
%{kernel_version}%{?kernel_flavor:%{kernel_flavor}}.
%prep
%setup -q -n openvswitch-%{openvswitch_version}
%build
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=%{_localstatedir} --with-linux=/lib/modules/%{xen_version}/build --enable-ssl CFLAGS='-g -O2 -msse -msse2'
make %{_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
install -d -m 755 $RPM_BUILD_ROOT/etc
install -d -m 755 $RPM_BUILD_ROOT/etc/init.d
install -m 755 xenserver/etc_init.d_openvswitch \
$RPM_BUILD_ROOT/etc/init.d/openvswitch
install -m 755 xenserver/etc_init.d_openvswitch-xapi-update \
$RPM_BUILD_ROOT/etc/init.d/openvswitch-xapi-update
install -d -m 755 $RPM_BUILD_ROOT/etc/sysconfig
install -d -m 755 $RPM_BUILD_ROOT/etc/logrotate.d
install -m 755 xenserver/etc_logrotate.d_openvswitch \
$RPM_BUILD_ROOT/etc/logrotate.d/openvswitch
install -d -m 755 $RPM_BUILD_ROOT/etc/profile.d
install -m 755 xenserver/etc_profile.d_openvswitch.sh \
$RPM_BUILD_ROOT/etc/profile.d/openvswitch.sh
install -d -m 755 $RPM_BUILD_ROOT/etc/xapi.d/plugins
install -m 755 xenserver/etc_xapi.d_plugins_openvswitch-cfg-update \
$RPM_BUILD_ROOT/etc/xapi.d/plugins/openvswitch-cfg-update
install -d -m 755 $RPM_BUILD_ROOT/usr/share/openvswitch/scripts
install -m 755 xenserver/opt_xensource_libexec_interface-reconfigure \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/interface-reconfigure
install -m 644 xenserver/opt_xensource_libexec_InterfaceReconfigure.py \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/InterfaceReconfigure.py
install -m 644 xenserver/opt_xensource_libexec_InterfaceReconfigureBridge.py \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/InterfaceReconfigureBridge.py
install -m 644 xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/InterfaceReconfigureVswitch.py
install -m 755 xenserver/etc_xensource_scripts_vif \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/vif
install -m 755 xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/ovs-xapi-sync
install -m 755 xenserver/usr_share_openvswitch_scripts_sysconfig.template \
$RPM_BUILD_ROOT/usr/share/openvswitch/scripts/sysconfig.template
install -d -m 755 $RPM_BUILD_ROOT/usr/lib/xsconsole/plugins-base
install -m 644 \
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
$RPM_BUILD_ROOT/usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.py
install -d -m 755 $RPM_BUILD_ROOT/lib/modules/%{xen_version}/extra/openvswitch
find datapath/linux -name *.ko -exec install -m 755 \{\} $RPM_BUILD_ROOT/lib/modules/%{xen_version}/extra/openvswitch \;
install -d -m 755 $RPM_BUILD_ROOT/etc/xensource/bugtool
cp -rf $RPM_BUILD_ROOT/usr/share/openvswitch/bugtool-plugins/* $RPM_BUILD_ROOT/etc/xensource/bugtool
# Get rid of stuff we don't want to make RPM happy.
rm \
$RPM_BUILD_ROOT/usr/bin/ovs-testcontroller \
$RPM_BUILD_ROOT/usr/bin/ovs-l3ping \
$RPM_BUILD_ROOT/usr/bin/ovs-pki \
$RPM_BUILD_ROOT/usr/bin/ovs-test \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-testcontroller.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-l3ping.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-test.8
(cd "$RPM_BUILD_ROOT" && rm -f usr/lib/lib*)
(cd "$RPM_BUILD_ROOT" && rm -rf usr/include)
(cd "$RPM_BUILD_ROOT" && rm -rf usr/lib/pkgconfig)
install -d -m 755 $RPM_BUILD_ROOT/var/lib/openvswitch
%check
%if %{with check}
if make check TESTSUITEFLAGS='%{_smp_mflags}' RECHECK=yes; then :;
else
cat tests/testsuite.log
exit 1
fi
%endif
%clean
rm -rf $RPM_BUILD_ROOT
%post
# A list of Citrix XenServer scripts that we might need to replace
# with our own versions.
scripts="
/etc/xensource/scripts/vif
/opt/xensource/libexec/InterfaceReconfigure.py
/opt/xensource/libexec/InterfaceReconfigureBridge.py
/opt/xensource/libexec/InterfaceReconfigureVswitch.py
/opt/xensource/libexec/interface-reconfigure"
# Calculate into $md5sums a comma-separated set of md5sums of the
# Citrix XenServer scripts that we might need to replace. We might be
# upgrading an older version of the package that moved the files out
# of the way, so we need to look for the files in those out-of-the-way
# locations first.
md5sums=
for script in $scripts; do
b=$(basename "$script")
if test -e /usr/lib/openvswitch/xs-saved/"$b"; then
f=/usr/lib/openvswitch/xs-saved/"$b"
elif test -e /usr/lib/openvswitch/xs-original/"$b"; then
f=/usr/lib/openvswitch/xs-original/"$b"
elif test -e "$script" && test ! -h "$script"; then
f=$script
else
printf "\n$script: not found\n"
f=/dev/null
fi
md5sums="$md5sums,$(md5sum $f | awk '{print $1}')"
done
md5sums=${md5sums#,}
# Now check the md5sums against the known sets of md5sums:
#
# - If they are known to be a version of XenServer scripts that we should
# replace, we replace them (by putting $scripts into $replace_files).
#
# - Otherwise, we guess that it's better not to replace them, because the
# improvements that our versions of the scripts provide are minimal, so
# it's better to avoid possibly breaking any changes made upstream by
# Citrix.
case $md5sums in
cf09a68d9f8b434e79a4c83b01a3bb4b,395866df1b0b20c12c4dd2f7de0ecdb4,9d493545ae81463239d3162cbc798852,862d0939b441de9264a900628e950fe9,21f85db25599d7f026cd489385d58aa6)
keep_files=
replace_files=$scripts
printf "\nVerified host scripts from XenServer 6.0.0.\n"
;;
c5f48246577a17cf1b971fb5ce4e920b,2e2c912f86f9c536c89adc34ff3c2b2b,28d3ff72d72bdec4f37d70699f5edb76,67e1d0af16fc1ddf10009c5c063ad2ba,f3feff30aa3b3f8b514664a96a8dc0ab)
keep_files=
replace_files=$scripts
printf "\nVerified host scripts from XenServer 5.6-SP2.\n"
;;
c5f48246577a17cf1b971fb5ce4e920b,2e2c912f86f9c536c89adc34ff3c2b2b,28d3ff72d72bdec4f37d70699f5edb76,67e1d0af16fc1ddf10009c5c063ad2ba,24bae6906d182ba47668174f8e480cc6)
keep_files=
replace_files=$scripts
printf "\nVerified host scripts from XenServer 5.6-FP1.\n"
;;
*)
keep_files=$scripts
replace_files=
cat <<EOF
The host scripts on this machine are not those of any supported
version of XenServer. On XenServer earlier than 5.6-FP1, your Open
vSwitch installation will not work. On XenServer 5.6-FP1 or later,
Open vSwitch is not verified to work, which could lead to unexpected
behavior.
EOF
;;
esac
if grep -F net.ipv4.conf.all.arp_filter /etc/sysctl.conf >/dev/null 2>&1; then :; else
cat >>/etc/sysctl.conf <<EOF
# This works around an issue in xhad, which binds to a particular
# Ethernet device, which in turn causes ICMP port unreachable messages
# if packets are received are on the wrong interface, which in turn
# can happen if we send out ARP replies on every interface (as Linux
# does by default) instead of just on the interface that has the IP
# address being ARPed for, which this sysctl setting in turn works
# around.
#
# Bug #1378.
net.ipv4.conf.all.arp_filter = 1
EOF
fi
if test ! -e /etc/openvswitch/conf.db; then
install -d -m 755 -o root -g root /etc/openvswitch
# Create ovs-vswitchd config database
ovsdb-tool -vconsole:off create /etc/openvswitch/conf.db \
/usr/share/openvswitch/vswitch.ovsschema
# Create initial table in config database
ovsdb-tool -vconsole:off transact /etc/openvswitch/conf.db \
'[{"op": "insert", "table": "Open_vSwitch", "row": {}}]' \
> /dev/null
fi
# Create default or update existing /etc/sysconfig/openvswitch.
SYSCONFIG=/etc/sysconfig/openvswitch
TEMPLATE=/usr/share/openvswitch/scripts/sysconfig.template
if [ ! -e $SYSCONFIG ]; then
cp $TEMPLATE $SYSCONFIG
else
for var in $(awk -F'[ :]' '/^# [_A-Z0-9]+:/{print $2}' $TEMPLATE)
do
if ! grep $var $SYSCONFIG >/dev/null 2>&1; then
echo >> $SYSCONFIG
sed -n "/$var:/,/$var=/p" $TEMPLATE >> $SYSCONFIG
fi
done
fi
# Deliberately break %postun in broken OVS builds that revert original
# XenServer scripts during rpm -U by moving the directory where it thinks
# they are saved.
if [ -d /usr/lib/openvswitch/xs-original ]; then
mkdir -p /usr/lib/openvswitch/xs-saved
mv /usr/lib/openvswitch/xs-original/* /usr/lib/openvswitch/xs-saved/ &&
rmdir /usr/lib/openvswitch/xs-original
fi
# Replace XenServer files by our versions.
mkdir -p /usr/lib/openvswitch/xs-saved \
|| printf "Could not create script backup directory.\n"
for f in $replace_files; do
s=$(basename "$f")
t=$(readlink "$f")
if [ -f "$f" ] && [ "$t" != "/usr/share/openvswitch/scripts/$s" ]; then
mv "$f" /usr/lib/openvswitch/xs-saved/ \
|| printf "Could not save original XenServer $s script\n"
ln -s "/usr/share/openvswitch/scripts/$s" "$f" \
|| printf "Could not link to Open vSwitch $s script\n"
fi
done
# Clean up dangling symlinks to removed OVS replacement scripts no longer
# provided by OVS. Any time a replacement script is removed from OVS,
# it should be added here to ensure correct reversion from old versions of
# OVS that don't clean up dangling symlinks during the uninstall phase.
for orig in /usr/sbin/xen-bugtool $keep_files; do
saved=/usr/lib/openvswitch/xs-saved/$(basename "$orig")
[ -e "$saved" ] && mv -f "$saved" "$orig"
done
# Ensure all required services are set to run
for s in openvswitch openvswitch-xapi-update; do
if chkconfig --list $s >/dev/null 2>&1; then
chkconfig --del $s || printf "Could not remove $s init script.\n"
fi
chkconfig --add $s || printf "Could not add $s init script.\n"
chkconfig $s on || printf "Could not enable $s init script.\n"
done
if [ "$1" = "1" ]; then # $1 = 1 for install
# Configure system to use Open vSwitch
/opt/xensource/bin/xe-switch-network-backend vswitch
else # $1 = 2 for upgrade
mode=$(cat /etc/xensource/network.conf)
if [ "$mode" != "vswitch" ] && [ "$mode" != "openvswitch" ]; then
printf "\nThe server is not configured to run Open vSwitch. To run in\n"
printf "vswitch mode, you must run the following command:\n\n"
printf " xe-switch-network-backend vswitch"
printf "\n\n"
fi
fi
%posttrans %{module_package}
# Ensure that modprobe will find our modules.
#
# This has to be in %posttrans instead of %post because older versions
# installed modules into a different directory and "rpm -U" runs the
# new version's %post before removing the old version's files, so if
# we use %post then depmod may find the old versions that are about to
# be removed.
depmod %{xen_version}
mode=$(cat /etc/xensource/network.conf)
if [ "$mode" = "vswitch" ] || [ "$mode" = "openvswitch" ]; then
printf "\nTo use the newly installed Open vSwitch kernel module, you\n"
printf "will either have to reboot the hypervisor or follow any\n"
printf "workarounds provided by your administration guide. Failure to do\n"
printf "so may result in incorrect operation."
printf "\n\n"
fi
%preun
if [ "$1" = "0" ]; then # $1 = 0 for uninstall
# Configure system to use bridge
/opt/xensource/bin/xe-switch-network-backend bridge
# The "openvswitch" service should have been removed from
# "xe-switch-network-backend bridge".
for s in openvswitch openvswitch-xapi-update; do
if chkconfig --list $s >/dev/null 2>&1; then
chkconfig --del $s || printf "Could not remove $s init script."
fi
done
fi
%postun
# Restore original XenServer scripts if the OVS equivalent no longer exists.
# This works both in the upgrade and erase cases.
# This lists every file that every version of OVS has ever replaced. Never
# remove old files that OVS no longer replaces, or upgrades from old versions
# will fail to restore the XS originals, leaving the system in a broken state.
# Also be sure to add removed script paths to the %post scriptlet above to
# prevent the same problem when upgrading from old versions of OVS that lack
# this restore-on-upgrade logic.
for f in \
/etc/xensource/scripts/vif \
/usr/sbin/xen-bugtool \
/opt/xensource/libexec/interface-reconfigure \
/opt/xensource/libexec/InterfaceReconfigure.py \
/opt/xensource/libexec/InterfaceReconfigureBridge.py \
/opt/xensource/libexec/InterfaceReconfigureVswitch.py
do
# Only revert dangling symlinks.
if [ -h "$f" ] && [ ! -e "$f" ]; then
s=$(basename "$f")
if [ ! -f "/usr/lib/openvswitch/xs-saved/$s" ]; then
printf "Original XenServer $s script not present in /usr/lib/openvswitch/xs-saved\n" >&2
printf "Could not restore original XenServer script.\n" >&2
else
(rm -f "$f" \
&& mv "/usr/lib/openvswitch/xs-saved/$s" "$f") \
|| printf "Could not restore original XenServer $s script.\n" >&2
fi
fi
done
if [ "$1" = "0" ]; then # $1 = 0 for uninstall
rm -f /usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.pyc \
/usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.pyo
rm -f /usr/share/openvswitch/scripts/InterfaceReconfigure.pyc \
/usr/share/openvswitch/scripts/InterfaceReconfigure.pyo \
/usr/share/openvswitch/scripts/InterfaceReconfigureBridge.pyc \
/usr/share/openvswitch/scripts/InterfaceReconfigureBridge.pyo \
/usr/share/openvswitch/scripts/InterfaceReconfigureVSwitch.pyc \
/usr/share/openvswitch/scripts/InterfaceReconfigureVSwitch.pyo
# Remove all configuration files
rm -f /etc/openvswitch/conf.db
rm -f /etc/sysconfig/openvswitch
rm -f /etc/openvswitch/vswitchd.cacert
# Remove saved XenServer scripts directory, but only if it's empty
rmdir -p /usr/lib/openvswitch/xs-saved 2>/dev/null
fi
exit 0
%files
%defattr(-,root,root)
/etc/bash_completion.d/ovs-appctl-bashcomp.bash
/etc/bash_completion.d/ovs-vsctl-bashcomp.bash
/etc/init.d/openvswitch
/etc/init.d/openvswitch-xapi-update
/etc/xapi.d/plugins/openvswitch-cfg-update
/etc/xensource/bugtool/*
/etc/logrotate.d/openvswitch
/etc/profile.d/openvswitch.sh
/usr/share/openvswitch/python/
/usr/share/openvswitch/bugtool-plugins/*
/usr/share/openvswitch/scripts/ovs-check-dead-ifs
/usr/share/openvswitch/scripts/ovs-xapi-sync
/usr/share/openvswitch/scripts/interface-reconfigure
/usr/share/openvswitch/scripts/InterfaceReconfigure.py
/usr/share/openvswitch/scripts/InterfaceReconfigureBridge.py
/usr/share/openvswitch/scripts/InterfaceReconfigureVswitch.py
/usr/share/openvswitch/scripts/vif
/usr/share/openvswitch/scripts/sysconfig.template
/usr/share/openvswitch/scripts/ovs-bugtool-*
/usr/share/openvswitch/scripts/ovs-save
/usr/share/openvswitch/scripts/ovs-ctl
/usr/share/openvswitch/scripts/ovs-lib
/usr/share/openvswitch/scripts/ovs-vtep
/usr/share/openvswitch/vswitch.ovsschema
/usr/share/openvswitch/local-config.ovsschema
/usr/share/openvswitch/vtep.ovsschema
/usr/sbin/ovs-bugtool
/usr/sbin/ovs-vswitchd
/usr/sbin/ovsdb-server
/usr/bin/ovs-appctl
/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
/usr/bin/ovs-tcpundump
/usr/bin/ovs-vlan-test
/usr/bin/ovs-vsctl
/usr/bin/ovsdb-client
/usr/bin/ovsdb-tool
/usr/bin/vtep-ctl
/usr/bin/ovs-tcpdump
/usr/lib/xsconsole/plugins-base/XSFeatureVSwitch.py
/usr/share/man/man1/ovsdb-client.1.gz
/usr/share/man/man1/ovsdb-server.1.gz
/usr/share/man/man1/ovsdb-tool.1.gz
/usr/share/man/man5/ovsdb.local-config.5.gz
/usr/share/man/man5/ovsdb-server.5.gz
/usr/share/man/man5/ovs-vswitchd.conf.db.5.gz
/usr/share/man/man5/vtep.5.gz
/usr/share/man/man7/ovs-fields.7.gz
/usr/share/man/man8/ovs-appctl.8.gz
/usr/share/man/man8/ovs-bugtool.8.gz
/usr/share/man/man8/ovs-ctl.8.gz
/usr/share/man/man8/ovs-dpctl.8.gz
/usr/share/man/man8/ovs-dpctl-top.8.gz
/usr/share/man/man8/ovs-ofctl.8.gz
/usr/share/man/man8/ovs-parse-backtrace.8.gz
/usr/share/man/man1/ovs-pcap.1.gz
/usr/share/man/man1/ovs-tcpundump.1.gz
/usr/share/man/man8/ovs-vlan-test.8.gz
/usr/share/man/man8/ovs-vsctl.8.gz
/usr/share/man/man8/ovs-vswitchd.8.gz
/usr/share/man/man8/vtep-ctl.8.gz
/usr/share/man/man8/ovs-tcpdump.8.gz
/var/lib/openvswitch
/var/log/openvswitch
%exclude /usr/lib/xsconsole/plugins-base/*.py[co]
%exclude /usr/share/openvswitch/scripts/*.py[co]
%exclude /usr/share/openvswitch/python/*.py[co]
%exclude /usr/share/openvswitch/python/ovs/*.py[co]
%exclude /usr/share/openvswitch/python/ovs/db/*.py[co]
%files %{module_package}
/lib/modules/%{xen_version}/extra/openvswitch/openvswitch.ko
/lib/modules/%{xen_version}/extra/openvswitch/vport-*.ko

View File

@@ -1,972 +0,0 @@
# Copyright (c) 2008,2009 Citrix Systems, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; version 2.1 only. with the special
# exception on linking described in file LICENSE.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
import sys
import syslog
import os
from xml.dom.minidom import getDOMImplementation
from xml.dom.minidom import parse as parseXML
the_root_prefix = ""
def root_prefix():
"""Returns a string to prefix to all file name references, which
is useful for testing."""
return the_root_prefix
def set_root_prefix(prefix):
global the_root_prefix
the_root_prefix = prefix
log_destination = "syslog"
def get_log_destination():
"""Returns the current log destination.
'syslog' means "log to syslog".
'stderr' means "log to stderr"."""
return log_destination
def set_log_destination(dest):
global log_destination
log_destination = dest
#
# Logging.
#
def log(s):
if get_log_destination() == 'syslog':
syslog.syslog(s)
else:
sys.stderr.write(s + '\n')
sys.stderr.flush()
#
# Exceptions.
#
class Error(Exception):
def __init__(self, msg):
Exception.__init__(self)
self.msg = msg
#
# Run external utilities
#
def run_command(command):
log("Running command: " + ' '.join(command))
rc = os.spawnl(os.P_WAIT, root_prefix() + command[0], *command)
if rc != 0:
log("Command failed %d: " % rc + ' '.join(command))
return False
return True
#
# Configuration File Handling.
#
class ConfigurationFile(object):
"""Write a file, tracking old and new versions.
Supports writing a new version of a file and applying and
reverting those changes.
"""
__STATE = {"OPEN":"OPEN",
"NOT-APPLIED":"NOT-APPLIED", "APPLIED":"APPLIED",
"REVERTED":"REVERTED", "COMMITTED": "COMMITTED"}
def __init__(self, path):
dirname,basename = os.path.split(path)
self.__state = self.__STATE['OPEN']
self.__children = []
self.__path = os.path.join(dirname, basename)
self.__oldpath = os.path.join(dirname, "." + basename + ".xapi-old")
self.__newpath = os.path.join(dirname, "." + basename + ".xapi-new")
self.__f = open(self.__newpath, "w")
def attach_child(self, child):
self.__children.append(child)
def path(self):
return self.__path
def readlines(self):
try:
return open(self.path()).readlines()
except:
return ""
def write(self, args):
if self.__state != self.__STATE['OPEN']:
raise Error("Attempt to write to file in state %s" % self.__state)
self.__f.write(args)
def close(self):
if self.__state != self.__STATE['OPEN']:
raise Error("Attempt to close file in state %s" % self.__state)
self.__f.close()
self.__state = self.__STATE['NOT-APPLIED']
def changed(self):
if self.__state != self.__STATE['NOT-APPLIED']:
raise Error("Attempt to compare file in state %s" % self.__state)
return True
def apply(self):
if self.__state != self.__STATE['NOT-APPLIED']:
raise Error("Attempt to apply configuration from state %s" % self.__state)
for child in self.__children:
child.apply()
log("Applying changes to %s configuration" % self.__path)
# Remove previous backup.
if os.access(self.__oldpath, os.F_OK):
os.unlink(self.__oldpath)
# Save current configuration.
if os.access(self.__path, os.F_OK):
os.link(self.__path, self.__oldpath)
os.unlink(self.__path)
# Apply new configuration.
assert(os.path.exists(self.__newpath))
os.link(self.__newpath, self.__path)
# Remove temporary file.
os.unlink(self.__newpath)
self.__state = self.__STATE['APPLIED']
def revert(self):
if self.__state != self.__STATE['APPLIED']:
raise Error("Attempt to revert configuration from state %s" % self.__state)
for child in self.__children:
child.revert()
log("Reverting changes to %s configuration" % self.__path)
# Remove existing new configuration
if os.access(self.__newpath, os.F_OK):
os.unlink(self.__newpath)
# Revert new configuration.
if os.access(self.__path, os.F_OK):
os.link(self.__path, self.__newpath)
os.unlink(self.__path)
# Revert to old configuration.
if os.access(self.__oldpath, os.F_OK):
os.link(self.__oldpath, self.__path)
os.unlink(self.__oldpath)
# Leave .*.xapi-new as an aid to debugging.
self.__state = self.__STATE['REVERTED']
def commit(self):
if self.__state != self.__STATE['APPLIED']:
raise Error("Attempt to commit configuration from state %s" % self.__state)
for child in self.__children:
child.commit()
log("Committing changes to %s configuration" % self.__path)
if os.access(self.__oldpath, os.F_OK):
os.unlink(self.__oldpath)
if os.access(self.__newpath, os.F_OK):
os.unlink(self.__newpath)
self.__state = self.__STATE['COMMITTED']
#
# Helper functions for encoding/decoding database attributes to/from XML.
#
def _str_to_xml(xml, parent, tag, val):
e = xml.createElement(tag)
parent.appendChild(e)
v = xml.createTextNode(val)
e.appendChild(v)
def _str_from_xml(n):
def getText(nodelist):
rc = ""
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc = rc + node.data
return rc
return getText(n.childNodes).strip()
def _bool_to_xml(xml, parent, tag, val):
if val:
_str_to_xml(xml, parent, tag, "True")
else:
_str_to_xml(xml, parent, tag, "False")
def _bool_from_xml(n):
s = _str_from_xml(n)
if s == "True":
return True
elif s == "False":
return False
else:
raise Error("Unknown boolean value %s" % s)
def _strlist_to_xml(xml, parent, ltag, itag, val):
e = xml.createElement(ltag)
parent.appendChild(e)
for v in val:
c = xml.createElement(itag)
e.appendChild(c)
cv = xml.createTextNode(v)
c.appendChild(cv)
def _strlist_from_xml(n, ltag, itag):
ret = []
for n in n.childNodes:
if n.nodeName == itag:
ret.append(_str_from_xml(n))
return ret
def _map_to_xml(xml, parent, tag, val, attrs):
e = xml.createElement(tag)
parent.appendChild(e)
for n,v in val.items():
if n in attrs:
_str_to_xml(xml, e, n, v)
else:
log("Unknown other-config attribute: %s" % n)
def _map_from_xml(n, attrs):
ret = {}
for n in n.childNodes:
if n.nodeName in attrs:
ret[n.nodeName] = _str_from_xml(n)
return ret
def _otherconfig_to_xml(xml, parent, val, attrs):
return _map_to_xml(xml, parent, "other_config", val, attrs)
def _otherconfig_from_xml(n, attrs):
return _map_from_xml(n, attrs)
#
# Definitions of the database objects (and their attributes) used by interface-reconfigure.
#
# Each object is defined by a dictionary mapping an attribute name in
# the xapi database to a tuple containing two items:
# - a function which takes this attribute and encodes it as XML.
# - a function which takes XML and decocdes it into a value.
#
# other-config attributes are specified as a simple array of strings
_PIF_XML_TAG = "pif"
_VLAN_XML_TAG = "vlan"
_TUNNEL_XML_TAG = "tunnel"
_BOND_XML_TAG = "bond"
_NETWORK_XML_TAG = "network"
_POOL_XML_TAG = "pool"
_ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in ['autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso', 'gro', 'lro'] ]
_PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 'static-routes' ] + \
[ 'bond-%s' % x for x in ['mode', 'miimon', 'downdelay', 'updelay', 'use_carrier', 'hashing-algorithm'] ] + \
[ 'vlan-bug-workaround' ] + \
_ETHTOOL_OTHERCONFIG_ATTRS
_PIF_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'management': (_bool_to_xml,_bool_from_xml),
'network': (_str_to_xml,_str_from_xml),
'device': (_str_to_xml,_str_from_xml),
'bond_master_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'bond_master_of', 'slave', v),
lambda n: _strlist_from_xml(n, 'bond_master_of', 'slave')),
'bond_slave_of': (_str_to_xml,_str_from_xml),
'VLAN': (_str_to_xml,_str_from_xml),
'VLAN_master_of': (_str_to_xml,_str_from_xml),
'VLAN_slave_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'VLAN_slave_of', 'master', v),
lambda n: _strlist_from_xml(n, 'VLAN_slave_Of', 'master')),
'tunnel_access_PIF_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'tunnel_access_PIF_of', 'pif', v),
lambda n: _strlist_from_xml(n, 'tunnel_access_PIF_of', 'pif')),
'tunnel_transport_PIF_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'tunnel_transport_PIF_of', 'pif', v),
lambda n: _strlist_from_xml(n, 'tunnel_transport_PIF_of', 'pif')),
'ip_configuration_mode': (_str_to_xml,_str_from_xml),
'IP': (_str_to_xml,_str_from_xml),
'netmask': (_str_to_xml,_str_from_xml),
'gateway': (_str_to_xml,_str_from_xml),
'DNS': (_str_to_xml,_str_from_xml),
'MAC': (_str_to_xml,_str_from_xml),
'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, v, _PIF_OTHERCONFIG_ATTRS),
lambda n: _otherconfig_from_xml(n, _PIF_OTHERCONFIG_ATTRS)),
# Special case: We write the current value
# PIF.currently-attached to the cache but since it will
# not be valid when we come to use the cache later
# (i.e. after a reboot) we always read it as False.
'currently_attached': (_bool_to_xml, lambda n: False),
}
_VLAN_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'tagged_PIF': (_str_to_xml,_str_from_xml),
'untagged_PIF': (_str_to_xml,_str_from_xml),
}
_TUNNEL_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'access_PIF': (_str_to_xml,_str_from_xml),
'transport_PIF': (_str_to_xml,_str_from_xml),
}
_BOND_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'master': (_str_to_xml,_str_from_xml),
'slaves': (lambda x, p, t, v: _strlist_to_xml(x, p, 'slaves', 'slave', v),
lambda n: _strlist_from_xml(n, 'slaves', 'slave')),
}
_NETWORK_OTHERCONFIG_ATTRS = [ 'mtu',
'static-routes',
'vswitch-controller-fail-mode',
'vswitch-disable-in-band' ] \
+ _ETHTOOL_OTHERCONFIG_ATTRS
_NETWORK_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
'bridge': (_str_to_xml,_str_from_xml),
'MTU': (_str_to_xml,_str_from_xml),
'PIFs': (lambda x, p, t, v: _strlist_to_xml(x, p, 'PIFs', 'PIF', v),
lambda n: _strlist_from_xml(n, 'PIFs', 'PIF')),
'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, v, _NETWORK_OTHERCONFIG_ATTRS),
lambda n: _otherconfig_from_xml(n, _NETWORK_OTHERCONFIG_ATTRS)),
}
_POOL_OTHERCONFIG_ATTRS = ['vswitch-controller-fail-mode']
_POOL_ATTRS = { 'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, v, _POOL_OTHERCONFIG_ATTRS),
lambda n: _otherconfig_from_xml(n, _POOL_OTHERCONFIG_ATTRS)),
}
#
# Database Cache object
#
_db = None
def db():
assert(_db is not None)
return _db
def db_init_from_cache(cache):
global _db
assert(_db is None)
_db = DatabaseCache(cache_file=cache)
def db_init_from_xenapi(session):
global _db
assert(_db is None)
_db = DatabaseCache(session_ref=session)
class DatabaseCache(object):
def __read_xensource_inventory(self):
filename = root_prefix() + "/etc/xensource-inventory"
f = open(filename, "r")
lines = [x.strip("\n") for x in f.readlines()]
f.close()
defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
defs = [ (a, b.strip("'")) for (a,b) in defs ]
return dict(defs)
def __pif_on_host(self,pif):
return pif in self.__pifs
def __get_pif_records_from_xapi(self, session, host):
self.__pifs = {}
for (p,rec) in session.xenapi.PIF.get_all_records().items():
if rec['host'] != host:
continue
self.__pifs[p] = {}
for f in _PIF_ATTRS:
self.__pifs[p][f] = rec[f]
self.__pifs[p]['other_config'] = {}
for f in _PIF_OTHERCONFIG_ATTRS:
if f not in rec['other_config']: continue
self.__pifs[p]['other_config'][f] = rec['other_config'][f]
def __get_vlan_records_from_xapi(self, session):
self.__vlans = {}
for (v,rec) in session.xenapi.VLAN.get_all_records().items():
if not self.__pif_on_host(rec['untagged_PIF']):
continue
self.__vlans[v] = {}
for f in _VLAN_ATTRS:
self.__vlans[v][f] = rec[f]
def __get_tunnel_records_from_xapi(self, session):
self.__tunnels = {}
for t in session.xenapi.tunnel.get_all():
rec = session.xenapi.tunnel.get_record(t)
if not self.__pif_on_host(rec['transport_PIF']):
continue
self.__tunnels[t] = {}
for f in _TUNNEL_ATTRS:
self.__tunnels[t][f] = rec[f]
def __get_bond_records_from_xapi(self, session):
self.__bonds = {}
for (b,rec) in session.xenapi.Bond.get_all_records().items():
if not self.__pif_on_host(rec['master']):
continue
self.__bonds[b] = {}
for f in _BOND_ATTRS:
self.__bonds[b][f] = rec[f]
def __get_network_records_from_xapi(self, session):
self.__networks = {}
for (n,rec) in session.xenapi.network.get_all_records().items():
self.__networks[n] = {}
for f in _NETWORK_ATTRS:
if f == "PIFs":
# drop PIFs on other hosts
self.__networks[n][f] = [p for p in rec[f] if self.__pif_on_host(p)]
elif f == "MTU" and f not in rec:
# XenServer 5.5 network records did not have an
# MTU field, so allow this to be missing.
pass
else:
self.__networks[n][f] = rec[f]
self.__networks[n]['other_config'] = {}
for f in _NETWORK_OTHERCONFIG_ATTRS:
if f not in rec['other_config']: continue
self.__networks[n]['other_config'][f] = rec['other_config'][f]
def __get_pool_records_from_xapi(self, session):
self.__pools = {}
for p in session.xenapi.pool.get_all():
rec = session.xenapi.pool.get_record(p)
self.__pools[p] = {}
for f in _POOL_ATTRS:
self.__pools[p][f] = rec[f]
for f in _POOL_OTHERCONFIG_ATTRS:
if f in rec['other_config']:
self.__pools[p]['other_config'][f] = rec['other_config'][f]
def __to_xml(self, xml, parent, key, ref, rec, attrs):
"""Encode a database object as XML"""
e = xml.createElement(key)
parent.appendChild(e)
if ref:
e.setAttribute('ref', ref)
for n,v in rec.items():
if n in attrs:
h,_ = attrs[n]
h(xml, e, n, v)
else:
raise Error("Unknown attribute %s" % n)
def __from_xml(self, e, attrs):
"""Decode a database object from XML"""
ref = e.attributes['ref'].value
rec = {}
for n in e.childNodes:
if n.nodeName in attrs:
_,h = attrs[n.nodeName]
rec[n.nodeName] = h(n)
return (ref,rec)
def __init__(self, session_ref=None, cache_file=None):
if session_ref and cache_file:
raise Error("can't specify session reference and cache file")
if cache_file == None:
import XenAPI
session = XenAPI.xapi_local()
if not session_ref:
log("No session ref given on command line, logging in.")
session.xenapi.login_with_password("root", "")
else:
session._session = session_ref
try:
inventory = self.__read_xensource_inventory()
assert('INSTALLATION_UUID' in inventory)
log("host uuid is %s" % inventory['INSTALLATION_UUID'])
host = session.xenapi.host.get_by_uuid(inventory['INSTALLATION_UUID'])
self.__get_pif_records_from_xapi(session, host)
self.__get_pool_records_from_xapi(session)
self.__get_tunnel_records_from_xapi(session)
self.__get_vlan_records_from_xapi(session)
self.__get_bond_records_from_xapi(session)
self.__get_network_records_from_xapi(session)
finally:
if not session_ref:
session.xenapi.session.logout()
else:
log("Loading xapi database cache from %s" % cache_file)
xml = parseXML(root_prefix() + cache_file)
self.__pifs = {}
self.__bonds = {}
self.__vlans = {}
self.__pools = {}
self.__tunnels = {}
self.__networks = {}
assert(len(xml.childNodes) == 1)
toplevel = xml.childNodes[0]
assert(toplevel.nodeName == "xenserver-network-configuration")
for n in toplevel.childNodes:
if n.nodeName == "#text":
pass
elif n.nodeName == _PIF_XML_TAG:
(ref,rec) = self.__from_xml(n, _PIF_ATTRS)
self.__pifs[ref] = rec
elif n.nodeName == _BOND_XML_TAG:
(ref,rec) = self.__from_xml(n, _BOND_ATTRS)
self.__bonds[ref] = rec
elif n.nodeName == _VLAN_XML_TAG:
(ref,rec) = self.__from_xml(n, _VLAN_ATTRS)
self.__vlans[ref] = rec
elif n.nodeName == _TUNNEL_XML_TAG:
(ref,rec) = self.__from_xml(n, _TUNNEL_ATTRS)
self.__vlans[ref] = rec
elif n.nodeName == _NETWORK_XML_TAG:
(ref,rec) = self.__from_xml(n, _NETWORK_ATTRS)
self.__networks[ref] = rec
elif n.nodeName == _POOL_XML_TAG:
(ref,rec) = self.__from_xml(n, _POOL_ATTRS)
self.__pools[ref] = rec
else:
raise Error("Unknown XML element %s" % n.nodeName)
def save(self, cache_file):
xml = getDOMImplementation().createDocument(
None, "xenserver-network-configuration", None)
for (ref,rec) in self.__pifs.items():
self.__to_xml(xml, xml.documentElement, _PIF_XML_TAG, ref, rec, _PIF_ATTRS)
for (ref,rec) in self.__bonds.items():
self.__to_xml(xml, xml.documentElement, _BOND_XML_TAG, ref, rec, _BOND_ATTRS)
for (ref,rec) in self.__vlans.items():
self.__to_xml(xml, xml.documentElement, _VLAN_XML_TAG, ref, rec, _VLAN_ATTRS)
for (ref,rec) in self.__tunnels.items():
self.__to_xml(xml, xml.documentElement, _TUNNEL_XML_TAG, ref, rec, _TUNNEL_ATTRS)
for (ref,rec) in self.__networks.items():
self.__to_xml(xml, xml.documentElement, _NETWORK_XML_TAG, ref, rec,
_NETWORK_ATTRS)
for (ref,rec) in self.__pools.items():
self.__to_xml(xml, xml.documentElement, _POOL_XML_TAG, ref, rec, _POOL_ATTRS)
temp_file = cache_file + ".%d" % os.getpid()
f = open(temp_file, 'w')
f.write(xml.toprettyxml())
f.close()
os.rename(temp_file, cache_file)
def get_pif_by_uuid(self, uuid):
pifs = map(lambda ref_rec: ref_rec[0],
filter(lambda ref_rec: uuid == ref_rec[1]['uuid'],
self.__pifs.items()))
if len(pifs) == 0:
raise Error("Unknown PIF \"%s\"" % uuid)
elif len(pifs) > 1:
raise Error("Non-unique PIF \"%s\"" % uuid)
return pifs[0]
def get_pifs_by_device(self, device):
return list(map(lambda ref_rec: ref_rec[0],
list(filter(lambda ref_rec: ref_rec[1]['device'] == device,
self.__pifs.items()))))
def get_networks_with_bridge(self, bridge):
return list(map(lambda ref_rec: ref_rec[0],
list(filter(lambda ref_rec: ref_rec[1]['bridge'] == bridge,
self.__networks.items()))))
def get_network_by_bridge(self, bridge):
#Assumes one network has bridge.
try:
return self.get_networks_with_bridge(bridge)[0]
except KeyError:
return None
def get_pif_by_bridge(self, bridge):
networks = self.get_networks_with_bridge(bridge)
if len(networks) == 0:
raise Error("No matching network \"%s\"" % bridge)
answer = None
for network in networks:
nwrec = self.get_network_record(network)
for pif in nwrec['PIFs']:
pifrec = self.get_pif_record(pif)
if answer:
raise Error("Multiple PIFs on host for network %s" % (bridge))
answer = pif
if not answer:
raise Error("No PIF on host for network %s" % (bridge))
return answer
def get_pif_record(self, pif):
if pif in self.__pifs:
return self.__pifs[pif]
raise Error("Unknown PIF \"%s\"" % pif)
def get_all_pifs(self):
return self.__pifs
def pif_exists(self, pif):
return pif in self.__pifs
def get_management_pif(self):
""" Returns the management pif on host
"""
all = self.get_all_pifs()
for pif in all:
pifrec = self.get_pif_record(pif)
if pifrec['management']: return pif
return None
def get_network_record(self, network):
if network in self.__networks:
return self.__networks[network]
raise Error("Unknown network \"%s\"" % network)
def get_bond_record(self, bond):
if bond in self.__bonds:
return self.__bonds[bond]
else:
return None
def get_vlan_record(self, vlan):
if vlan in self.__vlans:
return self.__vlans[vlan]
else:
return None
def get_pool_record(self):
if len(self.__pools) > 0:
return list(self.__pools.values())[0]
#
#
#
PIF_OTHERCONFIG_DEFAULTS = {'gro': 'off', 'lro': 'off'}
def ethtool_settings(oc, defaults = {}):
settings = []
if 'ethtool-speed' in oc:
val = oc['ethtool-speed']
if val in ["10", "100", "1000"]:
settings += ['speed', val]
else:
log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val)
if 'ethtool-duplex' in oc:
val = oc['ethtool-duplex']
if val in ["half", "full"]:
settings += ['duplex', val]
else:
log("Invalid value for ethtool-duplex = %s. Must be half|full." % val)
if 'ethtool-autoneg' in oc:
val = oc['ethtool-autoneg']
if val in ["true", "on"]:
settings += ['autoneg', 'on']
elif val in ["false", "off"]:
settings += ['autoneg', 'off']
else:
log("Invalid value for ethtool-autoneg = %s. Must be on|true|off|false." % val)
offload = []
for opt in ("rx", "tx", "sg", "tso", "ufo", "gso", "gro", "lro"):
if "ethtool-" + opt in oc:
val = oc["ethtool-" + opt]
if val in ["true", "on"]:
offload += [opt, 'on']
elif val in ["false", "off"]:
offload += [opt, 'off']
else:
log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val))
elif opt in defaults:
offload += [opt, defaults[opt]]
return settings,offload
# By default the MTU is taken from the Network.MTU setting for VIF,
# PIF and Bridge. However it is possible to override this by using
# {VIF,PIF,Network}.other-config:mtu.
#
# type parameter is a string describing the object that the oc parameter
# is from. e.g. "PIF", "Network"
def mtu_setting(nw, type, oc):
mtu = None
nwrec = db().get_network_record(nw)
if 'MTU' in nwrec:
mtu = nwrec['MTU']
else:
mtu = "1500"
if 'mtu' in oc:
log("Override Network.MTU setting on bridge %s from %s.MTU is %s" % \
(nwrec['bridge'], type, mtu))
mtu = oc['mtu']
if mtu is not None:
try:
int(mtu) # Check that the value is an integer
return mtu
except ValueError as x:
log("Invalid value for mtu = %s" % mtu)
return None
#
# IP Network Devices -- network devices with IP configuration
#
def pif_ipdev_name(pif):
"""Return the ipdev name associated with pif"""
pifrec = db().get_pif_record(pif)
nwrec = db().get_network_record(pifrec['network'])
if nwrec['bridge']:
# TODO: sanity check that nwrec['bridgeless'] != 'true'
return nwrec['bridge']
else:
# TODO: sanity check that nwrec['bridgeless'] == 'true'
return pif_netdev_name(pif)
#
# Bare Network Devices -- network devices without IP configuration
#
def netdev_exists(netdev):
return os.path.exists(root_prefix() + "/sys/class/net/" + netdev)
def unicode_2to3(string):
if sys.version_info < (3,):
return string.encode()
return string
def pif_netdev_name(pif):
"""Get the netdev name for a PIF."""
pifrec = db().get_pif_record(pif)
if pif_is_vlan(pif):
return unicode_2to3("%(device)s.%(VLAN)s" % pifrec)
else:
return unicode_2to3(pifrec['device'])
#
# Bridges
#
def pif_is_bridged(pif):
pifrec = db().get_pif_record(pif)
nwrec = db().get_network_record(pifrec['network'])
if nwrec['bridge']:
# TODO: sanity check that nwrec['bridgeless'] != 'true'
return True
else:
# TODO: sanity check that nwrec['bridgeless'] == 'true'
return False
def pif_bridge_name(pif):
"""Return the bridge name of a pif.
PIF must be a bridged PIF."""
pifrec = db().get_pif_record(pif)
nwrec = db().get_network_record(pifrec['network'])
if nwrec['bridge']:
return nwrec['bridge']
else:
raise Error("PIF %(uuid)s does not have a bridge name" % pifrec)
#
# Bonded PIFs
#
def pif_is_bond(pif):
pifrec = db().get_pif_record(pif)
return len(pifrec['bond_master_of']) > 0
def pif_get_bond_masters(pif):
"""Returns a list of PIFs which are bond masters of this PIF"""
pifrec = db().get_pif_record(pif)
bso = pifrec['bond_slave_of']
# bond-slave-of is currently a single reference but in principle a
# PIF could be a member of several bonds which are not
# concurrently attached. Be robust to this possibility.
if not bso or bso == "OpaqueRef:NULL":
bso = []
elif not type(bso) == list:
bso = [bso]
bondrecs = [db().get_bond_record(bond) for bond in bso]
bondrecs = [rec for rec in bondrecs if rec]
return [bond['master'] for bond in bondrecs]
def pif_get_bond_slaves(pif):
"""Returns a list of PIFs which make up the given bonded pif."""
pifrec = db().get_pif_record(pif)
bmo = pifrec['bond_master_of']
if len(bmo) > 1:
raise Error("Bond-master-of contains too many elements")
if len(bmo) == 0:
return []
bondrec = db().get_bond_record(bmo[0])
if not bondrec:
raise Error("No bond record for bond master PIF")
return bondrec['slaves']
#
# VLAN PIFs
#
def pif_is_vlan(pif):
return db().get_pif_record(pif)['VLAN'] != '-1'
def pif_get_vlan_slave(pif):
"""Find the PIF which is the VLAN slave of pif.
Returns the 'physical' PIF underneath the a VLAN PIF @pif."""
pifrec = db().get_pif_record(pif)
vlan = pifrec['VLAN_master_of']
if not vlan or vlan == "OpaqueRef:NULL":
raise Error("PIF is not a VLAN master")
vlanrec = db().get_vlan_record(vlan)
if not vlanrec:
raise Error("No VLAN record found for PIF")
return vlanrec['tagged_PIF']
def pif_get_vlan_masters(pif):
"""Returns a list of PIFs which are VLANs on top of the given pif."""
pifrec = db().get_pif_record(pif)
vlans = [db().get_vlan_record(v) for v in pifrec['VLAN_slave_of']]
return [v['untagged_PIF'] for v in vlans if v and db().pif_exists(v['untagged_PIF'])]
#
# Tunnel PIFs
#
def pif_is_tunnel(pif):
return len(db().get_pif_record(pif)['tunnel_access_PIF_of']) > 0
#
# Datapath base class
#
class Datapath(object):
"""Object encapsulating the actions necessary to (de)configure the
datapath for a given PIF. Does not include configuration of the
IP address on the ipdev.
"""
def __init__(self, pif):
self._pif = pif
@classmethod
def rewrite(cls):
"""Class method called when write action is called. Can be used
to update any backend specific configuration."""
pass
def configure_ipdev(self, cfg):
"""Write ifcfg TYPE field for an IPdev, plus any type specific
fields to cfg
"""
raise NotImplementedError
def preconfigure(self, parent):
"""Prepare datapath configuration for PIF, but do not actually
apply any changes.
Any configuration files should be attached to parent.
"""
raise NotImplementedError
def bring_down_existing(self):
"""Tear down any existing network device configuration which
needs to be undone in order to bring this PIF up.
"""
raise NotImplementedError
def configure(self):
"""Apply the configuration prepared in the preconfigure stage.
Should assume any configuration files changed attached in
the preconfigure stage are applied and bring up the
necessary devices to provide the datapath for the
PIF.
Should not bring up the IPdev.
"""
raise NotImplementedError
def post(self):
"""Called after the IPdev has been brought up.
Should do any final setup, including reinstating any
devices which were taken down in the bring_down_existing
hook.
"""
raise NotImplementedError
def bring_down(self):
"""Tear down and deconfigure the datapath. Should assume the
IPdev has already been brought down.
"""
raise NotImplementedError
def DatapathFactory():
# XXX Need a datapath object for bridgeless PIFs
try:
network_conf = open(root_prefix() + "/etc/xensource/network.conf", 'r')
network_backend = network_conf.readline().strip()
network_conf.close()
except Exception as e:
raise Error("failed to determine network backend:" + e)
if network_backend == "bridge":
from InterfaceReconfigureBridge import DatapathBridge
return DatapathBridge
elif network_backend in ["openvswitch", "vswitch"]:
from InterfaceReconfigureVswitch import DatapathVswitch
return DatapathVswitch
else:
raise Error("unknown network backend %s" % network_backend)

View File

@@ -1,476 +0,0 @@
# Copyright (c) 2008,2009 Citrix Systems, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; version 2.1 only. with the special
# exception on linking described in file LICENSE.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
from InterfaceReconfigure import *
import sys
import time
sysfs_bonding_masters = root_prefix() + "/sys/class/net/bonding_masters"
def open_pif_ifcfg(pif):
pifrec = db().get_pif_record(pif)
interface = pif_netdev_name(pif)
log("Configuring %s (%s)" % (interface, pifrec['MAC']))
f = ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), interface))
f.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
(os.path.basename(f.path()), os.path.basename(sys.argv[0])))
f.write("XEMANAGED=yes\n")
f.write("DEVICE=%s\n" % interface)
f.write("ONBOOT=no\n")
return f
#
# Bare Network Devices -- network devices without IP configuration
#
def netdev_down(netdev):
"""Bring down a bare network device"""
if not netdev_exists(netdev):
log("netdev: down: device %s does not exist, ignoring" % netdev)
return
run_command(["/sbin/ifdown", netdev])
def netdev_up(netdev, mtu=None):
"""Bring up a bare network device"""
#if not netdev_exists(netdev):
# raise Error("netdev: up: device %s does not exist" % netdev)
run_command(["/sbin/ifup", netdev])
#
# Bonding driver
#
def load_bonding_driver():
log("Loading bonding driver")
run_command(["/sbin/modprobe", "bonding"])
try:
# bond_device_exists() uses the contents of sysfs_bonding_masters to work out which devices
# have already been created. Unfortunately the driver creates "bond0" automatically at
# modprobe init. Get rid of this now or our accounting will go wrong.
f = open(sysfs_bonding_masters, "w")
f.write("-bond0")
f.close()
except IOError as e:
log("Failed to load bonding driver: %s" % e)
def bonding_driver_loaded():
lines = open(root_prefix() + "/proc/modules").read().split("\n")
modules = [line.split(" ")[0] for line in lines]
return "bonding" in modules
def bond_device_exists(name):
f = open(sysfs_bonding_masters, "r")
bonds = f.readline().split()
f.close()
return name in bonds
def __create_bond_device(name):
if not bonding_driver_loaded():
load_bonding_driver()
if bond_device_exists(name):
log("bond master %s already exists, not creating" % name)
else:
log("Creating bond master %s" % name)
try:
f = open(sysfs_bonding_masters, "w")
f.write("+" + name)
f.close()
except IOError as e:
log("Failed to create %s: %s" % (name, e))
def create_bond_device(pif):
"""Ensures that a bond master device exists in the kernel."""
if not pif_is_bond(pif):
return
__create_bond_device(pif_netdev_name(pif))
def __destroy_bond_device(name):
if bond_device_exists(name):
retries = 10 # 10 * 0.5 seconds
while retries > 0:
retries = retries - 1
log("Destroying bond master %s (%d attempts remain)" % (name,retries))
try:
f = open(sysfs_bonding_masters, "w")
f.write("-" + name)
f.close()
retries = 0
except IOError as e:
time.sleep(0.5)
else:
log("bond master %s does not exist, not destroying" % name)
def destroy_bond_device(pif):
"""No, Mr. Bond, I expect you to die."""
pifrec = db().get_pif_record(pif)
if not pif_is_bond(pif):
return
# If the bonding module isn't loaded then do nothing.
if not os.access(sysfs_bonding_masters, os.F_OK):
return
name = pif_netdev_name(pif)
__destroy_bond_device(name)
#
# Bring Interface up/down.
#
def bring_down_interface(pif, destroy=False):
"""Bring down the interface associated with PIF.
Brings down the given interface as well as any physical interfaces
which are bond slaves of this one. This is because they will be
required when the bond is brought up."""
def destroy_bridge(pif):
"""Bring down the bridge associated with a PIF."""
#if not pif_is_bridged(pif):
# return
bridge = pif_bridge_name(pif)
if not netdev_exists(bridge):
log("destroy_bridge: bridge %s does not exist, ignoring" % bridge)
return
log("Destroy bridge %s" % bridge)
netdev_down(bridge)
run_command(["/usr/sbin/brctl", "delbr", bridge])
def destroy_vlan(pif):
vlan = pif_netdev_name(pif)
if not netdev_exists(vlan):
log("vconfig del: vlan %s does not exist, ignoring" % vlan)
return
log("Destroy vlan device %s" % vlan)
run_command(["/sbin/vconfig", "rem", vlan])
if pif_is_vlan(pif):
interface = pif_netdev_name(pif)
log("bring_down_interface: %s is a VLAN" % interface)
netdev_down(interface)
if destroy:
destroy_vlan(pif)
destroy_bridge(pif)
else:
return
slave = pif_get_vlan_slave(pif)
if db().get_pif_record(slave)['currently_attached']:
log("bring_down_interface: vlan slave is currently attached")
return
masters = pif_get_vlan_masters(slave)
masters = [m for m in masters if m != pif and db().get_pif_record(m)['currently_attached']]
if len(masters) > 0:
log("bring_down_interface: vlan slave has other masters")
return
log("bring_down_interface: no more masters, bring down vlan slave %s" % pif_netdev_name(slave))
pif = slave
else:
vlan_masters = pif_get_vlan_masters(pif)
log("vlan masters of %s - %s" % (db().get_pif_record(pif)['device'], [pif_netdev_name(m) for m in vlan_masters]))
if len([m for m in vlan_masters if db().get_pif_record(m)['currently_attached']]) > 0:
log("Leaving %s up due to currently attached VLAN masters" % pif_netdev_name(pif))
return
# pif is now either a bond or a physical device which needs to be brought down
# Need to bring down bond slaves first since the bond device
# must be up to enslave/unenslave.
bond_slaves = pif_get_bond_slaves_sorted(pif)
log("bond slaves of %s - %s" % (db().get_pif_record(pif)['device'], [pif_netdev_name(s) for s in bond_slaves]))
for slave in bond_slaves:
slave_interface = pif_netdev_name(slave)
if db().get_pif_record(slave)['currently_attached']:
log("leave bond slave %s up (currently attached)" % slave_interface)
continue
log("bring down bond slave %s" % slave_interface)
netdev_down(slave_interface)
# Also destroy the bridge associated with the slave, since
# it will carry the MAC address and possibly an IP address
# leading to confusion.
destroy_bridge(slave)
interface = pif_netdev_name(pif)
log("Bring interface %s down" % interface)
netdev_down(interface)
if destroy:
destroy_bond_device(pif)
destroy_bridge(pif)
def interface_is_up(pif):
try:
interface = pif_netdev_name(pif)
state = open("%s/sys/class/net/%s/operstate" % (root_prefix(), interface)).read().strip()
return state == "up"
except:
return False # interface prolly doesn't exist
def bring_up_interface(pif):
"""Bring up the interface associated with a PIF.
Also bring up the interfaces listed in additional.
"""
# VLAN on bond seems to need bond brought up explicitly, but VLAN
# on normal device does not. Might as well always bring it up.
if pif_is_vlan(pif):
slave = pif_get_vlan_slave(pif)
if not interface_is_up(slave):
bring_up_interface(slave)
interface = pif_netdev_name(pif)
create_bond_device(pif)
log("Bring interface %s up" % interface)
netdev_up(interface)
#
# Datapath topology configuration.
#
def _configure_physical_interface(pif):
"""Write the configuration for a physical interface.
Writes the configuration file for the physical interface described by
the pif object.
Returns the open file handle for the interface configuration file.
"""
pifrec = db().get_pif_record(pif)
log("Configuring physical interface %s" % pifrec['device'])
f = open_pif_ifcfg(pif)
f.write("TYPE=Ethernet\n")
f.write("HWADDR=%(MAC)s\n" % pifrec)
settings,offload = ethtool_settings(pifrec['other_config'],
PIF_OTHERCONFIG_DEFAULTS)
if len(settings):
f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings))
if len(offload):
f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload))
mtu = mtu_setting(pifrec['network'], "PIF", pifrec['other_config'])
if mtu:
f.write("MTU=%s\n" % mtu)
return f
def pif_get_bond_slaves_sorted(pif):
pifrec = db().get_pif_record(pif)
# build a list of slave's pifs
slave_pifs = pif_get_bond_slaves(pif)
# Ensure any currently attached slaves are listed in the opposite order to the order in
# which they were attached. The first slave attached must be the last detached since
# the bond is using its MAC address.
try:
attached_slaves = open("%s/sys/class/net/%s/bonding/slaves" % (root_prefix(), pifrec['device'])).readline().split()
for slave in attached_slaves:
pifs = [p for p in db().get_pifs_by_device(slave) if not pif_is_vlan(p)]
slave_pif = pifs[0]
slave_pifs.remove(slave_pif)
slave_pifs.insert(0, slave_pif)
except IOError:
pass
return slave_pifs
def _configure_bond_interface(pif):
"""Write the configuration for a bond interface.
Writes the configuration file for the bond interface described by
the pif object. Handles writing the configuration for the slave
interfaces.
Returns the open file handle for the bond interface configuration
file.
"""
pifrec = db().get_pif_record(pif)
f = open_pif_ifcfg(pif)
if pifrec['MAC'] != "":
f.write("MACADDR=%s\n" % pifrec['MAC'])
for slave in pif_get_bond_slaves(pif):
s = _configure_physical_interface(slave)
s.write("MASTER=%(device)s\n" % pifrec)
s.write("SLAVE=yes\n")
s.close()
f.attach_child(s)
settings,offload = ethtool_settings(pifrec['other_config'])
if len(settings):
f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings))
if len(offload):
f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload))
mtu = mtu_setting(pifrec['network'], "Bond-PIF", pifrec['other_config'])
if mtu:
f.write("MTU=%s\n" % mtu)
# The bond option defaults
bond_options = {
"mode": "balance-slb",
"miimon": "100",
"downdelay": "200",
"updelay": "31000",
"use_carrier": "1",
"hashing-algorithm": "src_mac",
}
# override defaults with values from other-config whose keys being with "bond-"
oc = pifrec['other_config']
overrides = filter(lambda key,val: key.startswith("bond-"), oc.items())
overrides = map(lambda key,val: (key[5:], val), overrides)
bond_options.update(overrides)
# write the bond options to ifcfg-bondX
f.write('BONDING_OPTS="')
for (name,val) in bond_options.items():
f.write("%s=%s " % (name,val))
f.write('"\n')
return f
def _configure_vlan_interface(pif):
"""Write the configuration for a VLAN interface.
Writes the configuration file for the VLAN interface described by
the pif object. Handles writing the configuration for the master
interface if necessary.
Returns the open file handle for the VLAN interface configuration
file.
"""
slave = _configure_pif(pif_get_vlan_slave(pif))
pifrec = db().get_pif_record(pif)
f = open_pif_ifcfg(pif)
f.write("VLAN=yes\n")
settings,offload = ethtool_settings(pifrec['other_config'])
if len(settings):
f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings))
if len(offload):
f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload))
mtu = mtu_setting(pifrec['network'], "VLAN-PIF", pifrec['other_config'])
if mtu:
f.write("MTU=%s\n" % mtu)
f.attach_child(slave)
return f
def _configure_pif(pif):
"""Write the configuration for a PIF object.
Writes the configuration file the PIF and all dependent
interfaces (bond slaves and VLAN masters etc).
Returns the open file handle for the interface configuration file.
"""
if pif_is_vlan(pif):
f = _configure_vlan_interface(pif)
elif pif_is_bond(pif):
f = _configure_bond_interface(pif)
else:
f = _configure_physical_interface(pif)
f.write("BRIDGE=%s\n" % pif_bridge_name(pif))
f.close()
return f
#
#
#
class DatapathBridge(Datapath):
def __init__(self, pif):
if pif_is_tunnel(pif):
raise Error("Tunnel PIFs are not supported in Bridge mode")
Datapath.__init__(self, pif)
log("Configured for Bridge datapath")
def configure_ipdev(self, cfg):
if pif_is_bridged(self._pif):
cfg.write("TYPE=Bridge\n")
cfg.write("DELAY=0\n")
cfg.write("STP=off\n")
cfg.write("PIFDEV=%s\n" % pif_netdev_name(self._pif))
else:
cfg.write("TYPE=Ethernet\n")
def preconfigure(self, parent):
pf = _configure_pif(self._pif)
parent.attach_child(pf)
def bring_down_existing(self):
# Bring down any VLAN masters so that we can reconfigure the slave.
for master in pif_get_vlan_masters(self._pif):
name = pif_netdev_name(master)
log("action_up: bring down vlan master %s" % (name))
netdev_down(name)
# interface-reconfigure is never explicitly called to down a bond master.
# However, when we are called to up a slave it is implicit that we are destroying the master.
bond_masters = pif_get_bond_masters(self._pif)
for master in bond_masters:
log("action_up: bring down bond master %s" % (pif_netdev_name(master)))
# bring down master
bring_down_interface(master, destroy=True)
# No masters left - now its safe to reconfigure the slave.
bring_down_interface(self._pif)
def configure(self):
bring_up_interface(self._pif)
def post(self):
# Bring back any currently-attached VLAN masters
for master in [v for v in pif_get_vlan_masters(self._pif) if db().get_pif_record(v)['currently_attached']]:
name = pif_netdev_name(master)
log("action_up: bring up %s" % (name))
netdev_up(name)
def bring_down(self):
bring_down_interface(self._pif, destroy=True)

View File

@@ -1,724 +0,0 @@
# Copyright (c) 2008,2009,2011 Citrix Systems, Inc.
# Copyright (c) 2009,2010,2011,2012,2013,2017 Nicira, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; version 2.1 only. with the special
# exception on linking described in file LICENSE.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
from InterfaceReconfigure import *
import os
import re
import subprocess
#
# Bare Network Devices -- network devices without IP configuration
#
def netdev_down(netdev):
"""Bring down a bare network device"""
if not netdev_exists(netdev):
log("netdev: down: device %s does not exist, ignoring" % netdev)
return
run_command(["/sbin/ip", "link", "set", netdev, 'down'])
def netdev_up(netdev, mtu=None):
"""Bring up a bare network device"""
if not netdev_exists(netdev):
raise Error("netdev: up: device %s does not exist" % netdev)
if mtu:
mtu = ["mtu", mtu]
else:
mtu = []
run_command(["/sbin/ip", "link", "set", netdev, 'up'] + mtu)
# This is a list of drivers that do support VLAN tx or rx acceleration, but
# to which the VLAN bug workaround should not be applied. This could be
# because these are known-good drivers (that is, they do not have any of
# the bugs that the workaround avoids) or because the VLAN bug workaround
# will not work for them and may cause other problems.
#
# This is a very short list because few drivers have been tested.
NO_VLAN_WORKAROUND_DRIVERS = (
"bonding",
)
def netdev_get_driver_name(netdev):
"""Returns the name of the driver for network device 'netdev'"""
symlink = '%s/sys/class/net/%s/device/driver' % (root_prefix(), netdev)
try:
target = os.readlink(symlink)
except OSError as e:
log("%s: could not read netdev's driver name (%s)" % (netdev, e))
return None
slash = target.rfind('/')
if slash < 0:
log("target %s of symbolic link %s does not contain slash"
% (target, symlink))
return None
return target[slash + 1:]
def netdev_get_features(netdev):
"""Returns the features bitmap for the driver for 'netdev'.
The features bitmap is a set of NETIF_F_ flags supported by its driver."""
try:
features = open("%s/sys/class/net/%s/features" % (root_prefix(), netdev)).read().strip()
return int(features, 0)
except:
return 0 # interface prolly doesn't exist
def netdev_has_vlan_accel(netdev):
"""Returns True if 'netdev' supports VLAN acceleration, False otherwise."""
NETIF_F_HW_VLAN_TX = 128
NETIF_F_HW_VLAN_RX = 256
NETIF_F_VLAN = NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX
return (netdev_get_features(netdev) & NETIF_F_VLAN) != 0
#
# PIF miscellanea
#
def pif_currently_in_use(pif):
"""Determine if a PIF is currently in use.
A PIF is determined to be currently in use if
- PIF.currently-attached is true
- Any bond master is currently attached
- Any VLAN master is currently attached
"""
rec = db().get_pif_record(pif)
if rec['currently_attached']:
log("configure_datapath: %s is currently attached" % (pif_netdev_name(pif)))
return True
for b in pif_get_bond_masters(pif):
if pif_currently_in_use(b):
log("configure_datapath: %s is in use by BOND master %s" % (pif_netdev_name(pif),pif_netdev_name(b)))
return True
for v in pif_get_vlan_masters(pif):
if pif_currently_in_use(v):
log("configure_datapath: %s is in use by VLAN master %s" % (pif_netdev_name(pif),pif_netdev_name(v)))
return True
return False
#
# Datapath Configuration
#
def pif_datapath(pif):
"""Return the datapath PIF associated with PIF.
A non-VLAN PIF is its own datapath PIF, except that a bridgeless PIF has
no datapath PIF at all.
A VLAN PIF's datapath PIF is its VLAN slave's datapath PIF.
"""
if pif_is_vlan(pif):
return pif_datapath(pif_get_vlan_slave(pif))
pifrec = db().get_pif_record(pif)
nwrec = db().get_network_record(pifrec['network'])
if not nwrec['bridge']:
return None
else:
return pif
def datapath_get_physical_pifs(pif):
"""Return the PIFs for the physical network device(s) associated with a datapath PIF.
For a bond master PIF, these are the bond slave PIFs.
For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
A VLAN PIF cannot be a datapath PIF.
"""
if pif_is_tunnel(pif):
return []
elif pif_is_vlan(pif):
# Seems like overkill...
raise Error("get-physical-pifs should not get passed a VLAN")
elif pif_is_bond(pif):
return pif_get_bond_slaves(pif)
else:
return [pif]
def datapath_deconfigure_physical(netdev):
return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
def vsctl_escape(s):
if s.isalnum():
return s
def escape(match):
c = match.group(0)
if c == '\0':
raise Error("strings may not contain null bytes")
elif c == '\\':
return r'\\'
elif c == '\n':
return r'\n'
elif c == '\r':
return r'\r'
elif c == '\t':
return r'\t'
elif c == '\b':
return r'\b'
elif c == '\a':
return r'\a'
else:
return r'\x%02x' % ord(c)
return '"' + re.sub(r'["\\\000-\037]', escape, s) + '"'
def datapath_configure_tunnel(pif):
pass
def datapath_configure_bond(pif,slaves):
bridge = pif_bridge_name(pif)
pifrec = db().get_pif_record(pif)
interface = pif_netdev_name(pif)
argv = ['--', '--fake-iface', 'add-bond', bridge, interface]
for slave in slaves:
argv += [pif_netdev_name(slave)]
# Bonding options.
bond_options = {
"mode": "balance-slb",
"miimon": "100",
"downdelay": "200",
"updelay": "31000",
"use_carrier": "1",
"hashing-algorithm": "src_mac",
}
# override defaults with values from other-config whose keys
# being with "bond-"
oc = pifrec['other_config']
overrides = filter(lambda key_val:
key_val[0].startswith("bond-"), oc.items())
overrides = map(lambda key_val: (key_val[0][5:], key_val[1]), overrides)
bond_options.update(overrides)
mode = None
halgo = None
argv += ['--', 'set', 'Port', interface]
if pifrec['MAC'] != "":
argv += ['MAC=%s' % vsctl_escape(pifrec['MAC'])]
for (name,val) in sorted(bond_options.items()):
if name in ['updelay', 'downdelay']:
# updelay and downdelay have dedicated schema columns.
# The value must be a nonnegative integer.
try:
value = int(val)
if value < 0:
raise ValueError
argv += ['bond_%s=%d' % (name, value)]
except ValueError:
log("bridge %s has invalid %s '%s'" % (bridge, name, value))
elif name in ['miimon', 'use_carrier']:
try:
value = int(val)
if value < 0:
raise ValueError
if name == 'use_carrier':
if value:
value = "carrier"
else:
value = "miimon"
argv += ["other-config:bond-detect-mode=%s" % value]
else:
argv += ["other-config:bond-miimon-interval=%d" % value]
except ValueError:
log("bridge %s has invalid %s '%s'" % (bridge, name, value))
elif name == "mode":
mode = val
elif name == "hashing-algorithm":
halgo = val
else:
# Pass other bond options into other_config.
argv += ["other-config:%s=%s" % (vsctl_escape("bond-%s" % name),
vsctl_escape(val))]
if mode == 'lacp':
argv += ['lacp=active']
if halgo == 'src_mac':
argv += ['bond_mode=balance-slb']
elif halgo == "tcpudp_ports":
argv += ['bond_mode=balance-tcp']
else:
log("bridge %s has invalid bond-hashing-algorithm '%s'" % (bridge, halgo))
argv += ['bond_mode=balance-slb']
elif mode in ['balance-slb', 'active-backup']:
argv += ['lacp=off', 'bond_mode=%s' % mode]
else:
log("bridge %s has invalid bond-mode '%s'" % (bridge, mode))
argv += ['lacp=off', 'bond_mode=balance-slb']
return argv
def datapath_deconfigure_bond(netdev):
return ['--', '--with-iface', '--if-exists', 'del-port', netdev]
def datapath_deconfigure_ipdev(interface):
return ['--', '--with-iface', '--if-exists', 'del-port', interface]
def datapath_modify_config(commands):
#log("modifying configuration:")
#for c in commands:
# log(" %s" % c)
rc = run_command(['/usr/bin/ovs-vsctl'] + ['--timeout=20']
+ [c for c in commands if not c.startswith('#')])
if not rc:
raise Error("Failed to modify vswitch configuration")
return True
#
# Toplevel Datapath Configuration.
#
def configure_datapath(pif):
"""Bring up the configuration for 'pif', which must not be a VLAN PIF, by:
- Tearing down other PIFs that use the same physical devices as 'pif'.
- Ensuring that 'pif' itself is set up.
- *Not* tearing down any PIFs that are stacked on top of 'pif' (i.e. VLANs
on top of 'pif'.
Returns a tuple containing
- A list containing the necessary vsctl command line arguments
- A list of additional devices which should be brought up after
the configuration is applied.
- A list containing flows to apply to the pif bridge, note that
port numbers may need to be substituted once ofport is known
"""
vsctl_argv = []
extra_up_ports = []
bridge_flows = []
assert not pif_is_vlan(pif)
bridge = pif_bridge_name(pif)
physical_devices = datapath_get_physical_pifs(pif)
vsctl_argv += ['## configuring datapath %s' % bridge]
# Determine additional devices to deconfigure.
#
# Given all physical devices which are part of this PIF we need to
# consider:
# - any additional bond which a physical device is part of.
# - any additional physical devices which are part of an additional bond.
#
# Any of these which are not currently in use should be brought
# down and deconfigured.
extra_down_bonds = []
extra_down_ports = []
for p in physical_devices:
for bond in pif_get_bond_masters(p):
if bond == pif:
log("configure_datapath: leaving bond %s up" % pif_netdev_name(bond))
continue
if bond in extra_down_bonds:
continue
if db().get_pif_record(bond)['currently_attached']:
log("configure_datapath: implicitly tearing down currently-attached bond %s" % pif_netdev_name(bond))
extra_down_bonds += [bond]
for s in pif_get_bond_slaves(bond):
if s in physical_devices:
continue
if s in extra_down_ports:
continue
if pif_currently_in_use(s):
continue
extra_down_ports += [s]
log("configure_datapath: bridge - %s" % bridge)
log("configure_datapath: physical - %s" % [pif_netdev_name(p) for p in physical_devices])
log("configure_datapath: extra ports - %s" % [pif_netdev_name(p) for p in extra_down_ports])
log("configure_datapath: extra bonds - %s" % [pif_netdev_name(p) for p in extra_down_bonds])
# Need to fully deconfigure any bridge which any of the:
# - physical devices
# - bond devices
# - sibling devices
# refers to
for brpif in physical_devices + extra_down_ports + extra_down_bonds:
if brpif == pif:
continue
b = pif_bridge_name(brpif)
#ifdown(b)
# XXX
netdev_down(b)
vsctl_argv += ['# remove bridge %s' % b]
vsctl_argv += ['--', '--if-exists', 'del-br', b]
for n in extra_down_ports:
dev = pif_netdev_name(n)
vsctl_argv += ['# deconfigure sibling physical device %s' % dev]
vsctl_argv += datapath_deconfigure_physical(dev)
netdev_down(dev)
for n in extra_down_bonds:
dev = pif_netdev_name(n)
vsctl_argv += ['# deconfigure bond device %s' % dev]
vsctl_argv += datapath_deconfigure_bond(dev)
netdev_down(dev)
for p in physical_devices:
dev = pif_netdev_name(p)
vsctl_argv += ['# deconfigure physical port %s' % dev]
vsctl_argv += datapath_deconfigure_physical(dev)
vsctl_argv += ['--', '--may-exist', 'add-br', bridge]
if len(physical_devices) > 1:
vsctl_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
vsctl_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
vsctl_argv += ['# configure bond %s' % pif_netdev_name(pif)]
vsctl_argv += datapath_configure_bond(pif, physical_devices)
extra_up_ports += [pif_netdev_name(pif)]
elif len(physical_devices) == 1:
iface = pif_netdev_name(physical_devices[0])
vsctl_argv += ['# add physical device %s' % iface]
vsctl_argv += ['--', '--may-exist', 'add-port', bridge, iface]
elif pif_is_tunnel(pif):
datapath_configure_tunnel(pif)
vsctl_argv += ['# configure Bridge MAC']
vsctl_argv += ['--', 'set', 'Bridge', bridge,
'other-config:hwaddr=%s' % vsctl_escape(db().get_pif_record(pif)['MAC'])]
pool = db().get_pool_record()
network = db().get_network_by_bridge(bridge)
network_rec = None
fail_mode = None
valid_fail_modes = ['standalone', 'secure']
if network:
network_rec = db().get_network_record(network)
fail_mode = network_rec['other_config'].get('vswitch-controller-fail-mode')
if (fail_mode not in valid_fail_modes) and pool:
fail_mode = pool['other_config'].get('vswitch-controller-fail-mode')
# Add default flows to allow management traffic if fail-mode
# transitions to secure based on pool fail-mode setting
if fail_mode == 'secure' and db().get_pif_record(pif).get('management', False):
prev_fail_mode = vswitchCfgQuery(['get-fail-mode', bridge])
if prev_fail_mode != 'secure':
tp = 'idle_timeout=0,priority=0'
host_mgmt_mac = db().get_pif_record(pif)['MAC']
# account for bond as management interface
if len(physical_devices) > 1:
bridge_flows += ['%s,in_port=local,arp,dl_src=%s,actions=NORMAL' % (tp, host_mgmt_mac)]
bridge_flows += ['%s,in_port=local,dl_src=%s,actions=NORMAL' % (tp, host_mgmt_mac)]
# we don't know slave ofports yet, substitute later
bridge_flows += ['%s,in_port=%%s,arp,nw_proto=1,actions=local' % (tp)]
bridge_flows += ['%s,in_port=%%s,dl_dst=%s,actions=local' % (tp, host_mgmt_mac)]
else:
bridge_flows += ['%s,in_port=%%s,arp,nw_proto=1,actions=local' % (tp)]
bridge_flows += ['%s,in_port=local,arp,dl_src=%s,actions=%%s' % (tp, host_mgmt_mac)]
bridge_flows += ['%s,in_port=%%s,dl_dst=%s,actions=local' % (tp, host_mgmt_mac)]
bridge_flows += ['%s,in_port=local,dl_src=%s,actions=%%s' % (tp, host_mgmt_mac)]
if fail_mode not in valid_fail_modes:
fail_mode = 'standalone'
vsctl_argv += ['--', 'set', 'Bridge', bridge, 'fail_mode=%s' % fail_mode]
if network_rec:
dib = network_rec['other_config'].get('vswitch-disable-in-band')
if not dib:
vsctl_argv += ['--', 'remove', 'Bridge', bridge, 'other_config', 'disable-in-band']
elif dib in ['true', 'false']:
vsctl_argv += ['--', 'set', 'Bridge', bridge, 'other_config:disable-in-band=' + dib]
else:
log('"' + dib + '"' "isn't a valid setting for other_config:disable-in-band on " + bridge)
vsctl_argv += set_br_external_ids(pif)
vsctl_argv += ['## done configuring datapath %s' % bridge]
return vsctl_argv,extra_up_ports,bridge_flows
def deconfigure_bridge(pif):
vsctl_argv = []
bridge = pif_bridge_name(pif)
log("deconfigure_bridge: bridge - %s" % bridge)
vsctl_argv += ['# deconfigure bridge %s' % bridge]
vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
return vsctl_argv
def set_br_external_ids(pif):
pifrec = db().get_pif_record(pif)
dp = pif_datapath(pif)
dprec = db().get_pif_record(dp)
xs_network_uuids = []
for nwpif in db().get_pifs_by_device(pifrec['device']):
rec = db().get_pif_record(nwpif)
# When state is read from dbcache PIF.currently_attached
# is always assumed to be false... Err on the side of
# listing even detached networks for the time being.
#if nwpif != pif and not rec['currently_attached']:
# log("Network PIF %s not currently attached (%s)" % (rec['uuid'],pifrec['uuid']))
# continue
nwrec = db().get_network_record(rec['network'])
uuid = nwrec['uuid']
if pif_is_vlan(nwpif):
xs_network_uuids.append(uuid)
else:
xs_network_uuids.insert(0, uuid)
vsctl_argv = []
vsctl_argv += ['# configure xs-network-uuids']
vsctl_argv += ['--', 'br-set-external-id', pif_bridge_name(pif),
'xs-network-uuids', ';'.join(xs_network_uuids)]
return vsctl_argv
#
#
#
class DatapathVswitch(Datapath):
def __init__(self, pif):
Datapath.__init__(self, pif)
self._dp = pif_datapath(pif)
self._ipdev = pif_ipdev_name(pif)
self._bridge_flows = []
if pif_is_vlan(pif) and not self._dp:
raise Error("Unbridged VLAN devices not implemented yet")
log("Configured for Vswitch datapath")
@classmethod
def rewrite(cls):
if not os.path.exists("/var/run/openvswitch/db.sock"):
# ovsdb-server is not running, so we can't update the database.
# Probably we are being called as part of system shutdown. Just
# skip the update, since the external-ids will be updated on the
# next boot anyhow.
return
vsctl_argv = []
for pif in db().get_all_pifs():
pifrec = db().get_pif_record(pif)
if not pif_is_vlan(pif) and pifrec['currently_attached']:
vsctl_argv += set_br_external_ids(pif)
if vsctl_argv != []:
datapath_modify_config(vsctl_argv)
def configure_ipdev(self, cfg):
cfg.write("TYPE=Ethernet\n")
def preconfigure(self, parent):
vsctl_argv = []
extra_ports = []
bridge_flows = []
pifrec = db().get_pif_record(self._pif)
dprec = db().get_pif_record(self._dp)
ipdev = self._ipdev
c,e,f = configure_datapath(self._dp)
bridge = pif_bridge_name(self._pif)
vsctl_argv += c
extra_ports += e
bridge_flows += f
dpname = pif_bridge_name(self._dp)
if pif_is_vlan(self._pif):
# In some cases XAPI may misguidedly leave an instance of
# 'bridge' which should be deleted.
vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
# configure_datapath() set up the underlying datapath bridge.
# Stack a VLAN bridge on top of it.
vsctl_argv += ['--', '--may-exist', 'add-br',
bridge, dpname, pifrec['VLAN']]
vsctl_argv += set_br_external_ids(self._pif)
if ipdev != bridge:
vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
vsctl_argv += datapath_deconfigure_ipdev(ipdev)
vsctl_argv += ["# reconfigure ipdev %s" % ipdev]
vsctl_argv += ['--', 'add-port', bridge, ipdev]
if ipdev != dpname:
vsctl_argv += ['# configure Interface MAC']
vsctl_argv += ['--', 'set', 'Interface', pif_ipdev_name(self._pif),
'MAC=%s' % vsctl_escape(dprec['MAC'])]
self._vsctl_argv = vsctl_argv
self._extra_ports = extra_ports
self._bridge_flows = bridge_flows
def bring_down_existing(self):
# interface-reconfigure is never explicitly called to down a
# bond master. However, when we are called to up a slave it
# is implicit that we are destroying the master. Conversely,
# when we are called to up a bond is is implicit that we are
# taking down the slaves.
#
# This is (only) important in the case where the device being
# implicitly taken down uses DHCP. We need to kill the
# dhclient process, otherwise performing the inverse operation
# later later will fail because ifup will refuse to start a
# duplicate dhclient.
bond_masters = pif_get_bond_masters(self._pif)
for master in bond_masters:
log("action_up: bring down bond master %s" % (pif_netdev_name(master)))
run_command(["/sbin/ifdown", pif_bridge_name(master)])
bond_slaves = pif_get_bond_slaves(self._pif)
for slave in bond_slaves:
log("action_up: bring down bond slave %s" % (pif_netdev_name(slave)))
run_command(["/sbin/ifdown", pif_bridge_name(slave)])
def configure(self):
# Bring up physical devices. ovs-vswitchd initially enables or
# disables bond slaves based on whether carrier is detected
# when they are added, and a network device that is down
# always reports "no carrier".
physical_devices = datapath_get_physical_pifs(self._dp)
if pif_is_bond(self._dp):
brec = db().get_pif_record(self._dp)
bond_mtu = mtu_setting(brec['network'], "PIF", brec['other_config'])
else:
bond_mtu = None
for p in physical_devices:
prec = db().get_pif_record(p)
oc = prec['other_config']
dev = pif_netdev_name(p)
if bond_mtu:
mtu = bond_mtu
else:
mtu = mtu_setting(prec['network'], "PIF", oc)
netdev_up(dev, mtu)
settings, offload = ethtool_settings(oc, PIF_OTHERCONFIG_DEFAULTS)
if len(settings):
run_command(['/sbin/ethtool', '-s', dev] + settings)
if len(offload):
run_command(['/sbin/ethtool', '-K', dev] + offload)
driver = netdev_get_driver_name(dev)
if 'vlan-bug-workaround' in oc:
vlan_bug_workaround = oc['vlan-bug-workaround'] == 'true'
elif driver in NO_VLAN_WORKAROUND_DRIVERS:
vlan_bug_workaround = False
else:
vlan_bug_workaround = netdev_has_vlan_accel(dev)
datapath_modify_config(self._vsctl_argv)
if self._bridge_flows:
ofports = []
physical_devices = datapath_get_physical_pifs(self._dp)
if len(physical_devices) > 1:
for slave in physical_devices:
name = pif_netdev_name(slave)
ofport = vswitchCfgQuery(['get', 'interface', name, 'ofport'])
ofports.append(ofport)
else:
name = pif_netdev_name(self._dp)
ofport = vswitchCfgQuery(['get', 'interface', name, 'ofport'])
ofports.append(ofport)
dpname = pif_bridge_name(self._dp)
for flow in self._bridge_flows:
if flow.find('in_port=%s') != -1 or flow.find('actions=%s') != -1:
for port in ofports:
f = flow % (port.decode())
run_command(['/usr/bin/ovs-ofctl', 'add-flow', dpname, f])
else:
run_command(['/usr/bin/ovs-ofctl', 'add-flow', dpname, flow])
def post(self):
for p in self._extra_ports:
log("action_up: bring up %s" % p)
netdev_up(p)
def bring_down(self):
vsctl_argv = []
dp = self._dp
ipdev = self._ipdev
bridge = pif_bridge_name(dp)
log("deconfigure ipdev %s on %s" % (ipdev,bridge))
vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
vsctl_argv += datapath_deconfigure_ipdev(ipdev)
if pif_is_vlan(self._pif):
# Delete the VLAN bridge.
vsctl_argv += deconfigure_bridge(self._pif)
# If the VLAN's slave is attached, leave datapath setup.
slave = pif_get_vlan_slave(self._pif)
if db().get_pif_record(slave)['currently_attached']:
log("action_down: vlan slave is currently attached")
dp = None
# If the VLAN's slave has other VLANs that are attached, leave datapath setup.
for master in pif_get_vlan_masters(slave):
if master != self._pif and db().get_pif_record(master)['currently_attached']:
log("action_down: vlan slave has other master: %s" % pif_netdev_name(master))
dp = None
# Otherwise, take down the datapath too (fall through)
if dp:
log("action_down: no more masters, bring down slave %s" % bridge)
else:
# Stop here if this PIF has attached VLAN masters.
masters = [db().get_pif_record(m)['VLAN'] for m in pif_get_vlan_masters(self._pif) if db().get_pif_record(m)['currently_attached']]
if len(masters) > 0:
log("Leaving datapath %s up due to currently attached VLAN masters %s" % (bridge, masters))
dp = None
if dp:
vsctl_argv += deconfigure_bridge(dp)
physical_devices = [pif_netdev_name(p) for p in datapath_get_physical_pifs(dp)]
log("action_down: bring down physical devices - %s" % physical_devices)
for p in physical_devices:
netdev_down(p)
datapath_modify_config(vsctl_argv)
#
# utility methods
#
def vswitchCfgQuery(action_args):
cmd = ['%s/usr/bin/ovs-vsctl' % root_prefix(),
'-vconsole:off'] + action_args
output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()
if len(output) == 0 or output[0] == None:
output = ""
else:
output = output[0].strip()
return output

View File

@@ -1,739 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2008,2009 Citrix Systems, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; version 2.1 only. with the special
# exception on linking described in file LICENSE.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
"""Usage:
%(command-name)s <PIF> up
%(command-name)s <PIF> down
%(command-name)s rewrite
%(command-name)s --force <BRIDGE> up
%(command-name)s --force <BRIDGE> down
%(command-name)s --force <BRIDGE> rewrite --device=<INTERFACE> --mac=<MAC-ADDRESS> <CONFIG>
where <PIF> is one of:
--session <SESSION-REF> --pif <PIF-REF>
--pif-uuid <PIF-UUID>
and <CONFIG> is one of:
--mode=dhcp
--mode=static --ip=<IPADDR> --netmask=<NM> [--gateway=<GW>]
Options:
--session A session reference to use to access the xapi DB
--pif A PIF reference within the session.
--pif-uuid The UUID of a PIF.
--force An interface name.
--root-prefix=DIR Use DIR as alternate root directory (for testing).
--no-syslog Write log messages to stderr instead of system log.
"""
# Notes:
# 1. Every pif belongs to exactly one network
# 2. Every network has zero or one pifs
# 3. A network may have an associated bridge, allowing vifs to be attached
# 4. A network may be bridgeless (there's no point having a bridge over a storage pif)
from InterfaceReconfigure import *
import os, sys, getopt
import syslog
import traceback
import re
import random
import syslog
management_pif = None
dbcache_file = "/var/xapi/network.dbcache"
#
# Logging.
#
def log_pif_action(action, pif):
pifrec = db().get_pif_record(pif)
rec = {}
rec['uuid'] = pifrec['uuid']
rec['ip_configuration_mode'] = pifrec['ip_configuration_mode']
rec['action'] = action
rec['pif_netdev_name'] = pif_netdev_name(pif)
rec['message'] = "Bring %(action)s PIF %(uuid)s" % rec
log("%(message)s: %(pif_netdev_name)s configured as %(ip_configuration_mode)s" % rec)
#
# Exceptions.
#
class Usage(Exception):
def __init__(self, msg):
Exception.__init__(self)
self.msg = msg
#
# Boot from Network filesystem or device.
#
def check_allowed(pif):
"""Determine whether interface-reconfigure should be manipulating this PIF.
Used to prevent system PIFs (such as network root disk) from being interfered with.
"""
pifrec = db().get_pif_record(pif)
try:
f = open(root_prefix() + "/proc/ardence")
macline = filter(lambda x: x.startswith("HWaddr:"), f.readlines())
f.close()
if len(macline) == 1:
p = re.compile(".*\s%(MAC)s\s.*" % pifrec, re.IGNORECASE)
if p.match(macline[0]):
log("Skipping PVS device %(device)s (%(MAC)s)" % pifrec)
return False
except IOError:
pass
return True
#
# Bare Network Devices -- network devices without IP configuration
#
def netdev_remap_name(pif, already_renamed=[]):
"""Check whether 'pif' exists and has the correct MAC.
If not, try to find a device with the correct MAC and rename it.
'already_renamed' is used to avoid infinite recursion.
"""
def read1(name):
file = None
try:
file = open(name, 'r')
return file.readline().rstrip('\n')
finally:
if file != None:
file.close()
def get_netdev_mac(device):
try:
return read1("%s/sys/class/net/%s/address" % (root_prefix(), device))
except:
# Probably no such device.
return None
def get_netdev_tx_queue_len(device):
try:
return int(read1("%s/sys/class/net/%s/tx_queue_len" % (root_prefix(), device)))
except:
# Probably no such device.
return None
def get_netdev_by_mac(mac):
for device in os.listdir(root_prefix() + "/sys/class/net"):
dev_mac = get_netdev_mac(device)
if (dev_mac and mac.lower() == dev_mac.lower() and
get_netdev_tx_queue_len(device)):
return device
return None
def rename_netdev(old_name, new_name):
raise Error("Trying to rename %s to %s - This functionality has been removed" % (old_name, new_name))
# log("Changing the name of %s to %s" % (old_name, new_name))
# run_command(['/sbin/ip', 'link', 'set', old_name, 'down'])
# if not run_command(['/sbin/ip', 'link', 'set', old_name, 'name', new_name]):
# raise Error("Could not rename %s to %s" % (old_name, new_name))
pifrec = db().get_pif_record(pif)
device = pifrec['device']
mac = pifrec['MAC']
# Is there a network device named 'device' at all?
device_exists = netdev_exists(device)
if device_exists:
# Yes. Does it have MAC 'mac'?
found_mac = get_netdev_mac(device)
if found_mac and mac.lower() == found_mac.lower():
# Yes, everything checks out the way we want. Nothing to do.
return
else:
log("No network device %s" % device)
# What device has MAC 'mac'?
cur_device = get_netdev_by_mac(mac)
if not cur_device:
log("No network device has MAC %s" % mac)
return
# First rename 'device', if it exists, to get it out of the way
# for 'cur_device' to replace it.
if device_exists:
rename_netdev(device, "dev%d" % random.getrandbits(24))
# Rename 'cur_device' to 'device'.
rename_netdev(cur_device, device)
#
# IP Network Devices -- network devices with IP configuration
#
def ifdown(netdev):
"""Bring down a network interface"""
if not netdev_exists(netdev):
log("ifdown: device %s does not exist, ignoring" % netdev)
return
if not os.path.exists("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), netdev)):
log("ifdown: device %s exists but ifcfg-%s does not" % (netdev,netdev))
run_command(["/sbin/ip", "link", "set", netdev, 'down'])
return
run_command(["/sbin/ifdown", netdev])
def ifup(netdev):
"""Bring up a network interface"""
if not os.path.exists(root_prefix() + "/etc/sysconfig/network-scripts/ifcfg-%s" % netdev):
raise Error("ifup: device %s exists but ifcfg-%s does not" % (netdev,netdev))
d = os.getenv("DHCLIENTARGS","")
if os.path.exists("/etc/firstboot.d/data/firstboot_in_progress"):
os.putenv("DHCLIENTARGS", d + " -T 240 " )
run_command(["/sbin/ifup", netdev])
os.putenv("DHCLIENTARGS", d )
#
#
#
def pif_rename_physical_devices(pif):
if pif_is_tunnel(pif):
return
if pif_is_vlan(pif):
pif = pif_get_vlan_slave(pif)
if pif_is_bond(pif):
pifs = pif_get_bond_slaves(pif)
else:
pifs = [pif]
for pif in pifs:
netdev_remap_name(pif)
#
# IP device configuration
#
def ipdev_configure_static_routes(interface, oc, f):
"""Open a route-<interface> file for static routes.
Opens the static routes configuration file for interface and writes one
line for each route specified in the network's other config "static-routes" value.
E.g. if
interface ( RO): xenbr1
other-config (MRW): static-routes: 172.16.0.0/15/192.168.0.3,172.18.0.0/16/192.168.0.4;...
Then route-xenbr1 should be
172.16.0.0/15 via 192.168.0.3 dev xenbr1
172.18.0.0/16 via 192.168.0.4 dev xenbr1
"""
if 'static-routes' in oc:
# The key is present - extract comma separates entries
lines = oc['static-routes'].split(',')
else:
# The key is not present, i.e. there are no static routes
lines = []
child = ConfigurationFile("%s/etc/sysconfig/network-scripts/route-%s" % (root_prefix(), interface))
child.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
(os.path.basename(child.path()), os.path.basename(sys.argv[0])))
try:
for l in lines:
network, masklen, gateway = l.split('/')
child.write("%s/%s via %s dev %s\n" % (network, masklen, gateway, interface))
f.attach_child(child)
child.close()
except ValueError as e:
log("Error in other-config['static-routes'] format for network %s: %s" % (interface, e))
def ipdev_open_ifcfg(pif):
ipdev = pif_ipdev_name(pif)
log("Writing network configuration for %s" % ipdev)
f = ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), ipdev))
f.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
(os.path.basename(f.path()), os.path.basename(sys.argv[0])))
f.write("XEMANAGED=yes\n")
f.write("DEVICE=%s\n" % ipdev)
f.write("ONBOOT=no\n")
f.write("NOZEROCONF=yes\n")
return f
def ipdev_configure_network(pif, dp):
"""Write the configuration file for a network.
Writes configuration derived from the network object into the relevant
ifcfg file. The configuration file is passed in, but if the network is
bridgeless it will be ifcfg-<interface>, otherwise it will be ifcfg-<bridge>.
This routine may also write ifcfg files of the networks corresponding to other PIFs
in order to maintain consistency.
params:
pif: Opaque_ref of pif
dp: Datapath object
"""
pifrec = db().get_pif_record(pif)
nw = pifrec['network']
nwrec = db().get_network_record(nw)
ipdev = pif_ipdev_name(pif)
f = ipdev_open_ifcfg(pif)
mode = pifrec['ip_configuration_mode']
log("Configuring %s using %s configuration" % (ipdev, mode))
oc = None
if 'other_config' in pifrec:
oc = pifrec['other_config']
dp.configure_ipdev(f)
if pifrec['ip_configuration_mode'] == "DHCP":
f.write("BOOTPROTO=dhcp\n")
f.write("PERSISTENT_DHCLIENT=yes\n")
elif pifrec['ip_configuration_mode'] == "Static":
f.write("BOOTPROTO=none\n")
f.write("NETMASK=%(netmask)s\n" % pifrec)
f.write("IPADDR=%(IP)s\n" % pifrec)
f.write("GATEWAY=%(gateway)s\n" % pifrec)
elif pifrec['ip_configuration_mode'] == "None":
f.write("BOOTPROTO=none\n")
else:
raise Error("Unknown ip-configuration-mode %s" % pifrec['ip_configuration_mode'])
if 'other_config' in nwrec:
settings,offload = ethtool_settings(nwrec['other_config'])
if len(settings):
f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings))
if len(offload):
f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload))
ipdev_configure_static_routes(ipdev, nwrec['other_config'], f)
mtu = mtu_setting(nw, "Network", nwrec['other_config'])
if mtu:
f.write("MTU=%s\n" % mtu)
if 'DNS' in pifrec and pifrec['DNS'] != "":
ServerList = pifrec['DNS'].split(",")
for i in range(len(ServerList)): f.write("DNS%d=%s\n" % (i+1, ServerList[i]))
if oc and 'domain' in oc:
f.write("DOMAIN='%s'\n" % oc['domain'].replace(',', ' '))
# There can be only one DNSDEV and one GATEWAYDEV in /etc/sysconfig/network.
#
# The peerdns pif will be the one with
# pif::other-config:peerdns=true, or the mgmt pif if none have
# this set.
#
# The gateway pif will be the one with
# pif::other-config:defaultroute=true, or the mgmt pif if none
# have this set.
# Work out which pif on this host should be the DNSDEV and which
# should be the GATEWAYDEV
#
# Note: we prune out the bond master pif (if it exists). This is
# because when we are called to bring up an interface with a bond
# master, it is implicit that we should bring down that master.
pifs_on_host = [p for p in db().get_all_pifs() if not p in pif_get_bond_masters(pif)]
# now prune out bond slaves as they are not connected to the IP
# stack and so cannot be used as gateway or DNS devices.
pifs_on_host = [ p for p in pifs_on_host if len(pif_get_bond_masters(p)) == 0]
# loop through all the pifs on this host looking for one with
# other-config:peerdns = true, and one with
# other-config:default-route=true
peerdns_pif = None
defaultroute_pif = None
for __pif in pifs_on_host:
__pifrec = db().get_pif_record(__pif)
__oc = __pifrec['other_config']
if 'peerdns' in __oc and __oc['peerdns'] == 'true':
if peerdns_pif == None:
peerdns_pif = __pif
else:
log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \
(db().get_pif_record(peerdns_pif)['device'], __pifrec['device']))
if 'defaultroute' in __oc and __oc['defaultroute'] == 'true':
if defaultroute_pif == None:
defaultroute_pif = __pif
else:
log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \
(db().get_pif_record(defaultroute_pif)['device'], __pifrec['device']))
# If no pif is explicitly specified then use the mgmt pif for
# peerdns/defaultroute.
if peerdns_pif == None:
peerdns_pif = management_pif
if defaultroute_pif == None:
defaultroute_pif = management_pif
is_dnsdev = peerdns_pif == pif
is_gatewaydev = defaultroute_pif == pif
if is_dnsdev or is_gatewaydev:
fnetwork = ConfigurationFile(root_prefix() + "/etc/sysconfig/network")
for line in fnetwork.readlines():
if is_dnsdev and line.lstrip().startswith('DNSDEV='):
fnetwork.write('DNSDEV=%s\n' % ipdev)
is_dnsdev = False
elif is_gatewaydev and line.lstrip().startswith('GATEWAYDEV='):
fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
is_gatewaydev = False
else:
fnetwork.write(line)
if is_dnsdev:
fnetwork.write('DNSDEV=%s\n' % ipdev)
if is_gatewaydev:
fnetwork.write('GATEWAYDEV=%s\n' % ipdev)
fnetwork.close()
f.attach_child(fnetwork)
return f
#
# Toplevel actions
#
def action_up(pif, force):
pifrec = db().get_pif_record(pif)
ipdev = pif_ipdev_name(pif)
dp = DatapathFactory()(pif)
log("action_up: %s" % ipdev)
f = ipdev_configure_network(pif, dp)
dp.preconfigure(f)
f.close()
pif_rename_physical_devices(pif)
# if we are not forcing the interface up then attempt to tear down
# any existing devices which might interfere with brinign this one
# up.
if not force:
ifdown(ipdev)
dp.bring_down_existing()
try:
f.apply()
dp.configure()
ifup(ipdev)
dp.post()
# Update /etc/issue (which contains the IP address of the management interface)
os.system(root_prefix() + "/sbin/update-issue")
f.commit()
except Error as e:
log("failed to apply changes: %s" % e.msg)
f.revert()
raise
def action_down(pif):
ipdev = pif_ipdev_name(pif)
dp = DatapathFactory()(pif)
log("action_down: %s" % ipdev)
ifdown(ipdev)
dp.bring_down()
def action_rewrite():
DatapathFactory().rewrite()
# This is useful for reconfiguring the mgmt interface after having lost connectivity to the pool master
def action_force_rewrite(bridge, config):
def getUUID():
import subprocess
uuid,_ = subprocess.Popen(['uuidgen'], stdout = subprocess.PIPE).communicate()
return uuid.strip()
# Notes:
# 1. that this assumes the interface is bridged
# 2. If --gateway is given it will make that the default gateway for the host
# extract the configuration
try:
mode = config['mode']
mac = config['mac']
interface = config['device']
except:
raise Usage("Please supply --mode, --mac and --device")
if mode == 'static':
try:
netmask = config['netmask']
ip = config['ip']
except:
raise Usage("Please supply --netmask and --ip")
try:
gateway = config['gateway']
except:
gateway = None
elif mode != 'dhcp':
raise Usage("--mode must be either static or dhcp")
if 'vlan' in config:
is_vlan = True
vlan_slave, vlan_vid = config['vlan'].split('.')
else:
is_vlan = False
if is_vlan:
raise Error("Force rewrite of VLAN not implemented")
log("Configuring %s using %s configuration" % (bridge, mode))
f = ConfigurationFile(root_prefix() + dbcache_file)
pif_uuid = getUUID()
network_uuid = getUUID()
f.write('<?xml version="1.0" ?>\n')
f.write('<xenserver-network-configuration>\n')
f.write('\t<pif ref="OpaqueRef:%s">\n' % pif_uuid)
f.write('\t\t<network>OpaqueRef:%s</network>\n' % network_uuid)
f.write('\t\t<management>True</management>\n')
f.write('\t\t<uuid>%sPif</uuid>\n' % interface)
f.write('\t\t<bond_slave_of>OpaqueRef:NULL</bond_slave_of>\n')
f.write('\t\t<bond_master_of/>\n')
f.write('\t\t<VLAN_slave_of/>\n')
f.write('\t\t<VLAN_master_of>OpaqueRef:NULL</VLAN_master_of>\n')
f.write('\t\t<VLAN>-1</VLAN>\n')
f.write('\t\t<tunnel_access_PIF_of/>\n')
f.write('\t\t<tunnel_transport_PIF_of/>\n')
f.write('\t\t<device>%s</device>\n' % interface)
f.write('\t\t<MAC>%s</MAC>\n' % mac)
f.write('\t\t<other_config/>\n')
if mode == 'dhcp':
f.write('\t\t<ip_configuration_mode>DHCP</ip_configuration_mode>\n')
f.write('\t\t<IP></IP>\n')
f.write('\t\t<netmask></netmask>\n')
f.write('\t\t<gateway></gateway>\n')
f.write('\t\t<DNS></DNS>\n')
elif mode == 'static':
f.write('\t\t<ip_configuration_mode>Static</ip_configuration_mode>\n')
f.write('\t\t<IP>%s</IP>\n' % ip)
f.write('\t\t<netmask>%s</netmask>\n' % netmask)
if gateway is not None:
f.write('\t\t<gateway>%s</gateway>\n' % gateway)
f.write('\t\t<DNS></DNS>\n')
else:
raise Error("Unknown mode %s" % mode)
f.write('\t</pif>\n')
f.write('\t<network ref="OpaqueRef:%s">\n' % network_uuid)
f.write('\t\t<uuid>InitialManagementNetwork</uuid>\n')
f.write('\t\t<PIFs>\n')
f.write('\t\t\t<PIF>OpaqueRef:%s</PIF>\n' % pif_uuid)
f.write('\t\t</PIFs>\n')
f.write('\t\t<bridge>%s</bridge>\n' % bridge)
f.write('\t\t<other_config/>\n')
f.write('\t</network>\n')
f.write('</xenserver-network-configuration>\n')
f.close()
try:
f.apply()
f.commit()
except Error as e:
log("failed to apply changes: %s" % e.msg)
f.revert()
raise
def main(argv=None):
global management_pif
session = None
pif_uuid = None
pif = None
force_interface = None
force_management = False
if argv is None:
argv = sys.argv
try:
try:
shortops = "h"
longops = [ "pif=", "pif-uuid=",
"session=",
"force=",
"force-interface=",
"management",
"mac=", "device=", "mode=", "ip=", "netmask=", "gateway=",
"root-prefix=",
"no-syslog",
"help" ]
arglist, args = getopt.gnu_getopt(argv[1:], shortops, longops)
except getopt.GetoptError as msg:
raise Usage(msg)
force_rewrite_config = {}
for o,a in arglist:
if o == "--pif":
pif = a
elif o == "--pif-uuid":
pif_uuid = a
elif o == "--session":
session = a
elif o == "--force-interface" or o == "--force":
force_interface = a
elif o == "--management":
force_management = True
elif o in ["--mac", "--device", "--mode", "--ip", "--netmask", "--gateway"]:
force_rewrite_config[o[2:]] = a
elif o == "--root-prefix":
set_root_prefix(a)
elif o == "--no-syslog":
set_log_destination("stderr")
elif o == "-h" or o == "--help":
print(__doc__ % {'command-name': os.path.basename(argv[0])})
return 0
if get_log_destination() == "syslog":
syslog.openlog(os.path.basename(argv[0]))
log("Called as " + str.join(" ", argv))
if len(args) < 1:
raise Usage("Required option <action> not present")
if len(args) > 1:
raise Usage("Too many arguments")
action = args[0]
if not action in ["up", "down", "rewrite", "rewrite-configuration"]:
raise Usage("Unknown action \"%s\"" % action)
# backwards compatibility
if action == "rewrite-configuration": action = "rewrite"
if ( session or pif ) and pif_uuid:
raise Usage("--session/--pif and --pif-uuid are mutually exclusive.")
if ( session and not pif ) or ( not session and pif ):
raise Usage("--session and --pif must be used together.")
if force_interface and ( session or pif or pif_uuid ):
raise Usage("--force is mutually exclusive with --session, --pif and --pif-uuid")
if len(force_rewrite_config) and not (force_interface and action == "rewrite"):
raise Usage("\"--force rewrite\" needed for --device, --mode, --ip, --netmask, and --gateway")
if (action == "rewrite") and (pif or pif_uuid ):
raise Usage("rewrite action does not take --pif or --pif-uuid")
global db
if force_interface:
log("Force interface %s %s" % (force_interface, action))
if action == "rewrite":
action_force_rewrite(force_interface, force_rewrite_config)
elif action in ["up", "down"]:
db_init_from_cache(dbcache_file)
pif = db().get_pif_by_bridge(force_interface)
management_pif = db().get_management_pif()
if action == "up":
action_up(pif, True)
elif action == "down":
action_down(pif)
else:
raise Error("Unknown action %s" % action)
else:
db_init_from_xenapi(session)
if pif_uuid:
pif = db().get_pif_by_uuid(pif_uuid)
if action == "rewrite":
action_rewrite()
else:
if not pif:
raise Usage("No PIF given")
if force_management:
# pif is going to be the management pif
management_pif = pif
else:
# pif is not going to be the management pif.
# Search DB cache for pif on same host with management=true
pifrec = db().get_pif_record(pif)
management_pif = db().get_management_pif()
log_pif_action(action, pif)
if not check_allowed(pif):
return 0
if action == "up":
action_up(pif, False)
elif action == "down":
action_down(pif)
else:
raise Error("Unknown action %s" % action)
# Save cache.
db().save(dbcache_file)
except Usage as err:
sys.stderr.write(err.msg + "\n")
sys.stderr.write("For help use --help.\n")
sys.stderr.flush()
return 2
except Error as err:
log(err.msg)
return 1
return 0
if __name__ == "__main__":
rc = 1
try:
rc = main()
except:
ex = sys.exc_info()
err = traceback.format_exception(*ex)
for exline in err:
log(exline)
syslog.closelog()
sys.exit(rc)

View File

@@ -1,331 +0,0 @@
# Copyright (c) 2009,2010,2011,2012,2013 Nicira, Inc.
# Copyright (c) 2007-2011 Citrix Systems Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from XSConsoleLog import *
import os
import socket
import subprocess
vsctl="/usr/bin/ovs-vsctl"
if __name__ == "__main__":
raise Exception("This script is a plugin for xsconsole and cannot run independently")
from XSConsoleStandard import *
class VSwitchService:
service = {}
def __init__(self, name, processname=None):
self.name = name
self.processname = processname
if self.processname == None:
self.processname = name
def version(self):
try:
output = ShellPipe(["service", self.name, "version"]).Stdout()
except StandardError as e:
XSLogError("vswitch version retrieval error: " + str(e))
return "<unknown>"
for line in output:
if self.processname in line:
return line.split()[-1]
return "<unknown>"
def status(self):
try:
output = ShellPipe(["service", self.name, "status"]).Stdout()
except StandardError as e:
XSLogError("vswitch status retrieval error: " + str(e))
return "<unknown>"
if len(output) == 0:
return "<unknown>"
for line in output:
if self.processname not in line:
continue
elif "running" in line:
return "Running"
elif "stop" in line:
return "Stopped"
else:
return "<unknown>"
return "<unknown>"
def restart(self):
try:
ShellPipe(["service", self.name, "restart"]).Call()
except StandardError as e:
XSLogError("vswitch restart error: " + str(e))
@classmethod
def Inst(cls, name, processname=None):
key = name
if processname != None:
key = key + "-" + processname
if name not in cls.service:
cls.service[key] = VSwitchService(name, processname)
return cls.service[key]
class VSwitchConfig:
@staticmethod
def Get(action):
try:
arg = [vsctl, "-vconsole:off"] + action.split()
output = ShellPipe(arg).Stdout()
except StandardError as e:
XSLogError("config retrieval error: " + str(e))
return "<unknown>"
if len(output) == 0:
output = ""
else:
output = output[0].strip()
return output
class VSwitchControllerDialogue(Dialogue):
def __init__(self):
Dialogue.__init__(self)
data=Data.Inst()
self.hostsInPool = 0
self.hostsUpdated = 0
self.xs_version = data.host.software_version.product_version('')
pool = data.GetPoolForThisHost()
if pool is not None:
self.controller = pool.get("vswitch_controller", "")
else:
self.controller = ""
choiceDefs = [
ChoiceDef(Lang("Set pool-wide controller"),
lambda: self.getController()),
ChoiceDef(Lang("Delete pool-wide controller"),
lambda: self.deleteController()),
ChoiceDef(Lang("Resync server controller config"),
lambda: self.syncController()),
# ChoiceDef(Lang("Restart ovs-vswitchd"),
# lambda: self.restartService("vswitch")),
]
self.menu = Menu(self, None, Lang("Configure Open vSwitch"), choiceDefs)
self.ChangeState("INITIAL")
def BuildPane(self):
pane = self.NewPane(DialoguePane(self.parent))
pane.TitleSet(Lang("Configure Open vSwitch"))
pane.AddBox()
def ChangeState(self, inState):
self.state = inState
self.BuildPane()
self.UpdateFields()
def UpdateFields(self):
self.Pane().ResetPosition()
getattr(self, "UpdateFields" + self.state)() # Dispatch method named 'UpdateFields'+self.state
def UpdateFieldsINITIAL(self):
pane = self.Pane()
pane.AddTitleField(Lang("Select an action"))
pane.AddMenuField(self.menu)
pane.AddKeyHelpField( { Lang("<Enter>") : Lang("OK"), Lang("<Esc>") : Lang("Cancel") } )
def UpdateFieldsGETCONTROLLER(self):
pane = self.Pane()
pane.ResetFields()
pane.AddTitleField(Lang("Enter IP address of controller"))
pane.AddInputField(Lang("Address", 16), self.controller, "address")
pane.AddKeyHelpField( { Lang("<Enter>") : Lang("OK"), Lang("<Esc>") : Lang("Exit") } )
if pane.CurrentInput() is None:
pane.InputIndexSet(0)
def HandleKey(self, inKey):
handled = False
if hasattr(self, "HandleKey" + self.state):
handled = getattr(self, "HandleKey" + self.state)(inKey)
if not handled and inKey == 'KEY_ESCAPE':
Layout.Inst().PopDialogue()
handled = True
return handled
def HandleKeyINITIAL(self, inKey):
return self.menu.HandleKey(inKey)
def HandleKeyGETCONTROLLER(self, inKey):
pane = self.Pane()
if pane.CurrentInput() is None:
pane.InputIndexSet(0)
if inKey == 'KEY_ENTER':
inputValues = pane.GetFieldValues()
self.controller = inputValues['address']
Layout.Inst().PopDialogue()
# Make sure the controller is specified as a valid dotted quad
try:
socket.inet_aton(self.controller)
except socket.error:
Layout.Inst().PushDialogue(InfoDialogue(Lang("Please enter in dotted quad format")))
return True
Layout.Inst().TransientBanner(Lang("Setting controller..."))
try:
self.SetController(self.controller)
Layout.Inst().PushDialogue(InfoDialogue(Lang("Setting controller successful")))
except Exception as e:
Layout.Inst().PushDialogue(InfoDialogue(Lang("Setting controller failed")))
self.ChangeState("INITIAL")
return True
else:
return pane.CurrentInput().HandleKey(inKey)
def restartService(self, name):
s = VSwitchService.Inst(name)
s.restart()
Layout.Inst().PopDialogue()
def getController(self):
self.ChangeState("GETCONTROLLER")
self.Pane().InputIndexSet(0)
def deleteController(self):
self.controller = ""
Layout.Inst().PopDialogue()
Layout.Inst().TransientBanner(Lang("Deleting controller..."))
try:
self.SetController(None)
Layout.Inst().PushDialogue(InfoDialogue(Lang("Controller deletion successful")))
except Exception as e:
Layout.Inst().PushDialogue(InfoDialogue(Lang("Controller deletion failed")))
def syncController(self):
Layout.Inst().PopDialogue()
Layout.Inst().TransientBanner(Lang("Resyncing controller setting..."))
try:
Task.Sync(lambda s: self._updateThisServer(s))
Layout.Inst().PushDialogue(InfoDialogue(Lang("Resyncing controller config successful")))
except Exception as e:
Layout.Inst().PushDialogue(InfoDialogue(Lang("Resyncing controller config failed")))
def SetController(self, ip):
self.hostsInPool = 0
self.hostsUpdated = 0
Task.Sync(lambda s: self._modifyPoolConfig(s, ip or ""))
# Should be done asynchronously, maybe with an external script?
Task.Sync(lambda s: self._updateActiveServers(s))
def _modifyPoolConfig(self, session, value):
"""Modify pool configuration.
If value == "" then delete configuration, otherwise set to value.
"""
pools = session.xenapi.pool.get_all()
# We assume there is only ever one pool...
if len(pools) == 0:
XSLogFatal(Lang("No pool found for host."))
return
if len(pools) > 1:
XSLogFatal(Lang("More than one pool for host."))
return
session.xenapi.pool.set_vswitch_controller(value)
Data.Inst().Update()
def _updateActiveServers(self, session):
hosts = session.xenapi.host.get_all()
self.hostsUpdated = 0
self.hostsInPool = len(hosts)
self.UpdateFields()
for host in hosts:
Layout.Inst().TransientBanner("Updating host %d out of %d"
% (self.hostsUpdated + 1, self.hostsInPool))
session.xenapi.host.call_plugin(host, "openvswitch-cfg-update", "update", {})
self.hostsUpdated = self.hostsUpdated + 1
def _updateThisServer(self, session):
data = Data.Inst()
host = data.host.opaqueref()
session.xenapi.host.call_plugin(host, "openvswitch-cfg-update", "update", {})
class XSFeatureVSwitch:
@classmethod
def StatusUpdateHandler(cls, inPane):
data = Data.Inst()
xs_version = data.host.software_version.product_version('')
inPane.AddTitleField(Lang("Open vSwitch"))
inPane.NewLine()
inPane.AddStatusField(Lang("Version", 20),
VSwitchService.Inst("openvswitch", "ovs-vswitchd").version())
inPane.NewLine()
pool = data.GetPoolForThisHost()
if pool is not None:
dbController = pool.get("vswitch_controller", "")
else:
dbController = ""
if dbController == "":
dbController = Lang("<None>")
inPane.AddStatusField(Lang("Controller (config)", 20), dbController)
controller = VSwitchConfig.Get("get-manager")
if controller == "":
controller = Lang("<None>")
elif controller[0:4] == "ssl:":
controller = controller.split(':')[1]
inPane.AddStatusField(Lang("Controller (in-use)", 20), controller)
inPane.NewLine()
inPane.AddStatusField(Lang("ovs-vswitchd status", 20),
VSwitchService.Inst("openvswitch", "ovs-vswitchd").status())
inPane.AddStatusField(Lang("ovsdb-server status", 20),
VSwitchService.Inst("openvswitch", "ovsdb-server").status())
inPane.AddKeyHelpField( {
Lang("<Enter>") : Lang("Reconfigure"),
Lang("<F5>") : Lang("Refresh")
})
@classmethod
def ActivateHandler(cls):
DialogueUtils.AuthenticatedOnly(lambda: Layout.Inst().PushDialogue(VSwitchControllerDialogue()))
def Register(self):
Importer.RegisterNamedPlugIn(
self,
'VSwitch', # Key of this plugin for replacement, etc.
{
'menuname' : 'MENU_NETWORK',
'menupriority' : 800,
'menutext' : Lang('Open vSwitch') ,
'statusupdatehandler' : self.StatusUpdateHandler,
'activatehandler' : self.ActivateHandler
}
)
# Register this plugin when module is imported, IFF vswitchd is running
if os.path.exists('/var/run/openvswitch/ovs-vswitchd.pid'):
XSFeatureVSwitch().Register()

View File

@@ -1,404 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2009, 2010, 2011, 2012, 2013, 2020 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.
# A daemon to monitor the external_ids columns of the Bridge and
# Interface OVSDB tables for changes that require interrogating XAPI.
# Its responsibilities include:
#
# - Set the "bridge-id" key in the Bridge table.
# - Set the "iface-id" key in the Interface table.
# - Set the fail-mode on internal bridges.
import argparse
import os
import sys
import time
import XenAPI
import ovs.daemon
import ovs.db.idl
import ovs.dirs
import ovs.unixctl
import ovs.unixctl.server
vlog = ovs.vlog.Vlog("ovs-xapi-sync")
session = None
flush_cache = False
exiting = False
xapi_down = False
def unixctl_exit(conn, unused_argv, unused_aux):
global exiting
exiting = True
conn.reply(None)
def unixctl_flush_cache(conn, unused_argv, unused_aux):
global flush_cache
flush_cache = True
conn.reply(None)
# Set up a session to interact with XAPI.
#
# On system start-up, OVS comes up before XAPI, so we can't log into the
# session until later. Try to do this on-demand, since we won't
# actually do anything interesting until XAPI is up.
def init_session():
global session
if session is not None:
return True
try:
session = XenAPI.xapi_local()
session.xenapi.login_with_password("", "")
except XenAPI.Failure as e:
session = None
vlog.warn("Couldn't login to XAPI (%s)" % e)
return False
return True
def get_network_by_bridge(br_name):
if not init_session():
vlog.warn("Failed to get bridge id %s because"
" XAPI session could not be initialized" % br_name)
return None
recs = session.xenapi.network.get_all_records_where(
'field "bridge"="%s"' % br_name)
if len(recs) > 0:
return next(iter(recs.values()))
return None
# There are possibilities when multiple xs-network-uuids are set for a bridge.
# In cases like that, we should choose the bridge-id associated with the bridge
# name.
def get_single_bridge_id(bridge_ids, br_name, default=None):
global xapi_down
rec = get_network_by_bridge(br_name)
if rec and rec['uuid'] in bridge_ids:
return rec['uuid']
vlog.warn("Failed to get a single bridge id from Xapi.")
xapi_down = True
return default
# By default, the "bridge-id" external id in the Bridge table is the
# same as "xs-network-uuids". This may be overridden by defining a
# "nicira-bridge-id" key in the "other_config" field of the network
# record of XAPI. If nicira-bridge-id is undefined returns default.
# On error returns None.
def get_bridge_id(br_name, default=None):
rec = get_network_by_bridge(br_name)
if rec:
return rec['other_config'].get('nicira-bridge-id', default)
return None
# By default, the "iface-id" external id in the Interface table is the
# same as "xs-vif-uuid". This may be overridden by defining a
# "nicira-iface-id" key in the "other_config" field of the VIF
# record of XAPI.
def get_iface_id(if_name, xs_vif_uuid):
if not if_name.startswith("vif") and not if_name.startswith("tap"):
# Treat whatever was passed into 'xs_vif_uuid' as a default
# value for non-VIFs.
return xs_vif_uuid
if not init_session():
vlog.warn("Failed to get interface id %s because"
" XAPI session could not be initialized" % if_name)
return xs_vif_uuid
try:
vif = session.xenapi.VIF.get_by_uuid(xs_vif_uuid)
rec = session.xenapi.VIF.get_record(vif)
return rec['other_config'].get('nicira-iface-id', xs_vif_uuid)
except XenAPI.Failure:
vlog.warn("Could not find XAPI entry for VIF %s" % if_name)
return xs_vif_uuid
# By default, the "vm-id" external id in the Interface table is the
# same as "xs-vm-uuid". This may be overridden by defining a
# "nicira-vm-id" key in the "other_config" field of the VM
# record of XAPI.
def get_vm_id(if_name, xs_vm_uuid):
if not if_name.startswith("vif") and not if_name.startswith("tap"):
# Treat whatever was passed into 'xs_vm_uuid' as a default
# value for non-VIFs.
return xs_vm_uuid
if not init_session():
vlog.warn("Failed to get vm id for interface id %s because"
" XAPI session could not be initialized" % if_name)
return xs_vm_uuid
try:
vm = session.xenapi.VM.get_by_uuid(xs_vm_uuid)
rec = session.xenapi.VM.get_record(vm)
return rec['other_config'].get('nicira-vm-id', xs_vm_uuid)
except XenAPI.Failure:
vlog.warn("Could not find XAPI entry for VIF %s" % if_name)
return xs_vm_uuid
def set_or_delete(d, key, value):
if value is None:
if key in d:
del d[key]
return True
else:
if d.get(key) != value:
d[key] = value
return True
return False
def set_external_id(row, key, value):
row.verify("external_ids")
external_ids = row.external_ids
if set_or_delete(external_ids, key, value):
row.external_ids = external_ids
# XenServer does not call interface-reconfigure on internal networks,
# which is where the fail-mode would normally be set.
def update_fail_mode(row):
rec = get_network_by_bridge(row.name)
if not rec:
return
fail_mode = rec['other_config'].get('vswitch-controller-fail-mode')
if not fail_mode:
pools = session.xenapi.pool.get_all()
if len(pools) == 1:
prec = session.xenapi.pool.get_record(pools[0])
fail_mode = prec['other_config'].get(
'vswitch-controller-fail-mode')
if fail_mode not in ['standalone', 'secure']:
fail_mode = 'standalone'
row.verify("fail_mode")
if row.fail_mode != fail_mode:
row.fail_mode = fail_mode
def update_in_band_mgmt(row):
rec = get_network_by_bridge(row.name)
if not rec:
return
dib = rec['other_config'].get('vswitch-disable-in-band')
row.verify("other_config")
other_config = row.other_config
if dib and dib not in ['true', 'false']:
vlog.warn('"%s" isn\'t a valid setting for '
"other_config:disable-in-band on %s" % (dib, row.name))
elif set_or_delete(other_config, 'disable-in-band', dib):
row.other_config = other_config
def main():
global flush_cache, xapi_down
parser = argparse.ArgumentParser()
parser.add_argument("database", metavar="DATABASE",
help="A socket on which ovsdb-server is listening.")
parser.add_argument("--root-prefix", metavar="DIR", default='',
help="Use DIR as alternate root directory"
" (for testing).")
ovs.vlog.add_args(parser)
ovs.daemon.add_args(parser)
args = parser.parse_args()
ovs.vlog.handle_args(args)
ovs.daemon.handle_args(args)
remote = args.database
schema_helper = ovs.db.idl.SchemaHelper()
schema_helper.register_columns("Bridge", ["name", "external_ids",
"other_config", "fail_mode"])
schema_helper.register_columns("Interface", ["name", "external_ids"])
idl = ovs.db.idl.Idl(remote, schema_helper)
ovs.daemon.daemonize()
ovs.unixctl.command_register("exit", "", 0, 0, unixctl_exit, None)
ovs.unixctl.command_register("flush-cache", "", 0, 0, unixctl_flush_cache,
None)
error, unixctl_server = ovs.unixctl.server.UnixctlServer.create(None)
if error:
ovs.util.ovs_fatal(error, "could not create unixctl server", vlog)
# This daemon is usually started before XAPI, but to complete our
# tasks, we need it. Wait here until it's up.
cookie_file = args.root_prefix + "/var/run/xapi_init_complete.cookie"
while not os.path.exists(cookie_file):
time.sleep(1)
bridges = {} # Map from bridge name to nicira-bridge-id
iface_ids = {} # Map from xs-vif-uuid to iface-id
vm_ids = {} # Map from xs-vm-uuid to vm-id
seqno = idl.change_seqno # Sequence number when we last processed the db
while True:
unixctl_server.run()
if exiting:
break
idl.run()
if not xapi_down and not flush_cache and seqno == idl.change_seqno:
poller = ovs.poller.Poller()
unixctl_server.wait(poller)
idl.wait(poller)
poller.block()
continue
if xapi_down:
vlog.warn("Xapi is probably down. Retry again after a second.")
time.sleep(1)
xapi_down = False
if flush_cache:
vlog.info("Flushing cache as the result of unixctl.")
bridges = {}
iface_ids = {}
vm_ids = {}
flush_cache = False
seqno = idl.change_seqno
txn = ovs.db.idl.Transaction(idl)
new_bridges = {}
for row in idl.tables["Bridge"].rows.values():
bridge_id = bridges.get(row.name)
if bridge_id is None:
# Configure the new bridge.
update_fail_mode(row)
update_in_band_mgmt(row)
# Get the correct bridge_id, if we can.
bridge_id = get_bridge_id(row.name)
if bridge_id is None:
xs_network_uuids = row.external_ids.get("xs-network-uuids")
if xs_network_uuids:
bridge_ids = xs_network_uuids.split(";")
if len(bridge_ids) == 1:
bridge_id = bridge_ids[0]
else:
bridge_id = get_single_bridge_id(bridge_ids,
row.name)
set_external_id(row, "bridge-id", bridge_id)
if bridge_id is not None:
new_bridges[row.name] = bridge_id
bridges = new_bridges
iface_by_name = {}
for row in idl.tables["Interface"].rows.values():
iface_by_name[row.name] = row
new_iface_ids = {}
new_vm_ids = {}
for row in idl.tables["Interface"].rows.values():
# Match up paired vif and tap devices.
if row.name.startswith("vif"):
vif = row
tap = iface_by_name.get("tap%s" % row.name[3:])
elif row.name.startswith("tap"):
tap = row
vif = iface_by_name.get("vif%s" % row.name[3:])
else:
tap = vif = None
# Several tap external-ids need to be copied from the vif.
if row == tap and vif:
keys = ["attached-mac",
"xs-network-uuid",
"xs-vif-uuid",
"xs-vm-uuid"]
for k in keys:
set_external_id(row, k, vif.external_ids.get(k))
# Map from xs-vif-uuid to iface-id.
#
# (A tap's xs-vif-uuid comes from its vif. That falls out
# naturally from the copy loop above.)
xvu = row.external_ids.get("xs-vif-uuid")
if xvu:
iface_id = (new_iface_ids.get(xvu)
or iface_ids.get(xvu)
or get_iface_id(row.name, xvu))
new_iface_ids[xvu] = iface_id
else:
# No xs-vif-uuid therefore no iface-id.
iface_id = None
set_external_id(row, "iface-id", iface_id)
# Map from xs-vm-uuid to vm-id.
xvmu = row.external_ids.get("xs-vm-uuid")
if xvmu:
vm_id = (new_vm_ids.get(xvmu)
or vm_ids.get(xvmu)
or get_vm_id(row.name, xvmu))
new_vm_ids[xvmu] = vm_id
else:
vm_id = None
set_external_id(row, "vm-id", vm_id)
# When there's a vif and a tap, the tap is active (used for
# traffic). When there's just a vif, the vif is active.
#
# A tap on its own shouldn't happen, and we don't know
# anything about other kinds of devices, so we don't use
# an iface-status for those devices at all.
if vif and tap:
set_external_id(tap, "iface-status", "active")
set_external_id(vif, "iface-status", "inactive")
elif vif:
set_external_id(vif, "iface-status", "active")
else:
set_external_id(row, "iface-status", None)
iface_ids = new_iface_ids
vm_ids = new_vm_ids
txn.add_comment("ovs-xapi-sync: Updating records from XAPI")
txn.commit_block()
unixctl_server.close()
idl.close()
if __name__ == '__main__':
try:
main()
except SystemExit:
# Let system.exit() calls complete normally
raise
except:
vlog.exception("traceback")
sys.exit(ovs.daemon.RESTART_EXIT_CODE)

View File

@@ -1,24 +0,0 @@
### Configuration options for openvswitch
# Copyright (C) 2009, 2010, 2011 Nicira, Inc.
# FORCE_COREFILES: If 'yes' then core files will be enabled.
# FORCE_COREFILES=yes
# OVSDB_SERVER_PRIORITY: "nice" priority at which to run ovsdb-server.
#
# OVSDB_SERVER_PRIORITY=-10
# VSWITCHD_PRIORITY: "nice" priority at which to run ovs-vswitchd.
# VSWITCHD_PRIORITY=-10
# VSWITCHD_MLOCKALL: Whether to pass ovs-vswitchd the --mlockall option.
# This option should be set to "yes" or "no". The default is "yes".
# Enabling this option can avoid networking interruptions due to
# system memory pressure in extraordinary situations, such as multiple
# concurrent VM import operations.
# VSWITCHD_MLOCKALL=yes
# OVS_CTL_OPTS: Extra options to pass to ovs-ctl. This is, for example,
# a suitable place to specify --ovs-vswitchd-wrapper=valgrind.
# OVS_CTL_OPTS=