Retire Tripleo: remove repo content

TripleO project is retiring
- https://review.opendev.org/c/openstack/governance/+/905145

this commit remove the content of this project repo

Change-Id: I9da248ee774c038c99bf452898ac8658aa337aad
This commit is contained in:
Ghanshyam Mann 2024-02-24 11:32:07 -08:00
parent 27915c67c8
commit 6ed93f8448
136 changed files with 8 additions and 24569 deletions

View File

@ -1,7 +0,0 @@
[run]
branch = True
source = os_net_config
omit = os_net_config/tests/*
[report]
ignore_errors = True

53
.gitignore vendored
View File

@ -1,53 +0,0 @@
*.py[cod]
# C extensions
*.so
# Packages
*.egg*
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
.stestr/
cover
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Complexity
output/*.html
output/*/index.html
# Sphinx
doc/build
# pbr generates these
AUTHORS
ChangeLog
# Editors
*~
.*.swp
# Visual Studio Code
.vscode

View File

@ -1,3 +0,0 @@
# Format is:
# <preferred e-mail> <other e-mail 1>
# <preferred e-mail> <other e-mail 2>

View File

@ -1,4 +0,0 @@
[DEFAULT]
test_path=./os_net_config/tests
top_dir=./

View File

@ -1,16 +0,0 @@
If you would like to contribute to the development of OpenStack,
you must follow the steps in this page:
https://docs.openstack.org/infra/manual/developers.html
Once those steps have been completed, changes to OpenStack
should be submitted for review via the Gerrit tool, following
the workflow documented at:
https://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.
Bugs should be filed on Launchpad, not GitHub:
https://bugs.launchpad.net/os-net-config

View File

@ -1,4 +0,0 @@
os-net-config Style Commandments
================================
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

175
LICENSE
View File

@ -1,175 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

View File

@ -1,36 +1,10 @@
=============
os-net-config
=============
This project is no longer maintained.
Team and repository tags
------------------------
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
.. image:: https://governance.openstack.org/tc/badges/os-net-config.svg
:target: https://governance.openstack.org/tc/reference/tags/index.html
Overview
--------
``os-net-config`` is a host network configuration tool which supports multiple
backend configuration providers.
* Documentation: https://docs.openstack.org/os-net-config/latest
* Source: https://opendev.org/openstack/os-net-config
* Bugs: https://bugs.launchpad.net/os-net-config
* Release Notes: https://docs.openstack.org/releasenotes/os-net-config
* Free software: Apache License (2.0)
Features
--------
The core aim of this project is to allow fine grained (but extendable)
configuration of the networking parameters for a network host. The
project consists of:
* A CLI (os-net-config) which provides configuration via a YAML or JSON
file formats. By default os-net-config uses a YAML config file located
at /etc/os-net-config/config.yaml. This can be customized via the
--config-file CLI option.
* A python library which provides configuration via an object model.
For any further questions, please email
openstack-discuss@lists.openstack.org or join #openstack-dev on
OFTC.

View File

@ -1 +0,0 @@
[python: **.py]

View File

@ -1,9 +0,0 @@
# This is a cross-platform list tracking distribution packages needed for
# install and tests;
# see https://docs.openstack.org/infra/bindep/ for additional information.
ethtool
nmstate [platform:rpm]
NetworkManager-ovs [platform:rpm]
python3-libnmstate [platform:rpm]
nmstate-libs [platform:rpm]

View File

@ -1,2 +0,0 @@
sphinx>=2.0.0,!=2.1.0 # BSD
openstackdocstheme>=2.2.1 # Apache-2.0

View File

@ -1,81 +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.
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
#'sphinx.ext.intersphinx',
'openstackdocstheme'
]
# openstackdocstheme options
openstackdocs_repo_name = 'openstack/os-net-config'
openstackdocs_auto_name = False
openstackdocs_bug_project = 'os-net-config'
openstackdocs_bug_tag = ''
html_theme = 'openstackdocs'
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'os-net-config'
copyright = '2013, OpenStack Foundation'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'native'
# -- Options for HTML output --------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
('index',
'%s.tex' % project,
'%s Documentation' % project,
'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.
#intersphinx_mapping = {'http://docs.python.org/': None}

View File

@ -1,487 +0,0 @@
===============================
Network configuration reference
===============================
This section describes the supported ``/etc/os-net-config/config.yaml`` YAML
format and how they map to networking backend providers. The root element is
a ``network_config`` attribute, and the value is an array of dicts entries
describing the physical and virtual interfaces to configure. Each interface
entry has a mandatory ``type`` attribute, and the value determines what other
attributes are supported for that type.
.. _common-attributes:
Common attributes
-----------------
The following attributes are used in many types. See :ref:`multiple-nics` for
examples.
addresses
=========
A list of ``ip_netmask`` entries to specify the network addresses for this
interface. For example:
.. code-block:: yaml
addresses:
- ip_netmask: 192.0.2.2/24
- ip_netmask: 192.0.3.2/32
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``BOOTPROTO=static`` and populates ``IPADDR`` and ``NETMASK, followed by
``IPADDR<i>``, ``NETMASK<i>`` for subsequent addresses with ``<i>`` incrementing
from ``1``.
defroute
========
A boolean which defaults to ``true``. When ``false`` the default route given by an
IPV4 DHCP server will be ignored.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``DEFROUTE=no`` when set to ``false``.
dhclient_args
=============
Arguments to append to the call to the dhclient command, as a single string.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``DHCLIENTARGS`` to the supplied value
dns_servers
===========
A list of DNS servers (maximum of 2) to use for name resolution.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``DNS1``, ``DNS2`` to support up to 2 DNS resolvers.
domain
======
A string or a list of strings containing DNS search domains
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``DOMAIN`` containing all values as a space-separated list.
mtu
===
Maximum transmission unit for this interface.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``MTU`` to the specified value. If unspecified the default is ``1500``.
name
====
This is the name for the interface which is one of:
- the name of existing physical interface (NIC)
- the identifier from the mapping file which maps to a NIC
- the desired name of a bridge or bond
- a numbered identifier ``nic<i>`` starting with ``1`` for each active NIC:
``nic1``, ``nic2`` etc
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
When the name is an identifier in the mapping file or a ``nic<i>``
identifier, the actual name used will be the mapping value, not the
identifier.
The name format of a physical interfaces depends on ``biosdevname`` or
``net.ifnames`` sysctl settings or udev rules for persistent names. Names
will begin with ``eth`` if both sysctl settings are disabled and there are no
udev rules. The sort order used to allocate ``nic<i>`` identifiers are:
- Embedded interfaces first (``em<j>``, ``eth<j>``, ``eno<j>``) ordered
alphanumerically
- Then, other active NICs ordered alphanumerically
Each interface definition is written to
``/etc/sysconfig/network-scripts/ifcfg-<name>`` and the first value in the
file is ``DEVICE=<name>``.
nm_controlled
=============
Boolean whether this interface is managed by `NetworkManager`_, defaults to
``false``.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``NM_CONTROLLED=yes`` or ``NM_CONTROLLED=no``
onboot
======
Boolean which determines whether to enable the interface on machine boot,
defaults to ``true``.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``ONBOOT=yes`` or ``ONBOOT=no``.
primary
=======
In the ``members`` entries for a bond or bridge this may be set to ``true``
for the primary interface. This results in the bond or bridge inheriting the MAC
address of the primary interface.
routes
======
A list of route entries for this interface containing attributes:
- ``default`` Boolean whether this is the default route for this interface
- ``ip_netmask`` or ``destination`` Destination network address when ``default``
is ``false``
- ``next_hop`` or ``nexthop`` Gateway address for route destination
Other supported attributes include:
- ``route_table`` The table ID or name to add this route to
- ``route_options`` String of extra options to append to the end of the route
For example:
.. code-block:: yaml
routes:
- default: true
next_hop: 198.51.100.1
- ip_netmask: 192.0.2.2/24
next_hop: 203.0.113.254
route_table: 2
route_options: metric 100
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
A routes file for each interface definition is written to
``/etc/sysconfig/network-scripts/route-<name>``.
rules
=====
A list of commented route rules, for example:
.. code-block:: yaml
rules:
- rule: "iif em1 table 200"
comment: "Route incoming traffic to em1 with table 200"
- rule: "from 192.0.2.0/24 table 200"
comment: "Route all traffic from 192.0.2.0/24 with table 200"
- rule: "add blackhole from 172.19.40.0/24 table 200"
- rule: "add unreachable iif em1 from 192.168.1.0/24"
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Each interface is iterated in order and its rules are compared to existing
rules then converged by running ``ip rule del <rule>`` and ``ip rule add
<rule>``.
use_dhcp
========
Boolean for whether to use DHCP for the IPv4 boot protocol.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``PEERDNS=no`` when ``false``.
use_dhcpv6
==========
Boolean for whether to use DHCP for the IPv6 boot protocol.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``DHCPV6C=yes`` when ``true``.
..
Undocumented:
rules
nic_mapping
persist_mapping
.. _ovs-attributes:
Open vSwitch attributes
-----------------------
The `Open vSwitch`_ types support some or all of these attributes:
.. _ovs-options:
ovs_options
===========
String of other options to pass to Open vSwitch for this bond or bridge.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets the ``OVS_OPTIONS`` value.
.. _ovs-extra:
ovs_extra
=========
A list of extra options to pass to Open vSwitch.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Will set the ``OVS_EXTRA`` value with all the provided values.
ovs_fail_mode
=============
Failure mode for a bridge, defaults to ``standard``, can also be set to ``secure``
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Will be appended to the ``OVS_OPTIONS`` value and the concatenated list of
``OVS_EXTRA`` values.
type: interface
---------------
Configures a physical NIC. See :ref:`multiple-nics` for examples. All of the
:ref:`common-attributes` can be used with this type along with the following
attributes:
ethtool_opts
============
Device-specific options supported by `ethtool`_.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``ETHTOOL_OPTS`` to the value.
hotplug
=======
A boolean for whether to activate the device when it is plugged in.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``HOTPLUG=yes`` or ``HOTPLUG=no``
linkdelay
=========
Integer number of seconds to wait for link negotiation before configuring
the device.
ifcfg implementation
^^^^^^^^^^^^^^^^^^^^
Sets ``LINKDELAY`` to the delay value.
type: ovs_bridge
----------------
Configures an `Open vSwitch`_ bridge. See :ref:`control-plane-bridge` for an
example. All of the :ref:`common-attributes` and :ref:`ovs-attributes` can be
used with this type. The ``members`` attribute contains a list of entries for
interfaces to bridge typically of ``type``:
- ``interface``
- ``linux_bond``
- ``ovs_bond``
- ``vlan``
- other Open vSwitch internal interfaces
ifcfg implementation
====================
Values ``DEVICETYPE=ovs`` and ``TYPE=OVSBridge`` are set. When ``use_dhcp``
or ``use_dhcpv6`` is ``true``, ``OVSBOOTPROTO=dhcp`` is set and
``OVSDHCPINTERFACES`` is populated.
type: ovs_bond
--------------
Configures an `Open vSwitch`_ bond. See :ref:`ovs-bond` for an example. All
of the :ref:`common-attributes` and :ref:`ovs-attributes` can be used with
this type. The ``members`` attribute contains a list of entries for
interfaces to be bonded.
ifcfg implementation
====================
Values ``DEVICETYPE=ovs`` and ``TYPE=OVSBridge`` are set. When ``use_dhcp``
or ``use_dhcpv6`` is ``true``, ``OVSBOOTPROTO=dhcp`` is set and
``OVSDHCPINTERFACES`` is populated.
type: vlan
----------
Configures VLAN tagging for one VLAN. See :ref:`bonds-with-vlans` for an
example. :ref:`common-attributes` are supported but generally only ``mtu``,
``addresses`` or ``routes`` are used.
Other attributes for ``vlan`` are:
device
======
The ``name`` of an existing interface entry, which will typically be of
``type: interface``, ``type: ovs_bond``, or ``type: linux_bond``. Usually
``device`` is only used when the VLAN is not part of an ``ovs_bridge``. A
VLAN on an ``ovs_bridge`` is part of the ``members`` list for the bridge,
where a Linux VLAN is associated with an ``interface`` or ``linux_bond``
using the ``device`` parameter.
vlan_id
=======
The VLAN ID to tag when passing through the ``device`` interface.
ifcfg implementation
====================
Sets ``VLAN=yes`` and ``PHYSDEV`` to the ``device`` value.
type: linux_bridge
------------------
Configures a `Linux bridge`_. See :ref:`linux-bridge` for an example. All of
the :ref:`common-attributes` can be used with this type. The ``members``
attribute contains a list of entries for interfaces to bridge.
ifcfg implementation
====================
Sets ``TYPE=Bridge`` and ``DELAY=0``. The MAC address of the ``members``
interface which has ``primary: true`` will be used for the ``MACADDR`` value.
type: linux_bond
----------------
Configures a `Linux bond`_. See :ref:`bonds-vlans-dpdk` for an example. All
of the :ref:`common-attributes` can be used with this type. The ``members``
attribute contains a list of entries for interfaces to be bonded.
Extra bonding options are specified in the ``bonding_options`` string.
ifcfg implementation
====================
The MAC address of the ``members`` interface which has ``primary: true`` will
be used for the ``MACADDR`` value. ``BONDING_OPTS`` will contain the value of the
``bonding_options`` attribute.
type: ovs_user_bridge
---------------------
Configures an `Open vSwitch`_ bridge where the members are user ports. This
is generally used to set up `DPDK vHost User Ports`_. See
:ref:`bonds-vlans-dpdk` for an example. All of the :ref:`common-attributes`
and :ref:`ovs-attributes` can be used with this type. The ``members``
attribute usually contains a single ``type: ovs_dpdk_bond`` entry.
ifcfg implementation
====================
Values ``DEVICETYPE=ovs`` and ``TYPE=OVSUserBridge`` are set. When ``use_dhcp``
or ``use_dhcpv6`` is ``true``, ``OVSBOOTPROTO=dhcp`` is set and
``OVSDHCPINTERFACES`` is populated.
Each ``members`` interface also has ``OVS_BRIDGE`` set, as well as other
values depending on the type of the member.
type: ovs_dpdk_bond
-------------------
Configures an `Open vSwitch`_ bond for binding DPDK ports. See
:ref:`bonds-vlans-dpdk` for an example. All of the :ref:`common-attributes`
and :ref:`ovs-attributes` can be used with this type. The ``members``
attribute contains a list of ``type: ovs_dpdk_port`` ports to be bonded. The
value for attribute ``rx_queue`` will determine the RX queue length.
ifcfg implementation
====================
Values ``DEVICETYPE=ovs``, ``TYPE=OVSDPDKBond``, and ``RX_QUEUE`` are set.
``BOND_IFACES`` is populated with the ``name`` of all members. ``OVS_EXTRA``
is extended with a ``set Interface...`` directive for each member.
type: ovs_dpdk_port
-------------------
Creates an Open vSwitch DPDK port, usually in the ``members`` of a ``type:
ovs_dpdk_bond`` bond interface. See :ref:`bonds-vlans-dpdk` for an example.
All of the :ref:`common-attributes` and :ref:`ovs-attributes` can be used
with this type. Each port must have a ``members`` list with a single
interface entry. A port can have its own ``rx_queue`` specifed. The
``driver`` attribute can override the default kernel driver module of
``vfio-pci``.
ifcfg implementation
====================
Values ``DEVICETYPE=ovs`` and ``TYPE=OVSDPDKPort``, and ``RX_QUEUE`` are set.
``OVS_EXTRA`` is extended with a ``set Interface...`` directive for the one
``members`` interface.
..
Undocumented types:
route_table
route_rule
team
ivs_bridge
ivs_interface
nfvswitch_bridge
nfvswitch_internal
ovs_tunnel
ovs_patch_port
ib_interface
ib_child_interface
vpp_interface
vpp_bond
contrail_vrouter
contrail_vrouter_dpdk
sriov_pf
sriov_vf
linux_tap
.. _NetworkManager: https://en.wikipedia.org/wiki/NetworkManager
.. _ethtool: https://en.wikipedia.org/wiki/Ethtool
.. _Open vSwitch: https://www.openvswitch.org/
.. _Linux bridge: https://wiki.linuxfoundation.org/networking/bridge
.. _Linux bond: https://wiki.linuxfoundation.org/networking/bonding
.. _DPDK vHost User Ports: https://docs.openvswitch.org/en/latest/topics/dpdk/vhost-user/

View File

@ -1,4 +0,0 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

View File

@ -1,206 +0,0 @@
======================
Example configurations
======================
.. _multiple-nics:
Multiple NICs
-------------
.. code-block:: yaml
network_config:
- type: interface
name: nic1
mtu: 1500
dns_servers: 8.8.8.8
domain: example.com
routes:
- default: true
next_hop: 198.51.100.1
- ip_netmask: 192.0.2.2/24
next_hop: 203.0.113.254
use_dhcp: false
addresses:
- ip_netmask: 198.18.100.0/15
- type: interface
name: nic2
use_dhcp: true
- type: interface
name: nic3
use_dhcp: false # do not configure this interface
.. _control-plane-bridge:
Control plane bridge
--------------------
.. code-block:: yaml
network_config:
- type: ovs_bridge
name: br-ctlplane
use_dhcp: false
ovs_extra:
- br-set-external-id br-ctlplane bridge-id br-ctlplane
addresses:
- ip_netmask: 192.0.2.2/24
- ip_netmask: 198.51.100.2/24
- ip_netmask: 203.0.113.2/24
dns_servers: 8.8.8.8
domain: example.com
members:
- type: interface
name: nic1
primary: true
mtu: 1450
.. _ovs-bond:
OVS bond
--------
.. code-block:: yaml
network_config:
- type: ovs_bridge
name: br-ex
use_dhcp: true
dns_servers: 8.8.8.8
domain: example.com
members:
- type: ovs_bond
name: bond1
use_dhcp: true
ovs_options: bond_mode=balance-slb
members:
- type: interface
name: nic1
- type: interface
name: nic2
.. _bonds-with-vlans:
Bonds with VLANs and jumbo frames
---------------------------------
.. code-block:: yaml
network_config:
- type: interface
name: nic1
- type: ovs_bridge
name: br-bond
dns_servers: 8.8.8.8
domain: example.com
members:
- type: ovs_bond
name: bond1
mtu: 9000
ovs_options: bond_mode=balance-tcp lacp=active other-config:lacp-fallback-ab=true
members:
- type: interface
name: nic2
mtu: 9000
primary: true
- type: interface
name: nic3
mtu: 9000
- type: vlan
device: bond1
mtu: 9000
vlan_id: 10
addresses:
- ip_netmask: 198.51.200.2/24
- type: vlan
device: bond1
mtu: 9000
vlan_id: 20
addresses:
- ip_netmask: 198.51.100.2/24
.. _linux-bridge:
Linux bridge
------------
.. code-block:: yaml
network_config:
- type: linux_bridge
name: br-ex
addresses:
- ip_netmask: 192.0.2.2/24
dns_servers: 8.8.8.8
domain: example.com
members:
- type: interface
name: nic1
# force the MAC address of the bridge to this interface
primary: true
routes:
- ip_netmask: 0.0.0.0/0
next_hop: 10.0.0.1
default: true
.. _bonds-vlans-dpdk:
Linux bonds, VLANs, and DPDK
----------------------------
.. code-block:: yaml
network_config:
- type: interface
name: nic1
mtu: 1500
use_dhcp: false
addresses:
- ip_netmask: 192.0.2.2/24
routes:
- ip_netmask: 0.0.0.0/0
next_hop: 10.0.0.1
default: true
- type: linux_bond
name: bond_api
mtu: 1500
use_dhcp: false
dns_servers: 8.8.8.8
members:
- type: interface
name: nic2
mtu: 1500
primary: true
- type: interface
name: nic3
mtu: 1500
- type: vlan
device: bond_api
mtu: 1500
vlan_id: 10
addresses:
- ip_netmask: 198.51.200.2/24
- type: vlan
device: bond_api
mtu: 1500
vlan_id: 20
addresses:
- ip_netmask: 198.51.100.2/24
# Used as a provider network with external DHCP #
- type: ovs_user_bridge
name: br-dpdk0
members:
- type: ovs_dpdk_bond
name: dpdkbond0
rx_queue: 1
members:
- type: ovs_dpdk_port
name: dpdk0
members:
- type: interface
name: nic4
- type: ovs_dpdk_port
name: dpdk1
members:
- type: interface
name: nic5

View File

@ -1,26 +0,0 @@
.. os-net-config documentation master file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to os-net-config's documentation!
========================================================
Contents:
.. toctree::
:maxdepth: 2
readme
installation
usage
config
examples
contributing
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,12 +0,0 @@
============
Installation
============
At the command line::
$ pip install os-net-config
Or, if you have virtualenvwrapper installed::
$ mkvirtualenv os-net-config
$ pip install os-net-config

View File

@ -1 +0,0 @@
.. include:: ../../README.rst

View File

@ -1,80 +0,0 @@
=====
Usage
=====
Backend Provider Detection
--------------------------
The ``--provider`` argument to ``os-net-config`` selects one of the available
backend providers:
- ``ifcfg`` Configure network interfaces using the ifcfg format
``/etc/sysconfig/network-scripts/`` files.
- ``eni`` Configure network interfaces using the Debian/Ubuntu
``/etc/network/interfaces`` format
- ``iproute`` (Not implemented)
When the ``--provider`` argument is not specified when calling
``os-net-config`` the provider will be chosen using the following rules:
1) If path ``/etc/sysconfig/network-scripts/`` exists, use the ``ifcfg``
provider.
2) Otherwise if path ``/etc/network/`` exists, use the ``eni`` provider.
In these rules, if a path is specified for ``--root-dir`` this will be
prepended to the checked paths before doing the above tests.
Interface Mapping
-----------------
The file ``/etc/os-net-config/mapping.yaml`` can contain mappings from
interface identifiers to the actual interface names. A different mapping file can
be used by using the ``--mapping-file`` argument to ``os-net-config``.
This mapping allows consistent interface identifiers to be used in the config
without needing the full interface name which can vary across servers and
hardware changes. This also allows config to be performed for interfaces
which are in a ``DOWN`` state before configuration.
The format of the mapping.yaml is as follows:
.. code-block:: yaml
interface_mapping:
nic1: enp0s20f0u2u1u2
nic2: enp0s31f6
To assist in writing this file, the following command will generate a JSON
snippet with discovered interfaces::
$ os-net-config --interfaces
{'nic1': 'enp0s20f0u2u1u2', 'nic2': 'enp0s31f6'}
When the ``--persist-mapping`` argument is specified when calling
``os-net-config`` then the existing interfaces names will be permanently
renamed to their identifier name.
Network Configuration
---------------------
By default the file ``/etc/os-net-config/config.yaml`` will be sourced for
the network configuration, but an alternate file can be used with the
``--config-file`` argument. The following arguments change the behaviour
during configuration:
- ``--detailed-exit-codes`` If enabled an exit code of ``2`` means that
files were modified.
- ``--exit-on-validation-errors`` Exit with an error if configuration
file validation fails.
- ``--noop`` Return the configuration commands, without applying them.
- ``--no-activate`` Install the configuration but don't start/stop
interfaces.
- ``--cleanup`` Cleanup unconfigured interfaces.
Python Library
--------------
To use os-net-config in a project::
import os_net_config

View File

@ -1,19 +0,0 @@
{ "network_config": [
{
"type": "ovs_bridge",
"name": "br-ctlplane",
"use_dhcp": "true",
"members": [
{
"type": "ovs_bond",
"name": "bond1",
"use_dhcp": "true",
"members": [
{ "type": "interface", "name": "em1" },
{ "type": "interface", "name": "em2" }
]
}
]
}
]
}

View File

@ -1,17 +0,0 @@
network_config:
-
type: ovs_bridge
name: br-ctlplane
use_dhcp: true
members:
-
type: ovs_bond
name: bond1
use_dhcp: true
members:
-
type: interface
name: em1
-
type: interface
name: em2

View File

@ -1,23 +0,0 @@
# Example showing use of the optional nicN abstraction
# for device naming, which defaults to an ordered
# translation to biodev names based on which interfaces
# are active on the system.
# Optionally the default mapping may be overridden by
# a mapping file via the -m option.
network_config:
-
type: ovs_bridge
name: br-ctlplane
use_dhcp: true
members:
-
type: ovs_bond
name: bond1
use_dhcp: true
members:
-
type: interface
name: nic1
-
type: interface
name: nic2

View File

@ -1,17 +0,0 @@
{ "network_config": [
{
"type": "ovs_bridge",
"name": "br-ctlplane",
"ovs_extra": [
"br-set-external-id br-ctlplane bridge-id br-ctlplane"
],
"use_dhcp": "true",
"members": [
{
"type": "interface",
"name": "em1"
}
]
}
]
}

View File

@ -1,11 +0,0 @@
network_config:
-
type: ovs_bridge
name: br-ctlplane
use_dhcp: true
ovs_extra:
- br-set-external-id br-ctlplane bridge-id br-ctlplane
members:
-
type: interface
name: em1

View File

@ -1,15 +0,0 @@
{ "network_config": [
{
"type": "ovs_bridge",
"name": "br-ctlplane",
"ovs_fail_mode": "secure",
"use_dhcp": "true",
"members": [
{
"type": "interface",
"name": "em1"
}
]
}
]
}

View File

@ -1,10 +0,0 @@
network_config:
-
type: ovs_bridge
name: br-ctlplane
use_dhcp: true
ovs_fail_mode: secure
members:
-
type: interface
name: em1

View File

@ -1,18 +0,0 @@
{ "network_config": [
{
"type": "ovs_bridge",
"name": "br-ctlplane",
"ovs_extra": [
"br-set-external-id br-ctlplane bridge-id br-ctlplane",
"set bridge {name} stp_enable=true"
],
"use_dhcp": "true",
"members": [
{
"type": "interface",
"name": "em1"
}
]
}
]
}

View File

@ -1,12 +0,0 @@
network_config:
-
type: ovs_bridge
name: br-ctlplane
use_dhcp: true
ovs_extra:
- br-set-external-id br-ctlplane bridge-id br-ctlplane
- set bridge {name} stp_enable=true
members:
-
type: interface
name: em1

View File

@ -1,29 +0,0 @@
{ "network_config": [
{
"type": "ovs_bridge",
"name": "br-ctlplane",
"use_dhcp": "true",
"members": [
{
"type": "interface",
"name": "em1"
},
{
"type": "vlan",
"vlan_id": 16,
"ovs_options": "mac=00:11:22:33:44:55",
"ovs_extra": [
"foo=bar"
],
"addresses": [{
"ip_netmask": "192.0.2.1/24"
}]
}
],
"routes": [{
"next_hop": "192.0.2.1",
"ip_netmask": "192.0.2.1/24"
}]
}
]
}

View File

@ -1,22 +0,0 @@
network_config:
-
type: ovs_bridge
name: br-ctlplane
use_dhcp: true
members:
-
type: interface
name: em1
-
type: vlan
vlan_id: 16
ovs_options: "mac=00:11:22:33:44:55"
ovs_extra:
- "foo=bar"
addresses:
-
ip_netmask: 192.0.2.1/24
routes:
-
next_hop: 192.0.2.1
ip_netmask: 192.0.2.1/24

View File

@ -1,14 +0,0 @@
{ "network_config": [
{
"type": "contrail_vrouter",
"name": "vhost0",
"members": [
{
"type": "interface",
"name": "em3"
}
],
"mtu": 1500
}
]
}

View File

@ -1,9 +0,0 @@
network_config:
-
type: contrail_vrouter
name: vhost0
members:
-
type: interface
name: em3
mtu: 1500

View File

@ -1,15 +0,0 @@
{ "network_config": [
{
"type": "contrail_vrouter_dpdk",
"name": "vhost0",
"members": [
{
"type": "interface",
"name": "em3"
}
],
"mtu": 1500,
"driver": "vfio"
}
]
}

View File

@ -1,10 +0,0 @@
network_config:
-
type: contrail_vrouter_dpdk
name: vhost0
members:
-
type: interface
name: em3
mtu: 1500
driver: vfio #default driver is uio_pci_generic

View File

@ -1,20 +0,0 @@
{ "network_config": [
{
"type": "contrail_vrouter_dpdk",
"name": "vhost0",
"members": [
{
"type": "interface",
"name": "em3"
},
{
"type": "interface",
"name": "em1"
}
],
"bond_mode": "2",
"bond_policy": "802.3ad",
"mtu": 1500
}
]
}

View File

@ -1,14 +0,0 @@
network_config:
-
type: contrail_vrouter_dpdk
name: vhost0
members:
-
type: interface
name: em3
-
type: interface
name: em1
mtu: 1500
bond_mode: 2
bond_policy: 802.3ad

View File

@ -1,15 +0,0 @@
{ "network_config": [
{
"type": "contrail_vrouter",
"name": "vhost0",
"members": [
{
"type": "vlan",
"vlan_id": 100,
"device": "em3"
}
],
"mtu": 1500
}
]
}

View File

@ -1,10 +0,0 @@
network_config:
-
type: contrail_vrouter
name: vhost0
members:
-
type: vlan
vlan_id: 100
device: em3
mtu: 1500

View File

@ -1,20 +0,0 @@
{
"network_config": [
{
"type": "ib_interface",
"name": "ib0",
"use_dhcp": false
},
{
"type": "ib_child_interface",
"parent": "ib0",
"pkey_id": 100,
"use_dhcp": false,
"addresses": [
{
"ip_netmask": "10.20.30.40/24"
}
]
}
]
}

View File

@ -1,18 +0,0 @@
network_config:
# Note(abdallahyas): a parent InfiniBand interface is needed to be up for
# the IPoIB pkey interface to work. The ib0 interface here is just there
# to make sure that it is up, it can be configured separately.
-
type: ib_interface
name: ib0
use_dhcp: false
-
type: ib_child_interface
parent: ib0
pkey_id: 100
use_dhcp: false
addresses:
-
ip_netmask: 10.20.30.40/24

View File

@ -1,26 +0,0 @@
{"network_config": [
{
"type": "ib_interface",
"name": "ib0",
"use_dhcp": false,
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"routes": [
{
"ip_netmask": "0.0.0.0/0",
"next_hop": "192.0.2.254",
"default": "true"
}
]
},
{
"type": "ib_interface",
"name": "ib1",
"use_dhcp": true,
"defroute": false
}
]
}

View File

@ -1,18 +0,0 @@
network_config:
-
type: ib_interface
name: ib0
use_dhcp: false
addresses:
-
ip_netmask: 192.0.2.1/24
routes:
-
ip_netmask: 0.0.0.0/0
next_hop: 192.0.2.254
default: true
-
type: interface
name: ib1
use_dhcp: true
defroute: false

View File

@ -1,40 +0,0 @@
{"network_config": [
{
"type": "interface",
"name": "em1",
"use_dhcp": false,
"use_dhcpv6": false,
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"routes": [
{
"ip_netmask": "0.0.0.0/0",
"next_hop": "192.0.2.254",
"default": "true"
},
{
"ip_netmask": "10.1.2.0/24",
"next_hop": "192.0.2.5",
"route_options": "metric 10"
}
]
},
{
"type": "interface",
"name": "em2",
"use_dhcp": true,
"defroute": false,
"ethtool_opts": "speed 1000 duplex full"
},
{
"type": "interface",
"name": "em3",
"use_dhcp": true,
"hotplug": true,
"onboot": false
}
]
}

View File

@ -1,30 +0,0 @@
network_config:
-
type: interface
name: em1
use_dhcp: false
use_dhcpv6: false
addresses:
-
ip_netmask: 192.0.2.1/24
routes:
-
ip_netmask: 0.0.0.0/0
next_hop: 192.0.2.254
default: true
-
ip_netmask: 10.1.2.0/24
next_hop: 192.0.2.5
route_options: "metric 10"
-
type: interface
name: em2
use_dhcp: true
defroute: false
ethtool_opts: "speed 1000 duplex full"
-
type: interface
name: em3
use_dhcp: true
hotplug: true
onboot: false # if not set default is true

View File

@ -1,37 +0,0 @@
{
"network_config": [
{
"type": "ivs_bridge",
"members": [
{
"type": "interface",
"name": "nic2",
},
{
"type": "interface",
"name": "nic3"
},
{
"type": "ivs_interface",
"name": "api",
"addresses": [
{
"ip_netmask": "172.16.2.7/24"
}
],
"vlan_id": 201
},
{
"type": "ivs_interface",
"name": "storage",
"addresses": [
{
"ip_netmask": "172.16.1.6/24"
}
],
"vlan_id": 202
}
]
}
]
}

View File

@ -1,24 +0,0 @@
network_config:
-
type: ivs_bridge
members:
-
type: interface
name: nic2
-
type: interface
name: nic3
-
type: ivs_interface
name: api
vlan_id: 201
addresses:
-
ip_netmask: 172.16.2.7/24
-
type: ivs_interface
name: storage
vlan_id: 202
addresses:
-
ip_netmask: 172.16.1.6/24

View File

@ -1,13 +0,0 @@
network_config:
-
type: linux_bond
name: bond1
use_dhcp: true
bonding_options: "mode=active-backup"
members:
-
type: interface
name: em1
-
type: interface
name: em2

View File

@ -1,18 +0,0 @@
# To use NetworkManager to manage an interface, set nm_controlled=true.
# Note that some interface types may not be supported by NetworkManager.
network_config:
-
type: linux_bond
name: bond1
nm_controlled: true
use_dhcp: true
bonding_options: "mode=active-backup"
members:
-
type: interface
name: em1
nm_controlled: true
-
type: interface
name: em2
nm_controlled: true

View File

@ -1,9 +0,0 @@
network_config:
-
type: linux_bridge
name: br-ctlplane
use_dhcp: true
members:
-
type: interface
name: em1

View File

@ -1,8 +0,0 @@
{ "network_config": [
{
"type": "linux_tap",
"name": "tap0",
"use_dhcp": true
}
]
}

View File

@ -1,6 +0,0 @@
network_config:
-
type: linux_tap
name: tap0
use_dhcp: true

View File

@ -1,12 +0,0 @@
# This can be used with the -m option to override the
# default mapping of the nicN aliases in configs
# The mapping can specify either a device name or a mac address
# If --persist-mapping is specified, we write the device aliases
# config instead of the system names, e.g we actually configure
# nic1 intead of em3. This is probably best used with --cleanup
# to remove the stale configs e.g for em3
interface_mapping:
nic1: em3
nic2: em1
nic3: 12:34:56:de:f0:12
nic4: 12:34:56:78:9a:bc

View File

@ -1,8 +0,0 @@
# See the mapping.yaml sample for an overview of the mapping functionality.
# This shows the use of mnemonic aliases instead of the default nicN aliases
# in configs. It can be used with the -m option to override the default
# mapping of the nicN aliases.
interface_mapping:
provision: em1
bond0p1: em2
bond0p2: 12:34:56:de:f0:12

View File

@ -1,5 +0,0 @@
interface_mapping:
nic1: em1
nic2: em2
nic3: em4
nic4: em3

View File

@ -1,38 +0,0 @@
{
"network_config": [
{
"type": "nfvswitch_bridge",
"options": "-c 2,3,4,5",
"members": [
{
"type": "interface",
"name": "nic2",
},
{
"type": "interface",
"name": "nic3"
},
{
"type": "nfvswitch_internal",
"name": "api",
"addresses": [
{
"ip_netmask": "172.16.2.7/24"
}
],
"vlan_id": 201
},
{
"type": "nfvswitch_internal",
"name": "storage",
"addresses": [
{
"ip_netmask": "172.16.1.6/24"
}
],
"vlan_id": 202
}
]
}
]
}

View File

@ -1,25 +0,0 @@
network_config:
-
type: nfvswitch_bridge
options: "-c 2,3,4,5"
members:
-
type: interface
name: nic2
-
type: interface
name: nic3
-
type: nfvswitch_internal
name: api
vlan_id: 201
addresses:
-
ip_netmask: 172.16.2.7/24
-
type: nfvswitch_internal
name: storage
vlan_id: 202
addresses:
-
ip_netmask: 172.16.1.6/24

View File

@ -1,24 +0,0 @@
{ "network_config": [
{
"type": "ovs_user_bridge",
"name": "br-link",
"members": [
{
"type": "ovs_dpdk_port",
"name": "dpdk0",
"driver": "igb_uio",
"mtu": 8192,
"rx_queue": 4,
"rx_queue_size": 1024,
"tx_queue_size": 2048,
"members": [
{
"type": "interface",
"name": "nic2",
}
]
}
]
}
]
}

View File

@ -1,32 +0,0 @@
# ovs_user_bridge type refers to the OVSUserBridge OVS ifup type, which will
# have the datapath type set as 'netdev' for DPDK processing.
# ovs_dpdk_port type refers to the OVSDPDKPort OVS ifup type, which will
# add the port to the bridge with the interface type as 'dpdk'.
network_config:
-
type: ovs_user_bridge
name: br-link
members:
-
type: ovs_dpdk_port
# dpdk0 name is generated by dpdk drivers after dpdk_nic_bind
name: dpdk0
# driver is optional argument, default driver is 'vfio-pci'
driver: igb_uio
# MTU is optional, used for jumbo frames
mtu: 8192
# rx_queue is optional, used for multi-queue option. It configures the
# maximum number of queues for a physical interface. If not defined,
# the physical interface will have single queue. The number of queues
# should be less than the PMD cores as each queue will have one PMD
# thread (CPU) associated with it.
rx_queue: 4
# rx_queue_size and tx_queue_size are optional. It configures the
# number of rx/tx descriptors that the associated NIC will be
# initialized with.
rx_queue_size: 1024
tx_queue_size: 2048
members:
- type: interface
name: nic2

View File

@ -1,37 +0,0 @@
{ "network_config": [
{
"type": "ovs_user_bridge",
"name": "br-link",
"members": [
{
"type" : "ovs_dpdk_bond",
"name" : "dpdkbond0",
"mtu" : 9000,
"rx_queue": 4,
"members": [
{
"type" : "ovs_dpdk_port",
"name" : "dpdk0",
"members": [
{
"type": "interface",
"name": "nic2"
}
]
},
{
"type" : "ovs_dpdk_port",
"name" : "dpdk1",
"members": [
{
"type": "interface",
"name": "nic3"
}
]
},
]
}
]
}
]
}

View File

@ -1,40 +0,0 @@
# ovs_user_bridge type refers to the OVSUserBridge OVS ifup type, which will
# have the datapath type set as 'netdev' for DPDK processing.
# ovs_dpdk_port type refers to the OVSDPDKPort OVS ifup type, which will
# add the port to the bridge with the interface type as 'dpdk'.
# ovs_dpdk_bond type refers to the OVSDPDKBond OVS ifup type, which will
# create the bond with dpdk interface type for dpdk ports
network_config:
-
type: ovs_user_bridge
name: br-link
members:
-
type: ovs_dpdk_bond
name: dpdkbond0
# MTU is optional, e.g. for jumbo frames
mtu: 9000
# rx_queue is optional, used for multi-queue option. It configures the
# maximum number of queues for each interface associated with the
# ovs_dpdk_bond. If not defined, the physical interfaces will have
# single queue.
# (rx_queue) x (Number of members in the ovs_dpdk_bond) should be less
# than the number of PMD cores, as each queue will have one PMD thread
# (CPU) associated with it.
rx_queue: 4
members:
-
type: ovs_dpdk_port
name: dpdk0
members:
-
type: interface
name: nic2
-
type: ovs_dpdk_port
name: dpdk1
members:
-
type: interface
name: nic3

View File

@ -1,37 +0,0 @@
{
"network_config": [
{
"name": "br-ctlplane",
"type": "ovs_bridge",
"members": [
{
"mtu": 1500,
"primary": "true",
"name": "eth1",
"type": "interface"
}
],
"ovs_extra": [
"br-set-external-id br-ctlplane bridge-id br-ctlplane"
],
"mtu": 1500,
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
]
},
{
"name": "br_pub-patch",
"type": "ovs_patch_port",
"bridge_name": "br-ctlplane",
"peer": "br-ctlplane-patch"
},
{
"name": "br-ctlplane-patch",
"type": "ovs_patch_port",
"bridge_name": "br_pub",
"peer": "br_pub-patch"
}
]
}

View File

@ -1,23 +0,0 @@
network_config:
-
type: ovs_bridge
name: br-ctlplane
mtu: 1500
members:
-
type: interface
name: eth1
# force the MAC address of the bridge to this interface
primary: true
mtu: 1500
ovs_extra: ["br-set-external-id br-ctlplane bridge-id br-ctlplane"]
-
type: ovs_patch_port
name: br_pub-patch
bridge_name: br-ctlplane
peer: br-ctlplane-patch
-
type: ovs_patch_port
name: br-ctlplane-patch
bridge_name: br_pub
peer: br_pub-patch

View File

@ -1,52 +0,0 @@
network_config:
-
type: route_table
name: custom
table_id: 200
-
type: route_table
name: alternate
table_id: 201
-
type: interface
name: em1
use_dhcp: false
addresses:
-
ip_netmask: 192.0.2.1/24
routes:
-
ip_netmask: 10.1.3.0/24
next_hop: 192.0.2.5
route_options: "metric 10"
table: 200 # Use table ID or table name
-
ip_netmask: 0.0.0.0/0
next_hop: 192.0.2.254
default: true
table: 200
rules:
- rule: "iif em1 table 200"
comment: "Route incoming traffic to em1 with table 200"
- rule: "from 192.0.2.0/24 table 200"
comment: "Route all traffic from 192.0.2.0/24 with table 200"
- rule: "add blackhole from 172.19.40.0/24 table 200"
- rule: "add unreachable iif em1 from 192.168.1.0/24"
-
type: interface
name: em2
use_dhcp: false
addresses:
- ip_netmask: 10.0.2.1/24
routes:
-
ip_netmask: 10.1.3.0/24
next_hop: 10.0.2.253
table: alternate # Use table ID or table name
-
default: true
next_hop: 10.0.3.254
route_options: "table alternate"
rules:
- rule: "iif em2 table alternate"
- rule: "from 10.0.2.0/24 table alternate"

View File

@ -1,130 +0,0 @@
{
"network_config": [
{
"type": "sriov_pf",
"name": "p2p1",
"numvfs": 10,
"use_dhcp": false,
"promisc": true,
"ethtool_opts": "speed 1000 duplex full"
},
{
"type": "sriov_pf",
"name": "p2p2",
"numvfs": 10,
"use_dhcp": false,
"promisc": true
},
{
"type": "sriov_vf",
"device": "p2p1",
"vfid": 5,
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"vlan_id": 100,
"qos": 2,
"min_tx_rate": 10,
"max_tx_rate": 100,
"spoofcheck": true,
"macaddr": "00:78:90:80:cc:30",
"trust": true,
"state": "auto",
"promisc": false,
"ethtool_opts": "speed 1000 duplex full"
},
{
"type": "ovs_bridge",
"name": "br-vfs",
"members": [
{
"type": "sriov_vf",
"vfid": 1,
"trust": true,
"device": "p2p1",
"promisc": true,
"vlan_id": 116,
"qos": 3,
"min_tx_rate": 0,
"max_tx_rate": 0,
"spoofcheck": false
}
],
"use_dhcp": true
},
{
"type": "ovs_bridge",
"name": "br-bond",
"use_dhcp": true,
"members": [
{
"type": "ovs_bond",
"name": "bond_vf",
"ovs_options": "bond_mode=active-backup",
"members": [
{
"type": "sriov_vf",
"device": "p2p1",
"vfid": 2,
"vlan_id": 112,
"qos": 4,
"min_tx_rate": 0,
"max_tx_rate": 0,
"primary": true,
"trust": true,
"promisc": true,
"spoofcheck": false
},
{
"type": "sriov_vf",
"device": "p2p2",
"vfid": 2,
"vlan_id": 112,
"qos": 4,
"min_tx_rate": 0,
"max_tx_rate": 0,
"trust": true,
"promisc": true,
"spoofcheck": false
}
]
}
]
},
{
"type": "linux_bond",
"name": "bond_lnx",
"use_dhcp": true,
"bonding_options": "mode=active-backup",
"members": [
{
"type": "sriov_vf",
"device": "p2p1",
"vfid": 3,
"vlan_id": 113,
"qos": 5,
"min_tx_rate": 0,
"max_tx_rate": 0,
"spoofcheck": false,
"trust": true,
"promisc": false,
"primary": true,
},
{
"type": "sriov_vf",
"device": "p2p2",
"vfid": 3,
"vlan_id": 113,
"qos": 5,
"min_tx_rate": 0,
"max_tx_rate": 0,
"spoofcheck": false,
"trust": true,
"promisc": false
}
]
}
]
}

View File

@ -1,158 +0,0 @@
network_config:
# sriov_pf type shall be used to configure the PF's of NICs.
# The numvfs configured for the PF's shall be set on the sriov_numvfs of the
# sysfs for the corresponding NIC and the persistence of the same across reboots
# shall be handled
-
type: sriov_pf
# nic name or nic number of the NIC that needs to be configured for SRIOV
name: p2p1
# number of VFs required on the particular NIC
numvfs: 10
# Dont set the IP address on the PF
use_dhcp: false
# Allow all the traffic received. It might be needed when one of its VF
# is attached to a ovs bridge. Default: true
promisc: true
# Set ethtool options (optional)
ethtool_opts: "speed 1000 duplex full"
-
type: sriov_pf
name: p2p2
numvfs: 10
use_dhcp: false
promisc: true
# sriov_vf type shall be used to configure the VF's of NICs.
# It requires the PF devices to be configured via sriov_pf types
# "name" parameter is not required for VF's. It'll be derived from the VF id
# and the PF device name.
- type: sriov_vf
# The PF device needs to be configured via the sriov_pf type
# the PF device could be a nic number (ex: nic5) or nic name (ex: ens20f0)
device: p2p1
# The VF id shall be the VF number between 0 to (numvfs-1), where numvfs
# is the member of the sriov_pf type
vfid: 5
addresses:
- ip_netmask: 192.0.2.1/24
# When specified, all traffic sent from the VF will be tagged with the
# specified VLAN ID. Incoming traffic will be filtered for the specified
# VLAN ID, and will have all VLAN tags stripped before being passed to the
# VF. Setting this parameter to 0 disables VLAN tagging and filtering.
vlan_id: 100
# VLAN-Quality Of Service (priority) bits for the VLAN tag.
# When specified, all VLAN tags transmitted by the VF will include the
# specified priority bits in the VLAN tag. Requires vlan_id
# Default value is 0.
qos: 2
# change the allowed minimum transmit bandwidth, in Mbps, for the specified VF.
# Minimum TXRATE should be always <= Maximum TXRATE.
# Setting this parameter to 0 disables rate limiting.
min_tx_rate: 10
# change the allowed maximum transmit bandwidth, in Mbps, for the specified VF.
# Setting this parameter to 0 disables rate limiting.
max_tx_rate: 100
# MAC spoofing is a method of altering the MAC address
# The MAC address anti-spoofing when enabled protects from malicious MAC
# address spoofing. It should be disabled for 802.3ad bonds.
spoofcheck: true
# Change the MAC address of the VF.
macaddr: 00:78:90:80:cc:30
# Enabling trust (true) for VF allows enabling multicast/promiscuous mode
# on the VF. The default value is false.
trust: true
# Link state seen by the VF
# - auto: a reflection of the PF link state (default)
# - enable: lets the VF to communicate with other VFs on this host even
# if the PF link state is down
# - disable: causes the HW to drop any packets sent by the VF.
state: auto
# Enabling promisc mode allows the traffic originally targeted to go to the
# VF and it will also receive the unmatched traffic and all the multicast
# traffic received in the physical port. Note that all traffic that has
# destination mac that does not match any of the VFs/PF MAC addresses is
# referred to as unmatched traffic.
# The default value is false. Requires the enabling of trust mode
promisc: false
# Set ethtool options (optional)
ethtool_opts: "speed 1000 duplex full"
# Attach a SR-IOV VF to a ovs bridge
- type: ovs_bridge
name: br-vfs
use_dhcp: true
members:
# Specify the type
- type: sriov_vf
# Required field
device: p2p1
# Required field
vfid: 1
# Optional field
vlan_id: 116
# Optional field, but requires vlan_id
qos: 3
# For OVS Bridge, the default value is true (recommended)
trust: true
# For OVS Bridge, the default value is true (recommended)
promisc: true
# For OVS Bridge, the default value is false (recommended)
spoofcheck: false
- type: ovs_bridge
name: br-bond
use_dhcp: true
members:
-
type: ovs_bond
name: bond_vf
ovs_options: "bond_mode=active-backup"
members:
-
type: sriov_vf
device: p2p1
vfid: 2
vlan_id: 112
qos: 4
primary: true
# For OVS Bond, the default value is true (recommended)
trust: true
# For OVS Bond, the default value is true (recommended)
promisc: true
# For OVS Bond, the default value is false (recommended)
spoofcheck: false
-
type: sriov_vf
device: p2p2
vfid: 2
vlan_id: 112
qos: 4
trust: true
promisc: true
spoofcheck: false
- type: linux_bond
name: bond_lnx
use_dhcp: true
bonding_options: "mode=active-backup"
members:
-
type: sriov_vf
device: p2p1
vfid: 3
vlan_id: 113
qos: 5
# For linux_bond, the default value is false
spoofcheck: false
# For linux_bond, the default value is true
trust: true
# For linux_bond, the default value is false
promisc: false
primary: true
-
type: sriov_vf
device: p2p2
vfid: 3
vlan_id: 113
qos: 5
spoofcheck: false
trust: true
promisc: false

View File

@ -1,102 +0,0 @@
{
"network_config": [
{
"type": "sriov_pf",
"name": "p2p1",
"numvfs": 10,
"use_dhcp": false,
"promisc": true
},
{
"type": "sriov_pf",
"name": "p2p2",
"numvfs": 10,
"use_dhcp": false,
"promisc": true
},
{
"type": "sriov_vf",
"device": "p2p1",
"vfid": 5,
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"vlan_id": 100,
"qos": 2,
"spoofcheck": true,
"macaddr": "00:78:90:80:cc:30",
"trust": true,
"state": "auto",
"promisc": false
},
{
"name": "br-vfs",
"type": "ovs_user_bridge",
"use_dhcp": false,
"members": [
{
"name": "dpdk0",
"type": "ovs_dpdk_port",
"members": [
{
"device": "p5p2",
"qos": 3,
"spoofcheck": false,
"trust": true,
"type": "sriov_vf",
"vfid": 1,
"vlan_id": 116
}
]
}
]
},
{
"type": "ovs_user_bridge",
"name": "br-bond",
"members": [
{
"type" : "ovs_dpdk_bond",
"name" : "dpdkbond1",
"ovs_options": "bond_mode=active-backup",
"members": [
{
"type" : "ovs_dpdk_port",
"name" : "dpdk2",
"members": [
{
"type": "sriov_vf",
"device": "p2p1",
"vfid": 4,
"vlan_id": 114,
"spoofcheck": false,
"trust": true,
"qos": 6
}
],
"primary": true
},
{
"type" : "ovs_dpdk_port",
"name" : "dpdk3",
"members": [
{
"type": "sriov_vf",
"device": "p2p2",
"vfid": 4,
"vlan_id": 114,
"spoofcheck": false,
"trust": true,
"qos": 6
}
]
}
]
}
]
}
]
}

View File

@ -1,129 +0,0 @@
network_config:
# sriov_pf type shall be used to configure the PF's of NICs.
# The numvfs configured for the PF's shall be set on the sriov_numvfs of the
# sysfs for the corresponding NIC and the persistence of the same across reboots
# shall be handled
-
type: sriov_pf
# nic name or nic number of the NIC that needs to be configured for SRIOV
name: p2p1
# number of VFs required on the particular NIC
numvfs: 10
# Dont set the IP address on the PF
use_dhcp: false
# Allow all the traffic received. It might be needed when one of its VF
# is attached to a ovs bridge. Default: true
promisc: true
-
type: sriov_pf
name: p2p2
numvfs: 10
use_dhcp: false
promisc: true
# sriov_vf type shall be used to configure the VF's of NICs.
# It requires the PF devices to be configured via sriov_pf types
# "name" parameter is not required for VF's. It'll be derived from the VF id
# and the PF device name.
- type: sriov_vf
# The PF device needs to be configured via the sriov_pf type
# the PF device could be a nic number (ex: nic5) or nic name (ex: ens20f0)
device: p2p1
# The VF id shall be the VF number between 0 to (numvfs-1), where numvfs
# is the member of the sriov_pf type
vfid: 5
addresses:
- ip_netmask: 192.0.2.1/24
# When specified, all traffic sent from the VF will be tagged with the
# specified VLAN ID. Incoming traffic will be filtered for the specified
# VLAN ID, and will have all VLAN tags stripped before being passed to the
# VF. Setting this parameter to 0 disables VLAN tagging and filtering.
vlan_id: 100
# VLAN-Quality Of Service (priority) bits for the VLAN tag.
# When specified, all VLAN tags transmitted by the VF will include the
# specified priority bits in the VLAN tag. Requires vlan_id
# Default value is 0.
qos: 2
# MAC spoofing is a method of altering the MAC address
# The MAC address anti-spoofing when enabled protects from malicious MAC
# address spoofing. It should be disabled for 802.3ad bonds.
spoofcheck: true
# Change the MAC address of the VF.
macaddr: 00:78:90:80:cc:30
# Enabling trust (true) for VF allows enabling multicast/promiscuous mode
# on the VF. The default value is false.
trust: true
# Link state seen by the VF
# - auto: a reflection of the PF link state (default)
# - enable: lets the VF to communicate with other VFs on this host even
# if the PF link state is down
# - disable: causes the HW to drop any packets sent by the VF.
state: auto
# Enabling promisc mode allows the traffic originally targeted to go to the
# VF and it will also receive the unmatched traffic and all the multicast
# traffic received in the physical port. Note that all traffic that has
# destination mac that does not match any of the VFs/PF MAC addresses is
# referred to as unmatched traffic.
# The default value is false. Requires the enabling of trust mode
promisc: false
# Attach a SR-IOV VF to a ovs user bridge
- type: ovs_user_bridge
name: br-vfs
use_dhcp: false
members:
- type: ovs_dpdk_port
name: dpdk0
members:
# Specify the type
- type: sriov_vf
# Required field
device: p5p2
# Required field
vfid: 1
# Optional field
vlan_id: 116
# Optional field, but requires vlan_id
qos: 3
# Set trust to true when attaching to ovs_user_bridge
trust: true
# Set spoofcheck to false when attaching to ovs_user_bridge
spoofcheck: false
# Note: Do not set promisc mode.
-
type: ovs_user_bridge
name: br-bond
members:
-
type: ovs_dpdk_bond
name: dpdkbond1
ovs_options: "bond_mode=active-backup"
members:
-
type: ovs_dpdk_port
name: dpdk2
members:
-
type: sriov_vf
device: p2p1
vfid: 4
vlan_id: 114
qos: 6
# Default/Recommended : false
spoofcheck: false
# Default/Recommended : true
trust: true
primary: true
# Note: DO NOT SET promisc mode
-
type: ovs_dpdk_port
name: dpdk3
members:
-
type: sriov_vf
device: p2p2
vfid: 4
vlan_id: 114
qos: 6
spoofcheck: false
trust: true

View File

@ -1,85 +0,0 @@
{
"network_config": [
{
"type": "sriov_pf",
"name": "p2p1",
"numvfs": 10,
"use_dhcp": false,
"promisc": true,
"link_mode": "switchdev",
"steering_mode": "dmfs"
},
{
"type": "ovs_bridge",
"name": "br-pfs",
"members": [
{
"type": "sriov_pf",
"name": "p2p2",
"numvfs": 10,
"promisc": true,
"use_dhcp": false,
"link_mode": "switchdev"
}
],
"use_dhcp": true
},
{
"type": "ovs_bridge",
"name": "br-bond",
"use_dhcp": true,
"members": [
{
"type": "ovs_bond",
"name": "bond_pf",
"ovs_options": "bond_mode=active-backup",
"members": [
{
"type": "sriov_pf",
"name": "p5p1",
"numvfs": 10,
"primary": true,
"promisc": true,
"use_dhcp": false,
"link_mode": "switchdev"
},
{
"type": "sriov_pf",
"name": "p5p2",
"numvfs": 10,
"promisc": true,
"use_dhcp": false,
"link_mode": "switchdev"
}
]
}
]
},
{
"type": "linux_bond",
"name": "bond_lnx",
"use_dhcp": true,
"bonding_options": "mode=active-backup",
"members": [
{
"type": "sriov_pf",
"name": "p6p1",
"numvfs": 10,
"primary": true,
"promisc": true,
"use_dhcp": false,
"link_mode": "switchdev"
},
{
"type": "sriov_pf",
"name": "p6p2",
"numvfs": 10,
"promisc": true,
"use_dhcp": false,
"link_mode": "switchdev"
}
]
}
]
}

View File

@ -1,90 +0,0 @@
network_config:
# sriov_pf type shall be used to configure the PF's of NICs.
# The numvfs configured for the PF's shall be set on the sriov_numvfs of the
# sysfs for the corresponding NIC and the persistence of the same across reboots
# shall be handled.
# The link_mode configured the mode of the sriov_pf which can be "switchdev"
# or legacy.
# In case fo switchdev, you will enable the hardware offloading and VF-LAG
# capabilities
# For now, if you configured link_mode with "switchdev" you will not be able
# to use any of its sriov_vfs, the vfs will be only used for vms.
-
type: sriov_pf
# nic name or nic number of the NIC that needs to be configured for SRIOV
name: p2p1
# number of VFs required on the particular NIC
numvfs: 10
addresses:
- ip_netmask: 192.0.2.1/24
# Allow all the traffic received. Default: true
promisc: true
# The mode of sriov_pf which:
# - switchdev
# - legacy (default)
link_mode: switchdev
# (Optional) The flow steering mode, which could be smfs or dmfs
# If it's not set (None), the default will be smfs
steering_mode: dmfs
-
type: ovs_bridge
name: br-pfs
use_dhcp: true
members:
-
type: sriov_pf
name: p2p2
numvfs: 10
promisc: true
use_dhcp: false
link_mode: switchdev
-
type: ovs_bridge
name: br-bond
use_dhcp: true
members:
-
type: ovs_bond
name: bond_pf
ovs_options: "bond_mode=active-backup"
members:
-
type: sriov_pf
name: p5p1
numvfs: 10
primary: true
promisc: true
use_dhcp: false
link_mode: switchdev
-
type: sriov_pf
name: p5p2
numvfs: 10
promisc: true
use_dhcp: false
link_mode: switchdev
-
# VF-LAG capability, which means that the vfs will be bonded in hardware
type: linux_bond
name: bond_lnx
use_dhcp: true
bonding_options: "mode=active-backup"
members:
-
type: sriov_pf
name: p6p1
numvfs: 10
primary: true
promisc: true
use_dhcp: false
link_mode: switchdev
-
type: sriov_pf
name: p6p2
numvfs: 10
promisc: true
use_dhcp: false
link_mode: switchdev

View File

@ -1,13 +0,0 @@
{ "network_config": [
{
"type": "team",
"name": "team1",
"use_dhcp": true,
"bonding_options": "{\"runner\": {\"name\": \"activebackup\"}}",
"members": [
{ "type": "interface", "name": "em1", "primary": true },
{ "type": "interface", "name": "em2" }
]
}
]
}

View File

@ -1,18 +0,0 @@
# Config for bonding with teamd. Bonding options are provided as a JSON
# string. The following runners are available in teamd: broadcast,
# roundrobin, activebackup, loadbalance, and lacp.
# Please see the teamd.conf(5) man page for more information.
network_config:
-
type: team
name: team1
use_dhcp: true
bonding_options: '{"runner": {"name": "activebackup"}}'
members:
-
type: interface
name: em1
primary: true
-
type: interface
name: em2

View File

@ -1,28 +0,0 @@
{
"network_config": [
{
"type": "ovs_bridge",
"name": "br-vdpa",
"members": [
{
"type": "sriov_pf",
"name": "p2p1",
"numvfs": 10,
"vdpa": true,
"use_dhcp": false,
"link_mode": "switchdev"
},
{
"type": "sriov_pf",
"name": "p2p2",
"numvfs": 10,
"vdpa": true,
"use_dhcp": false,
"link_mode": "switchdev"
}
],
"use_dhcp": true
}
]
}

View File

@ -1,31 +0,0 @@
network_config:
# Since vDPA can't function without OVS Hardware Offload, the PFs have to
# be a member of an ovs_bridge.
- type: ovs_bridge
name: br-vdpa
use_dhcp: true
members:
# sriov_pf type shall be used to configure the PF's of vDPA devices.
# The numvfs configured for the PF's shall be set on the sriov_numvfs of the
# sysfs for the corresponding NIC and the persistence of the same across reboots
# shall be handled
-
type: sriov_pf
# nic name or nic number of the NIC that needs to be configured for vDPA
name: p2p1
# Flag this PF as a vDPA device
vdpa: true
# number of VFs required on the particular NIC
# Should be at least one when vdpa is true
numvfs: 10
# Dont set the IP address on the PF
use_dhcp: false
# Link mode for the PF has to be switchdev when vdpa is true
link_mode: switchdev
-
type: sriov_pf
name: p2p2
vdpa: true
numvfs: 10
use_dhcp: false
link_mode: switchdev

View File

@ -1,23 +0,0 @@
{ "network_config": [
{
"type": "vpp_bond",
"name": "net_bonding0",
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"bonding_options": "mode=2,xmit_policy=l34",
"members": [
{
"type": "vpp_interface",
"name": "eth1"
},
{
"type": "vpp_interface",
"name": "eth2"
}
]
}
]
}

View File

@ -1,17 +0,0 @@
network_config:
-
type: vpp_bond
# name must be in the format of eth_bondX or net_bondingX, where X is a
# unique number for each bond.
name: net_bonding0
addresses:
-
ip_netmask: 192.0.2.1/24
bonding_options: "mode=2,xmit_policy=l34"
members:
-
type: vpp_interface
name: eth1
-
type: vpp_interface
name: eth2

View File

@ -1,14 +0,0 @@
{ "network_config": [
{
"type": "vpp_interface",
"name": "nic2",
"addresses": [
{
"ip_netmask": "192.0.2.1/24"
}
],
"uio_driver": "uio_pci_generic",
"options": "vlan-strip-offload off"
}
]
}

View File

@ -1,18 +0,0 @@
network_config:
-
type: vpp_interface
name: nic2
addresses:
-
ip_netmask: 192.0.2.1/24
# DPDK poll-mode driver name. Defaults to 'vfio-pci', other possible value
# is 'uio_pci_generic'. It is also possible to specify other driver names
# such as 'igb_uio', however, it is assumed that any required kernel
# modules for those drivers are already loaded when os-net-config is
# invoked.
uio_driver: uio_pci_generic
# Interface options such as vlan stripping and tx/rx transmit queues
# specification. Reference for those configurations can
# be found at https://wiki.fd.io/view/VPP/Command-line_Arguments
# Example: 'vlan-strip-offload on num-rx-queues 3'
#options: "vlan-strip-offload off"

View File

@ -1,387 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2015 Red Hat, 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 logging
import os
from oslo_concurrency import processutils
from os_net_config import objects
from os_net_config import utils
logger = logging.getLogger(__name__)
class NotImplemented(Exception):
pass
class ConfigurationError(Exception):
pass
class NetConfig(object):
"""Common network config methods class."""
def __init__(self, noop=False, root_dir=''):
self.noop = noop
self.log_prefix = "NOOP: " if noop else ""
self.root_dir = root_dir
self.errors = []
def add_object(self, obj):
"""Convenience method to add any type of object to the network config.
See objects.py.
:param obj: The object to add.
"""
if isinstance(obj, objects.RouteTable):
self.add_route_table(obj)
if isinstance(obj, objects.Interface):
self.add_interface(obj)
elif isinstance(obj, objects.Vlan):
self.add_vlan(obj)
elif isinstance(obj, objects.IvsInterface):
self.add_ivs_interface(obj)
elif isinstance(obj, objects.NfvswitchInternal):
self.add_nfvswitch_internal(obj)
elif isinstance(obj, objects.OvsBridge):
self.add_bridge(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.OvsUserBridge):
self.add_ovs_user_bridge(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.LinuxBridge):
self.add_linux_bridge(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.IvsBridge):
self.add_ivs_bridge(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.NfvswitchBridge):
self.add_nfvswitch_bridge(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.OvsBond):
self.add_bond(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.LinuxBond):
self.add_linux_bond(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.LinuxTeam):
self.add_linux_team(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.OvsTunnel):
self.add_ovs_tunnel(obj)
elif isinstance(obj, objects.OvsPatchPort):
self.add_ovs_patch_port(obj)
elif isinstance(obj, objects.IbInterface):
self.add_ib_interface(obj)
elif isinstance(obj, objects.IbChildInterface):
self.add_ib_child_interface(obj)
elif isinstance(obj, objects.OvsDpdkPort):
self.add_ovs_dpdk_port(obj)
elif isinstance(obj, objects.OvsDpdkBond):
self.add_ovs_dpdk_bond(obj)
elif isinstance(obj, objects.SriovPF):
self.add_sriov_pf(obj)
elif isinstance(obj, objects.SriovVF):
self.add_sriov_vf(obj)
elif isinstance(obj, objects.VppInterface):
self.add_vpp_interface(obj)
elif isinstance(obj, objects.VppBond):
self.add_vpp_bond(obj)
for member in obj.members:
self.add_object(member)
elif isinstance(obj, objects.ContrailVrouter):
self.add_contrail_vrouter(obj)
elif isinstance(obj, objects.ContrailVrouterDpdk):
self.add_contrail_vrouter_dpdk(obj)
elif isinstance(obj, objects.LinuxTap):
self.add_linux_tap(obj)
def add_route_table(self, route_table):
"""Add a route table object to the net config object.
:param route_table: The RouteTable object to add.
"""
raise NotImplementedError("add_route_table is not implemented.")
def add_interface(self, interface):
"""Add an Interface object to the net config object.
:param interface: The Interface object to add.
"""
raise NotImplementedError("add_interface is not implemented.")
def add_vlan(self, vlan):
"""Add a Vlan object to the net config object.
:param vlan: The vlan object to add.
"""
raise NotImplementedError("add_vlan is not implemented.")
def add_bridge(self, bridge):
"""Add an OvsBridge object to the net config object.
:param bridge: The OvsBridge object to add.
"""
raise NotImplementedError("add_bridge is not implemented.")
def add_ovs_user_bridge(self, bridge):
"""Add an OvsUserBridge object to the net config object.
:param bridge: The OvsUserBridge object to add.
"""
raise NotImplementedError("add_ovs_user_bridge is not implemented.")
def add_linux_bridge(self, bridge):
"""Add a LinuxBridge object to the net config object.
:param bridge: The LinuxBridge object to add.
"""
raise NotImplementedError("add_linux_bridge is not implemented.")
def add_ivs_bridge(self, bridge):
"""Add a IvsBridge object to the net config object.
:param bridge: The IvsBridge object to add.
"""
raise NotImplementedError("add_ivs_bridge is not implemented.")
def add_nfvswitch_bridge(self, bridge):
"""Add a NfvswitchBridge object to the net config object.
:param bridge: The NfvswitchBridge object to add.
"""
raise NotImplementedError("add_nfvswitch_bridge is not implemented.")
def add_bond(self, bond):
"""Add an OvsBond object to the net config object.
:param bond: The OvsBond object to add.
"""
raise NotImplementedError("add_bond is not implemented.")
def add_linux_bond(self, bond):
"""Add a LinuxBond object to the net config object.
:param bond: The LinuxBond object to add.
"""
raise NotImplementedError("add_linux_bond is not implemented.")
def add_linux_team(self, team):
"""Add a LinuxTeam object to the net config object.
:param team: The LinuxTeam object to add.
"""
raise NotImplementedError("add_linux_team is not implemented.")
def add_ovs_tunnel(self, tunnel):
"""Add a OvsTunnel object to the net config object.
:param tunnel: The OvsTunnel object to add.
"""
raise NotImplementedError("add_ovs_tunnel is not implemented.")
def add_ovs_patch_port(self, ovs_patch_port):
"""Add a OvsPatchPort object to the net config object.
:param ovs_patch_port: The OvsPatchPort object to add.
"""
raise NotImplementedError("add_ovs_patch_port is not implemented.")
def add_ib_interface(self, ib_interface):
"""Add an InfiniBand Interface object to the net config object.
:param interface: The InfiniBand Interface object to add.
"""
raise NotImplementedError("add_ib_interface is not implemented.")
def add_ib_child_interface(self, ib_child_interface):
"""Add an InfiniBand child interface object to the net config object.
:param ib_child_interface: The InfiniBand child
interface object to add.
"""
raise NotImplementedError("add_ib_child_interface is not implemented.")
def add_ovs_dpdk_port(self, ovs_dpdk_port):
"""Add a OvsDpdkPort object to the net config object.
:param ovs_dpdk_port: The OvsDpdkPort object to add.
"""
raise NotImplementedError("add_ovs_dpdk_port is not implemented.")
def add_ovs_dpdk_bond(self, ovs_dpdk_bond):
"""Add a OvsDpdkBond object to the net config object.
:param ovs_dpdk_bond: The OvsDpdkBond object to add.
"""
raise NotImplementedError("add_ovs_dpdk_bond is not implemented.")
def add_sriov_pf(self, sriov_pf):
"""Add a SriovPF object to the net config object.
:param sriov_pf: The SriovPF object to add.
"""
raise NotImplementedError("add_sriov_pf is not implemented.")
def add_sriov_vf(self, sriov_vf):
"""Add a SriovVF object to the net config object.
:param sriov_vf: The SriovVF object to add.
"""
raise NotImplementedError("add_sriov_vf is not implemented.")
def add_vpp_interface(self, vpp_interface):
"""Add a VppInterface object to the net config object.
:param vpp_interface: The VppInterface object to add.
"""
raise NotImplementedError("add_vpp_interface is not implemented.")
def add_vpp_bond(self, vpp_bond):
"""Add a VppBond object to the net config object.
:param vpp_bond: The VppBond object to add.
"""
raise NotImplementedError("add_vpp_bond is not implemented.")
def add_contrail_vrouter(self, contrail_vrouter):
"""Add a ContrailVrouter object to the net config object.
:param contrail_vrouter:
The ContrailVrouter object to add.
"""
raise NotImplementedError("add_contrail_vrouter is not implemented.")
def add_contrail_vrouter_dpdk(self, contrail_vrouter_dpdk):
"""Add a ContrailVrouterDpdk object to the net config object.
:param contrail_vrouter_dpdk:
The ContrailVrouterDpdk object to add.
"""
raise NotImplementedError(
"add_contrail_vrouter_dpdk is not implemented.")
def add_linux_tap(self, linux_tap):
"""Add a LinuxTap object to the net config object.
:param linux_tap:
The LinuxTap object to add.
"""
raise NotImplementedError(
"add_linux_tap is not implemented.")
def apply(self, cleanup=False):
"""Apply the network configuration.
:param cleanup: A boolean which indicates whether any undefined
(existing but not present in the object model) interfaces
should be disabled and deleted.
:returns: a dict of the format: filename/data which contains info
for each file that was changed (or would be changed if in --noop
mode).
"""
raise NotImplementedError("apply is not implemented.")
def execute(self, msg, cmd, *args, **kwargs):
"""Print a message and run a command.
Print a message and run a command with processutils
in noop mode, this just prints a message.
"""
logger.info('%s%s' % (self.log_prefix, msg))
if not self.noop:
processutils.execute(cmd, *args, **kwargs)
def write_config(self, filename, data, msg=None):
msg = msg or "Writing config %s" % filename
logger.info('%s%s' % (self.log_prefix, msg))
if not self.noop:
utils.write_config(filename, data)
def remove_config(self, filename, msg=None):
msg = msg or "Removing config %s" % filename
logger.info('%s%s' % (self.log_prefix, msg))
if not self.noop:
os.remove(filename)
def ifdown(self, interface, iftype='interface'):
msg = 'running ifdown on %s: %s' % (iftype, interface)
self.execute(msg, '/sbin/ifdown', interface, check_exit_code=False)
if utils.is_active_nic(interface):
msg = '%s %s is up, trying with ip command' % (iftype, interface)
self.execute(msg, '/sbin/ip',
'link', 'set', 'dev', interface, 'down')
def ifup(self, interface, iftype='interface'):
"""Run 'ifup' on the specified interface
If a failure occurs when bringing up the interface it will be saved
to self.errors for later handling. This allows callers to continue
trying to bring up interfaces even if one fails.
:param interface: The name of the interface to be started.
:param iftype: The type of the interface.
"""
msg = 'running ifup on %s: %s' % (iftype, interface)
try:
self.execute(msg, '/sbin/ifup', interface)
except processutils.ProcessExecutionError as e:
self.errors.append(e)
def ifrename(self, oldname, newname):
msg = 'renaming %s to %s: ' % (oldname, newname)
# ifdown isn't enough when renaming, we need the link down
for name in (oldname, newname):
if utils.is_active_nic(name):
self.execute(msg, '/sbin/ip',
'link', 'set', 'dev', name, 'down')
self.execute(msg, '/sbin/ip',
'link', 'set', 'dev', name, 'link', 'down')
self.execute(msg, '/sbin/ip',
'link', 'set', 'dev', oldname, 'name', newname)
self.execute(msg, '/sbin/ip',
'link', 'set', 'dev', newname, 'up')
def ovs_appctl(self, action, *parameters, ignore_err=False):
"""Run 'ovs-appctl' with the specified action
Its possible the command may fail due to timing if, for example,
the command affects an interface and it the prior ifup command
has not completed. So retry the command and if a failures still
occurs save the error for later handling.
:param action: The ovs-appctl action.
:param parameters: Parameters to pass to ovs-appctl.
"""
msg = 'Running ovs-appctl %s %s' % (action, parameters)
try:
self.execute(msg, '/bin/ovs-appctl', action, *parameters,
delay_on_retry=True, attempts=5)
except processutils.ProcessExecutionError as e:
if not ignore_err:
self.errors.append(e)

View File

@ -1,365 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import json
import os
import sys
import yaml
from os_net_config import common
from os_net_config import impl_eni
from os_net_config import impl_ifcfg
from os_net_config import impl_iproute
from os_net_config import impl_nmstate
from os_net_config import objects
from os_net_config import utils
from os_net_config import validator
from os_net_config import version
logger = common.configure_logger()
_SYSTEM_CTL_CONFIG_FILE = '/etc/sysctl.d/os-net-sysctl.conf'
def parse_opts(argv):
parser = argparse.ArgumentParser(
description='Configure host network interfaces using a JSON'
' config file format.')
parser.add_argument('-c', '--config-file', metavar='CONFIG_FILE',
help="""path to the configuration file.""",
default='/etc/os-net-config/config.yaml')
parser.add_argument('-m', '--mapping-file', metavar='MAPPING_FILE',
help="""path to the interface mapping file.""",
default='/etc/os-net-config/mapping.yaml')
parser.add_argument('-i', '--interfaces', metavar='INTERFACES',
help="""Identify the real interface for a nic name. """
"""If a real name is given, it is returned if live. """
"""If no value is given, display full NIC mapping. """
"""Exit after printing, ignoring other parameters. """,
nargs='*', default=None)
parser.add_argument('-p', '--provider', metavar='PROVIDER',
help="""The provider to use. """
"""One of: ifcfg, eni, nmstate, iproute.""",
default=None)
parser.add_argument('-r', '--root-dir', metavar='ROOT_DIR',
help="""The root directory of the filesystem.""",
default='')
parser.add_argument('--detailed-exit-codes',
action='store_true',
help="""Enable detailed exit codes. """
"""If enabled an exit code of '2' means """
"""that files were modified. """
"""Disabled by default.""",
default=False)
parser.add_argument(
'--exit-on-validation-errors',
action='store_true',
help="Exit with an error if configuration file validation fails. "
"Without this option, just log a warning and continue.",
default=False)
parser.add_argument(
'-d', '--debug',
dest="debug",
action='store_true',
help="Print debugging output.",
required=False)
parser.add_argument(
'-v', '--verbose',
dest="verbose",
action='store_true',
help="Print verbose output.",
required=False)
parser.add_argument('--version', action='version',
version=version.version_info.version_string())
parser.add_argument(
'--noop',
dest="noop",
action='store_true',
help="Return the configuration commands, without applying them.",
required=False)
parser.add_argument(
'--no-activate',
dest="no_activate",
action='store_true',
help="Install the configuration but don't start/stop interfaces.",
required=False)
parser.add_argument(
'--cleanup',
dest="cleanup",
action='store_true',
help="Cleanup unconfigured interfaces.",
required=False)
parser.add_argument(
'--persist-mapping',
dest="persist_mapping",
action='store_true',
help="Make aliases defined in the mapping file permanent "
"(WARNING, permanently renames nics).",
required=False)
opts = parser.parse_args(argv[1:])
return opts
def _is_sriovpf_obj_found(obj):
configure_sriov = False
if isinstance(obj, objects.SriovPF):
configure_sriov = True
elif hasattr(obj, 'members') and obj.members is not None:
for member in obj.members:
if isinstance(member, objects.SriovPF):
configure_sriov = True
break
else:
configure_sriov = _is_sriovpf_obj_found(member)
return configure_sriov
def disable_ipv6_for_netdevs(net_devices):
sysctl_conf = ""
for net_device in net_devices:
sysctl_conf += "net.ipv6.conf.%s.disable_ipv6 = 1\n" % net_device
utils.write_config(_SYSTEM_CTL_CONFIG_FILE, sysctl_conf)
def get_sriovpf_member_of_bond_ovs_port(obj):
net_devs_list = []
if isinstance(obj, objects.OvsBridge):
for member in obj.members:
if isinstance(member, objects.LinuxBond):
for child_member in member.members:
if isinstance(child_member, objects.SriovPF):
if child_member.link_mode == 'switchdev':
net_devs_list.append(child_member.name)
return net_devs_list
def main(argv=sys.argv, main_logger=None):
opts = parse_opts(argv)
if not main_logger:
main_logger = common.configure_logger(log_file=not opts.noop)
common.logger_level(main_logger, opts.verbose, opts.debug)
main_logger.info(f"Using config file at: {opts.config_file}")
iface_array = []
configure_sriov = False
sriovpf_bond_ovs_ports = []
provider = None
if opts.provider:
if opts.provider == 'ifcfg':
provider = impl_ifcfg.IfcfgNetConfig(noop=opts.noop,
root_dir=opts.root_dir)
elif opts.provider == 'eni':
provider = impl_eni.ENINetConfig(noop=opts.noop,
root_dir=opts.root_dir)
elif opts.provider == 'iproute':
provider = impl_iproute.IPRouteNetConfig(noop=opts.noop,
root_dir=opts.root_dir)
elif opts.provider == 'nmstate':
provider = impl_nmstate.NmstateNetConfig(noop=opts.noop,
root_dir=opts.root_dir)
else:
main_logger.error("Invalid provider specified.")
return 1
else:
if os.path.exists('%s/etc/sysconfig/network-scripts/' % opts.root_dir):
provider = impl_ifcfg.IfcfgNetConfig(noop=opts.noop,
root_dir=opts.root_dir)
opts.provider = "ifcfg"
elif os.path.exists('%s/etc/network/' % opts.root_dir):
provider = impl_eni.ENINetConfig(noop=opts.noop,
root_dir=opts.root_dir)
opts.provider = "eni"
else:
main_logger.error("Unable to set provider for this operating "
"system.")
return 1
# Read the interface mapping file, if it exists
# This allows you to override the default network naming abstraction
# mappings by specifying a specific nicN->name or nicN->MAC mapping
if os.path.exists(opts.mapping_file):
main_logger.info(f"Using mapping file at: {opts.mapping_file}")
with open(opts.mapping_file) as cf:
iface_map = yaml.safe_load(cf.read())
iface_mapping = iface_map.get("interface_mapping")
main_logger.debug(f"interface_mapping: {iface_mapping}")
persist_mapping = opts.persist_mapping
main_logger.debug(f"persist_mapping: {persist_mapping}")
else:
main_logger.info("Not using any mapping file.")
iface_mapping = None
persist_mapping = False
# If --interfaces is specified, either return the real name of the
# interfaces specified, or return the map of all nic abstractions/names.
if opts.interfaces is not None:
reported_nics = {}
mapped_nics = objects.mapped_nics(iface_mapping)
retval = 0
if len(opts.interfaces) > 0:
for requested_nic in opts.interfaces:
found = False
# Check to see if requested iface is a mapped NIC name.
if requested_nic in mapped_nics:
reported_nics[requested_nic] = mapped_nics[requested_nic]
found = True
# Check to see if the requested iface is a real NIC name
if requested_nic in mapped_nics.values():
if found is True: # Name matches alias and real NIC
# (return the mapped NIC, but warn of overlap).
main_logger.warning(f"{requested_nic} overlaps with "
"real NIC name.")
else:
reported_nics[requested_nic] = requested_nic
found = True
if not found:
retval = 1
if reported_nics:
main_logger.debug("Interface mapping requested for interface: "
"%s" % reported_nics.keys())
else:
main_logger.debug("Interface mapping requested for all interfaces")
reported_nics = mapped_nics
# Return the report on the mapped NICs. If all NICs were found, exit
# cleanly, otherwise exit with status 1.
main_logger.debug("Interface report requested, exiting after report.")
print(json.dumps(reported_nics))
return retval
# Read config file containing network configs to apply
if os.path.exists(opts.config_file):
try:
with open(opts.config_file) as cf:
iface_array = yaml.safe_load(cf.read()).get("network_config")
main_logger.debug(f"network_config: {iface_array}")
except IOError:
main_logger.error(f"Error reading file: {opts.config_file}")
return 1
else:
main_logger.error(f"No config file exists at: {opts.config_file}")
return 1
if not isinstance(iface_array, list):
main_logger.error("No interfaces defined in config: "
f"{opts.config_file}")
return 1
for iface_json in iface_array:
if iface_json.get('type') != 'route_table':
iface_json.update({'nic_mapping': iface_mapping})
iface_json.update({'persist_mapping': persist_mapping})
validation_errors = validator.validate_config(iface_array)
if validation_errors:
if opts.exit_on_validation_errors:
main_logger.error('\n'.join(validation_errors))
return 1
else:
main_logger.warning('\n'.join(validation_errors))
# Look for the presence of SriovPF types in the first parse of the json
# if SriovPFs exists then PF devices needs to be configured so that the VF
# devices are created.
# The VFs will not be available now and an exception
# SriovVfNotFoundException will be raised while fetching the device name.
# After the first parse the SR-IOV PF devices would be configured and the
# VF devices would be created.
# In the second parse, all other objects shall be added
for iface_json in iface_array:
try:
obj = objects.object_from_json(iface_json)
except utils.SriovVfNotFoundException:
continue
if _is_sriovpf_obj_found(obj):
configure_sriov = True
provider.add_object(obj)
# Look for the presence of SriovPF as members of LinuxBond and that
# LinuxBond is member of OvsBridge
sriovpf_bond_ovs_ports.extend(
get_sriovpf_member_of_bond_ovs_port(obj))
# After reboot, shared_block for pf interface in switchdev mode will be
# missing in case IPv6 is enabled on the slaves of the bond and that bond
# is an ovs port. This is due to the fact that OVS assumes another entity
# manages the slaves.
# So as a workaround for that case we are disabling IPv6 over pfs so that
# OVS creates the shared_blocks ingress
if sriovpf_bond_ovs_ports:
disable_ipv6_for_netdevs(sriovpf_bond_ovs_ports)
if configure_sriov:
# Apply the ifcfgs for PFs now, so that NM_CONTROLLED=no is applied
# for each of the PFs before configuring the numvfs for the PF device.
# This step allows the network manager to unmanage the created VFs.
# In the second parse, when these ifcfgs for PFs are encountered,
# os-net-config skips the ifup <ifcfg-pfs>, since the ifcfgs for PFs
# wouldn't have changed.
pf_files_changed = provider.apply(cleanup=opts.cleanup,
activate=not opts.no_activate)
if opts.provider == 'ifcfg' and not opts.noop:
restart_ovs = bool(sriovpf_bond_ovs_ports)
# Avoid ovs restart for os-net-config re-runs, which will
# dirupt the offload configuration
if os.path.exists(utils._SRIOV_CONFIG_SERVICE_FILE):
restart_ovs = False
utils.configure_sriov_pfs(
execution_from_cli=True,
restart_openvswitch=restart_ovs)
for iface_json in iface_array:
# All sriov_pfs at top level or at any member level will be
# ignored and all other objects are parsed will be added here.
# The VFs are expected to be available now and an exception
# SriovVfNotFoundException shall be raised if not available.
try:
obj = objects.object_from_json(iface_json)
except utils.SriovVfNotFoundException:
if not opts.noop:
raise
if not _is_sriovpf_obj_found(obj):
provider.add_object(obj)
if opts.provider == 'ifcfg' and configure_sriov and not opts.noop:
utils.configure_sriov_vfs()
files_changed = provider.apply(cleanup=opts.cleanup,
activate=not opts.no_activate)
if opts.noop:
if configure_sriov:
files_changed.update(pf_files_changed)
for location, data in files_changed.items():
print("File: %s\n" % location)
print(data)
print("----")
if opts.detailed_exit_codes and len(files_changed) > 0:
return 2
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv, main_logger=logger))

View File

@ -1,302 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, 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.
#
# Common functions and variables meant to be shared across various modules
# As opposed to utils, this is meant to be imported from anywhere. We can't
# import anything from os_net_config here.
import logging
import logging.handlers
import os
from oslo_concurrency import processutils
import sys
import yaml
# File to contain the DPDK mapped nics, as nic name will not be available after
# binding driver, which is required for correct nic numbering.
# Format of the file (list mapped nic's details):
# -
# name: eth1
# pci_address: 0000:02:00.0
# mac_address: 01:02:03:04:05:06
# driver: vfio-pci
DPDK_MAPPING_FILE = '/var/lib/os-net-config/dpdk_mapping.yaml'
# File to contain the list of SR-IOV PF, VF and their configurations
# Format of the file shall be
# - device_type: pf
# name: <pf name>
# numvfs: <number of VFs>
# promisc: "on"/"off"
# - device_type: vf
# device:
# name: <pf name>
# vfid: <VF id>
# name: <vf name>
# vlan_id: <vlan>
# qos: <qos>
# spoofcheck: "on"/"off"
# trust: "on"/"off"
# state: "auto"/"enable"/"disable"
# macaddr: <mac address>
# promisc: "on"/"off"
SRIOV_CONFIG_FILE = '/var/lib/os-net-config/sriov_config.yaml'
_SYS_BUS_PCI_DEV = '/sys/bus/pci/devices'
SYS_CLASS_NET = '/sys/class/net'
_LOG_FILE = '/var/log/os-net-config.log'
MLNX_VENDOR_ID = "0x15b3"
logger = logging.getLogger(__name__)
class OvsDpdkBindException(ValueError):
pass
def configure_logger(log_file=False, verbose=False, debug=False):
LOG_FORMAT = ('%(asctime)s.%(msecs)03d %(levelname)s '
'%(name)s.%(funcName)s %(message)s')
DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
logger = logging.getLogger("os_net_config")
logger.handlers.clear()
logger_level(logger, verbose, debug)
logger.propagate = True
formatter = logging.Formatter(fmt=LOG_FORMAT, datefmt=DATE_FORMAT)
if log_file:
file_handler = logging.handlers.RotatingFileHandler(
_LOG_FILE, maxBytes=10485760, backupCount=7
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
return logger
def logger_level(logger, verbose=False, debug=False):
log_level = logging.WARN
if debug:
log_level = logging.DEBUG
elif verbose:
log_level = logging.INFO
logger.setLevel(log_level)
def get_dev_path(ifname, path=None):
if not path:
path = ""
elif path.startswith("_"):
path = path[1:]
else:
path = f"device/{path}"
return os.path.join(SYS_CLASS_NET, ifname, path)
def get_pci_dev_path(pci_address, path=None):
if not path:
path = ""
elif path.startswith("_"):
path = path[1:]
return os.path.join(_SYS_BUS_PCI_DEV, pci_address, path)
def get_vendor_id(ifname):
try:
with open(get_dev_path(ifname, "vendor"), 'r') as f:
out = f.read().strip()
return out
except IOError:
return
def get_device_id(ifname):
try:
with open(get_dev_path(ifname, 'device'), 'r') as f:
out = f.read().strip()
return out
except IOError:
return
def get_file_data(filename):
if not os.path.exists(filename):
return ''
try:
with open(filename, 'r') as f:
return f.read()
except IOError:
logger.error(f"Error reading file: {filename}")
return ''
def get_sriov_map(pf_name=None):
contents = get_file_data(SRIOV_CONFIG_FILE)
sriov_map = yaml.safe_load(contents) if contents else []
if len(sriov_map) and pf_name:
return [pf for pf in sriov_map if pf['name'] == pf_name]
return sriov_map
def get_dpdk_map():
contents = get_file_data(DPDK_MAPPING_FILE)
dpdk_map = yaml.safe_load(contents) if contents else []
return dpdk_map
def _get_dpdk_mac_address(name):
contents = get_file_data(DPDK_MAPPING_FILE)
dpdk_map = yaml.safe_load(contents) if contents else []
for item in dpdk_map:
if item['name'] == name:
return item['mac_address']
def interface_mac(name):
try: # If the iface is part of a Linux bond, the real MAC is only here.
with open(get_dev_path(name, 'bonding_slave/perm_hwaddr'),
'r') as f:
return f.read().rstrip()
except IOError:
pass # Iface is not part of a bond, continue
try:
with open(get_dev_path(name, '_address'), 'r') as f:
return f.read().rstrip()
except IOError:
# If the interface is bound to a DPDK driver, get the mac address from
# the DPDK mapping file as /sys files will be removed after binding.
dpdk_mac_address = _get_dpdk_mac_address(name)
if dpdk_mac_address:
return dpdk_mac_address
logger.error("Unable to read mac address: %s" % name)
raise
def get_interface_driver_by_pci_address(pci_address):
try:
uevent = get_pci_dev_path(pci_address, 'uevent')
with open(uevent, 'r') as f:
out = f.read().strip()
for line in out.split('\n'):
if 'DRIVER' in line:
driver = line.split('=')
if len(driver) == 2:
return driver[1]
except IOError:
return
def is_mellanox_interface(ifname):
vendor_id = get_vendor_id(ifname)
return vendor_id == MLNX_VENDOR_ID
def is_vf(pci_address):
# If DPDK drivers are bound on a VF, then the path common.SYS_CLASS_NET
# wouldn't exist. Instead we look for the path
# /sys/bus/pci/devices/<PCI addr>/physfn to understand if the device
# is actually a VF. This path could be used by VFs not bound with
# DPDK drivers as well
vf_path_check = _SYS_BUS_PCI_DEV + '/%s/physfn' % pci_address
is_sriov_vf = os.path.isdir(vf_path_check)
return is_sriov_vf
def is_vf_by_name(interface_name, check_mapping_file=False):
vf_path_check = get_dev_path(interface_name, 'physfn')
is_sriov_vf = os.path.isdir(vf_path_check)
if not is_sriov_vf and check_mapping_file:
sriov_map = get_sriov_map()
for item in sriov_map:
if (item['name'] == interface_name and
item['device_type'] == 'vf'):
is_sriov_vf = True
return is_sriov_vf
def set_driverctl_override(pci_address, driver):
if driver is None:
logger.info(f"Driver override is not required for device"
"{pci_address}")
return False
iface_driver = get_interface_driver_by_pci_address(pci_address)
if iface_driver == driver:
logger.info(f"Driver {driver} is already bound to the device"
"{pci_address}")
return False
try:
if is_vf(pci_address):
out, err = processutils.execute('driverctl', '--nosave',
'set-override', pci_address,
driver)
else:
out, err = processutils.execute('driverctl', 'set-override',
pci_address, driver)
if err:
msg = f"Failed to bind dpdk interface {pci_address} err - {err}"
raise OvsDpdkBindException(msg)
except processutils.ProcessExecutionError:
msg = f"Failed to bind interface {pci_address} with dpdk"
raise OvsDpdkBindException(msg)
return err
def list_kmods(mods: list) -> list:
"""Listing Kernel Modules
Checks in currently loaded modules for a list
of modules and returns the ones that are not loaded
"""
try:
stdout, stderr = processutils.execute('lsmod')
except processutils.ProcessExecutionError as exc:
logger.error(f"Failed to get lsmod: {exc}")
raise
modules = set([line.split()[0] for line in stdout.strip().split('\n')])
return list(set(mods) - set(modules))
def load_kmods(mods: list):
"""Loading Kernel Modules
Loads modules from list that are not already loaded
"""
needed = list_kmods(mods)
for mod in needed:
try:
stdout, stderr = processutils.execute('modprobe', mod)
except processutils.ProcessExecutionError as exc:
logger.error(f"Failed to modprobe {mod}: {exc}")
raise
def restorecon(path: str):
"""Executes restorecon on a path"""
logger.info(f"Restoring selinux context on {path}")
try:
stdout, stderr = processutils.execute('restorecon', '-R', '-F', '-v',
path)
except processutils.ProcessExecutionError as exc:
logger.error(f"Failed to restorecon on {path}: {exc}")
raise
logger.debug(f"Restorecon completed: {stdout}")

View File

@ -1,256 +0,0 @@
# -*- Coding: utf-8 -*-
# Copyright 2014-2015 Red Hat, 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 logging
import netaddr
import os_net_config
from os_net_config import common
from os_net_config import objects
from os_net_config import utils
logger = logging.getLogger(__name__)
# TODO(?): should move to interfaces.d
def _network_config_path(prefix=''):
return prefix + "/etc/network/interfaces"
class ENINetConfig(os_net_config.NetConfig):
"""Debian/Ubuntu implementation for network config
Configure iface/bridge/routes using debian/ubuntu
/etc/network/interfaces format.
"""
def __init__(self, noop=False, root_dir=''):
super(ENINetConfig, self).__init__(noop, root_dir)
self.interfaces = {}
self.routes = {}
self.bridges = {}
logger.info('ENI net config provider created.')
def _add_common(self, interface, static_addr=None, ip_version=4):
ovs_extra = []
data = ""
address_data = ""
if static_addr:
address_data += " address %s\n" % static_addr.ip
if ip_version == 6:
address_data += " netmask %s\n" % static_addr.prefixlen
else:
address_data += " netmask %s\n" % static_addr.netmask
else:
v4_addresses = interface.v4_addresses()
if v4_addresses:
for v4_address in v4_addresses:
data += self._add_common(interface, v4_address)
v6_addresses = interface.v6_addresses()
if v6_addresses:
for v6_address in v6_addresses:
data += self._add_common(interface, v6_address, 6)
if data:
return data
if isinstance(interface, objects.Vlan):
_iface = "iface vlan%i " % interface.vlan_id
else:
_iface = "iface %s " % interface.name
if static_addr and static_addr.version == 6:
_iface += "inet6 "
else:
_iface += "inet "
if interface.use_dhcp:
_iface += "dhcp\n"
elif interface.addresses:
_iface += "static\n"
else:
_iface += "manual\n"
if isinstance(interface, objects.OvsBridge):
data += "auto %s\n" % interface.name
data += "allow-ovs %s\n" % interface.name
data += _iface
data += address_data
data += " ovs_type OVSBridge\n"
if interface.members:
data += " ovs_ports"
for i in interface.members:
data += " %s" % i.name
data += "\n"
for mem in interface.members:
if isinstance(mem, objects.Interface):
data += " pre-up ip addr flush dev %s\n" % mem.name
if interface.primary_interface_name:
mac = common.interface_mac(
interface.primary_interface_name)
ovs_extra.append("set bridge %s other-config:hwaddr=%s" %
(interface.name, mac))
ovs_extra.extend(interface.ovs_extra)
elif interface.ovs_port:
if isinstance(interface, objects.Vlan):
data += "auto vlan%i\n" % interface.vlan_id
data += "allow-%s vlan%i\n" % (interface.bridge_name,
interface.vlan_id)
data += _iface
data += address_data
data += " ovs_bridge %s\n" % interface.bridge_name
data += " ovs_type OVSIntPort\n"
data += " ovs_options tag=%s\n" % interface.vlan_id
else:
data += "auto %s\n" % interface.name
data += "allow-%s %s\n" % (interface.bridge_name,
interface.name)
data += _iface
data += address_data
data += " ovs_bridge %s\n" % interface.bridge_name
data += " ovs_type OVSPort\n"
elif isinstance(interface, objects.Vlan):
data += "auto vlan%i\n" % interface.vlan_id
data += _iface
data += address_data
data += " vlan-raw-device %s\n" % interface.device
else:
if isinstance(interface, objects.Interface) and interface.hotplug:
data += "allow-hotplug %s\n" % interface.name
else:
data += "auto %s\n" % interface.name
data += _iface
data += address_data
if interface.mtu:
data += " mtu %i\n" % interface.mtu
if interface.hwaddr:
raise NotImplementedError("hwaddr is not implemented.")
if ovs_extra:
data += " ovs_extra %s\n" % " -- ".join(ovs_extra)
return data
def add_interface(self, interface):
"""Add an Interface object to the net config object.
:param interface: The Interface object to add.
"""
logger.info('adding interface: %s' % interface.name)
data = self._add_common(interface)
logger.debug('interface data: %s' % data)
self.interfaces[interface.name] = data
if interface.routes:
self._add_routes(interface.name, interface.routes)
def add_bridge(self, bridge):
"""Add an OvsBridge object to the net config object.
:param bridge: The OvsBridge object to add.
"""
logger.info('adding bridge: %s' % bridge.name)
data = self._add_common(bridge)
logger.debug('bridge data: %s' % data)
self.bridges[bridge.name] = data
if bridge.routes:
self._add_routes(bridge.name, bridge.routes)
def add_vlan(self, vlan):
"""Add a Vlan object to the net config object.
:param vlan: The vlan object to add.
"""
logger.info('adding vlan: %s' % vlan.name)
data = self._add_common(vlan)
logger.debug('vlan data: %s' % data)
self.interfaces[vlan.name] = data
if vlan.routes:
self._add_routes(vlan.name, vlan.routes)
def _add_routes(self, interface_name, routes=[]):
logger.info('adding custom route for interface: %s' % interface_name)
data = ""
for route in routes:
options = ""
if route.route_options:
options = " %s" % (route.route_options)
if route.default and not route.ip_netmask:
rt = netaddr.IPNetwork("0.0.0.0/0")
else:
rt = netaddr.IPNetwork(route.ip_netmask)
data += "up route add -net %s netmask %s gw %s%s\n" % (
str(rt.ip), str(rt.netmask), route.next_hop, options)
data += "down route del -net %s netmask %s gw %s%s\n" % (
str(rt.ip), str(rt.netmask), route.next_hop, options)
self.routes[interface_name] = data
logger.debug('route data: %s' % self.routes[interface_name])
def apply(self, cleanup=False, activate=True):
"""Apply the network configuration.
:param cleanup: A boolean which indicates whether any undefined
(existing but not present in the object model) interface
should be disabled and deleted.
:param activate: A boolean which indicates if the config should
be activated by stopping/starting interfaces
:returns: a dict of the format: filename/data which contains info
for each file that was changed (or would be changed if in --noop
mode).
Note the noop mode is set via the constructor noop boolean
"""
new_config = ""
# write out bridges first. This ensures that an ifup -a
# on reboot brings them up first
for bridge_name, bridge_data in self.bridges.items():
route_data = self.routes.get(bridge_name)
bridge_data += (route_data or '')
new_config += bridge_data
for interface_name, iface_data in self.interfaces.items():
route_data = self.routes.get(interface_name)
iface_data += (route_data or '')
new_config += iface_data
if utils.diff(_network_config_path(self.root_dir), new_config):
if activate:
for interface in self.interfaces.keys():
self.ifdown(interface)
for bridge in self.bridges.keys():
self.ifdown(bridge, iftype='bridge')
self.write_config(_network_config_path(self.root_dir), new_config)
if activate:
for bridge in self.bridges.keys():
self.ifup(bridge, iftype='bridge')
for interface in self.interfaces.keys():
self.ifup(interface)
if self.errors:
message = 'Failure(s) occurred when applying configuration'
logger.error(message)
for e in self.errors:
logger.error('stdout: %s, stderr: %s', e.stdout,
e.stderr)
raise os_net_config.ConfigurationError(message)
else:
logger.info('No interface changes are required.')
return {_network_config_path(self.root_dir): new_config}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, 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 os_net_config
class IprouteNetConfig(os_net_config.NetConfig):
"""Configure network interfaces using iproute2."""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,137 +0,0 @@
# Copyright 2020 Red Hat, 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 logging
import os
import yaml
from oslo_concurrency import processutils
logger = logging.getLogger(__name__)
_PCI_DRIVER_BIND_FILE_PATH = "/sys/bus/pci/drivers/%(driver)s/bind"
_PCI_DRIVER_FILE_PATH = "/sys/bus/pci/devices/%(pci)s/driver"
_SRIOV_BIND_CONFIG_FILE = "/var/lib/os-net-config/sriov_bind_config.yaml"
_SRIOV_BIND_SERVICE_FILE = "/etc/systemd/system/sriov_bind.service"
_SRIOV_BIND_SERVICE_CONTENT = """[Unit]
Description=SR-IOV vfs binding
After=network.service sriov_config.service
[Service]
Type=oneshot
ExecStart=/usr/bin/os-net-config-sriov-bind
[Install]
WantedBy=multi-user.target
"""
# File to contain the map of drivers and it's VFs list that should be bound
# Format of the file shall be
# <driver1>:
# - '<VF1_PCI>'
# - '<VF2_PCI>'
# - '<VF3_PCI>'
# - '<VF4_PCI>'
# <driver2>:
# - '<VF5_PCI>'
# - '<VF6_PCI>'
# - '<VF7_PCI>'
# - '<VF8_PCI>'
def get_file_data(filename):
if not os.path.exists(filename):
logger.error("Error file is not exist: %s" % filename)
raise FileNotFoundError(filename)
try:
with open(filename, 'r') as f:
return f.read()
except IOError:
logger.error("Error reading file: %s" % filename)
raise
def ensure_directory_presence(filepath):
dir_path = os.path.dirname(filepath)
if not os.path.exists(dir_path):
os.makedirs(dir_path)
def write_yaml_config(filepath, data):
ensure_directory_presence(filepath)
with open(filepath, 'w') as f:
yaml.safe_dump(data, f, default_flow_style=False)
def update_sriov_bind_pcis_map(sriov_bind_pcis_map):
sriov_bind_config_data = {}
try:
sriov_bind_config_data = _get_sriov_bind_pcis_map()
except Exception:
pass
# Compare two levels of the dictionary to conditionally write
# sriov_bind_pcis_map if it differs from existning sriov_bind_config_data
if (sriov_bind_config_data == {} or
set(sriov_bind_config_data.keys()) !=
set(sriov_bind_pcis_map.keys()) or not
all([set(sriov_bind_config_data[key]) ==
set(sriov_bind_pcis_map[key]) for key in
sriov_bind_config_data])):
write_yaml_config(_SRIOV_BIND_CONFIG_FILE, sriov_bind_pcis_map)
def _get_sriov_bind_pcis_map():
contents = get_file_data(_SRIOV_BIND_CONFIG_FILE)
sriov_bind_pcis_map = yaml.safe_load(contents) if contents else {}
return sriov_bind_pcis_map
def configure_sriov_bind_service():
"""Generate the sriov_bind.service
sriov_bind service shall bind all the vfs of switchdev-mode mlnx SriovPF
nics during reboot of the nodes.
"""
with open(_SRIOV_BIND_SERVICE_FILE, 'w') as f:
f.write(_SRIOV_BIND_SERVICE_CONTENT)
processutils.execute('systemctl', 'enable', 'sriov_bind')
def bind_vfs(sriov_bind_pcis_map=None):
if not sriov_bind_pcis_map:
sriov_bind_pcis_map = _get_sriov_bind_pcis_map()
for driver, pcis_list in sriov_bind_pcis_map.items():
for vf_pci in pcis_list:
vf_pci_driver_path = _PCI_DRIVER_FILE_PATH % {"pci": vf_pci}
if not os.path.exists(vf_pci_driver_path):
pci_driver_bind_file_path = _PCI_DRIVER_BIND_FILE_PATH %\
{"driver": driver}
try:
with open(pci_driver_bind_file_path, 'w') as f:
f.write("%s" % vf_pci)
logger.info("Vf %s has been bound" % vf_pci)
except IOError:
logger.error("Failed to bind vf %s" % vf_pci)
def main():
bind_vfs()
if __name__ == "__main__":
main()

View File

@ -1,816 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, 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.
#
# The sriov_config.py module does the SR-IOV PF configuration.
# It'll be invoked by the sriov_config systemd service for the persistence of
# the SR-IOV configuration across reboots. And os-net-config:utils also invokes
# it for the first time configuration.
# An entry point os-net-config-sriov is added for invocation of this module.
import argparse
import os
import pyudev
import queue
import re
import sys
import time
from json import loads
from os_net_config import common
from os_net_config import sriov_bind_config
from oslo_concurrency import processutils
logger = common.configure_logger()
_UDEV_RULE_FILE = '/etc/udev/rules.d/80-persistent-os-net-config.rules'
_UDEV_LEGACY_RULE_FILE = '/etc/udev/rules.d/70-os-net-config-sriov.rules'
_IFUP_LOCAL_FILE = '/sbin/ifup-local'
_RESET_SRIOV_RULES_FILE = '/etc/udev/rules.d/70-tripleo-reset-sriov.rules'
_ALLOCATE_VFS_FILE = '/etc/sysconfig/allocate_vfs'
_MLNX_DRIVER = "mlx5_core"
MLNX_UNBIND_FILE_PATH = "/sys/bus/pci/drivers/mlx5_core/unbind"
MLNX5_VDPA_KMODS = [
"vdpa",
"vhost_vdpa",
"mlx5_vdpa",
]
MAX_RETRIES = 10
MLNX_LAG_PATH = "/sys/kernel/debug/mlx5/{pf_pci}/lag/state"
PF_FUNC_RE = re.compile(r"\.(\d+)$", 0)
VF_PCI_RE = re.compile(r'/[\d]{4}\:(\d+):(\d+)\.(\d+)/net/[^\/]+$')
# In order to keep VF representor name consistent specially after the upgrade
# proccess, we should have a udev rule to handle that.
# The udev rule will rename the VF representor as "<sriov_pf_name>_<vf_num>"
_REP_LINK_NAME_FILE = "/etc/udev/rep-link-name.sh"
_REP_LINK_NAME_DATA = '''#!/bin/bash
# This file is autogenerated by os-net-config
set -x
PORT="$1"
echo "NUMBER=${PORT##pf*vf}"
'''
# Create a queue for passing the udev network events
vf_queue = queue.Queue()
# Global variable to store link between pci/pf
# for udev rule creationg when dealing with mlnx vdpa
vf_to_pf = {}
class SRIOVNumvfsException(ValueError):
pass
def udev_event_handler(action, device):
event = {"action": action, "device": device.sys_path}
logger.info(
f"Received udev event {event['action']} for {event['device']}"
)
vf_queue.put(event)
def _norm_path(dev, suffix):
return os.path.normpath(os.path.join(dev, suffix))
def _get_pf_path(device):
pf_path = _norm_path(device, "../../physfn/net")
if not os.path.isdir(pf_path):
pf_path = _norm_path(device, "physfn/net")
if not os.path.isdir(pf_path):
pf_path = None
return pf_path
def _driver_unbind(dev):
vf_pci_path = f"/sys/bus/pci/devices/{dev}/driver"
if os.path.exists(vf_pci_path):
logger.info(f"{dev}: Unbinding driver")
with open(MLNX_UNBIND_FILE_PATH, 'w') as f:
f.write(dev)
else:
logger.info(f"{dev}: No driver to unbind")
def _wait_for_vf_creation(pf_name, numvfs):
vf_count = 0
pf_config = common.get_sriov_map(pf_name)
vdpa = False
if len(pf_config):
vdpa = pf_config[0].get('vdpa', False)
while vf_count < numvfs:
try:
# wait for 5 seconds after every udev event
event = vf_queue.get(True, 5)
vf_name = os.path.basename(event["device"])
pf_path = _get_pf_path(event["device"])
logger.debug(f"{event['device']}: Got udev event: {event}")
if pf_path:
pf_nic = os.listdir(pf_path)
# NOTE(dvd): For vDPA devices, the VF event we're interrested
# in contains all the VFs. We can also use this to build a dict
# to correlate the VF pci address to the PF when creating the
# vdpa representator udev rule
#
# Data structure sample for vDPA:
# pf_path:
# /sys/devices/pci0000:00/0000:00:02.2/0000:06:01.2/physfn/net
# pf_nic: ['enp6s0f1np1_0', 'enp6s0f1np1_1', 'enp6s0f1np1']
# pf_name: enp6s0f1np1
if vf_name not in vf_to_pf and pf_name in pf_nic:
vf_to_pf[vf_name] = {
'device': event['device'],
'pf': pf_name
}
logger.info(
f"{pf_name}: VF {vf_name} created"
)
vf_count += 1
elif vf_name in vf_to_pf:
logger.debug(
f"{pf_name}: VF {vf_name} was already created"
)
elif vdpa:
logger.warning(f"{pf_name}: This PF is not in {pf_path}")
else:
logger.warning(
f"{pf_name}: Unable to parse event {event['device']}"
)
elif not vdpa:
logger.warning(f"{event['device']}: Unable to find PF")
except queue.Empty:
logger.info(f"{pf_name}: Timeout in the creation of VFs")
return
logger.info(f"{pf_name}: Required VFs are created")
def get_numvfs(ifname):
"""Getting sriov_numvfs for PF
Wrapper that will get the sriov_numvfs file for a PF.
:param ifname: interface name (ie: p1p1)
:returns: int -- the number of current VFs on ifname
:raises: SRIOVNumvfsException
"""
sriov_numvfs_path = common.get_dev_path(ifname, "sriov_numvfs")
logger.debug(f"{ifname}: Getting numvfs for interface")
try:
with open(sriov_numvfs_path, 'r') as f:
curr_numvfs = int(f.read())
except IOError as exc:
msg = f"{ifname}: Unable to read numvfs: {exc}"
raise SRIOVNumvfsException(msg)
logger.debug(f"{ifname}: Interface has {curr_numvfs} configured")
return curr_numvfs
def set_numvfs(ifname, numvfs):
"""Setting sriov_numvfs for PF
Wrapper that will set the sriov_numvfs file for a PF.
After numvfs has been set for an interface, _wait_for_vf_creation will be
called to monitor the creation.
Some restrictions:
- if current number of VF is already defined, we can't change numvfs
- if sriov_numvfs doesn't exist for an interface, we can't create it
:param ifname: interface name (ie: p1p1)
:param numvfs: an int that represents the number of VFs to be created.
:returns: int -- the number of current VFs on ifname
:raises: SRIOVNumvfsException
"""
curr_numvfs = get_numvfs(ifname)
logger.debug(f"{ifname}: Interface has {curr_numvfs} configured, setting "
f"to {numvfs}")
if not isinstance(numvfs, int):
msg = (f"{ifname}: Unable to configure pf with numvfs: {numvfs}\n"
f"numvfs must be an integer")
raise SRIOVNumvfsException(msg)
if numvfs != curr_numvfs:
if curr_numvfs != 0:
logger.warning(f"{ifname}: Numvfs already configured to "
f"{curr_numvfs}")
return curr_numvfs
sriov_numvfs_path = common.get_dev_path(ifname, "sriov_numvfs")
try:
logger.debug(f"Setting {sriov_numvfs_path} to {numvfs}")
with open(sriov_numvfs_path, "w") as f:
f.write("%d" % numvfs)
except IOError as exc:
msg = (f"{ifname} Unable to configure pf with numvfs: {numvfs}\n"
f"{exc}")
raise SRIOVNumvfsException(msg)
_wait_for_vf_creation(ifname, numvfs)
curr_numvfs = get_numvfs(ifname)
if curr_numvfs != numvfs:
msg = (f"{ifname}: Unable to configure pf with numvfs: {numvfs}\n"
"sriov_numvfs file is not set to the targeted number of "
"vfs")
raise SRIOVNumvfsException(msg)
return curr_numvfs
def restart_ovs_and_pfs_netdevs():
sriov_map = common.get_sriov_map()
processutils.execute('/usr/bin/systemctl', 'restart', 'openvswitch')
for item in sriov_map:
if item['device_type'] == 'pf':
if_down_interface(item['name'])
if_up_interface(item['name'])
def cleanup_puppet_config():
file_contents = ""
if os.path.exists(_RESET_SRIOV_RULES_FILE):
os.remove(_RESET_SRIOV_RULES_FILE)
if os.path.exists(_ALLOCATE_VFS_FILE):
os.remove(_ALLOCATE_VFS_FILE)
if os.path.exists(_IFUP_LOCAL_FILE):
# Remove the invocation of allocate_vfs script generated by puppet
# After the removal of allocate_vfs, if the ifup-local file has just
# "#!/bin/bash" left, then remove the file as well.
with open(_IFUP_LOCAL_FILE) as oldfile:
for line in oldfile:
if "/etc/sysconfig/allocate_vfs" not in line:
file_contents = file_contents + line
if file_contents.strip() == "#!/bin/bash":
os.remove(_IFUP_LOCAL_FILE)
else:
with open(_IFUP_LOCAL_FILE, 'w') as newfile:
newfile.write(file_contents)
def udev_monitor_setup():
# Create a context for pyudev and observe udev events for network
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('net')
observer = pyudev.MonitorObserver(monitor, udev_event_handler)
return observer
def udev_monitor_start(observer):
observer.start()
def udev_monitor_stop(observer):
observer.stop()
def is_partitioned_pf(dev_name: str) -> bool:
"""Check if any nic-partition(VF) is already used
Given a PF device, returns True if any VFs of this
device are in-use.
"""
sriov_map = common.get_sriov_map()
for config in sriov_map:
devtype = config.get('device_type', None)
if devtype == 'vf':
name = config.get('device', {}).get('name')
vf_name = config.get('name')
if dev_name == name:
logger.warning(f"{name} has VF({vf_name}) used by host")
return True
return False
def configure_sriov_pf(execution_from_cli=False, restart_openvswitch=False):
observer = udev_monitor_setup()
udev_monitor_start(observer)
sriov_map = common.get_sriov_map()
dpdk_vfs_pcis_list = []
vf_lag_sriov_pfs_list = []
trigger_udev_rule = False
# Cleanup the previous config by puppet-tripleo
cleanup_puppet_config()
if any(item.get('vdpa') for item in sriov_map):
common.load_kmods(MLNX5_VDPA_KMODS)
vdpa_devices = get_vdpa_vhost_devices()
for item in sriov_map:
if item['device_type'] == 'pf':
if pf_configure_status(item):
logger.debug(f"PF {item['name']} is already configured")
continue
_pf_interface_up(item)
if item.get('link_mode') == "legacy":
# Add a udev rule to configure the VF's when PF's are
# released by a guest
if not is_partitioned_pf(item['name']):
add_udev_rule_for_legacy_sriov_pf(item['name'],
item['numvfs'])
# When configuring vdpa, we need to configure switchdev before
# we create the VFs
is_mlnx = common.is_mellanox_interface(item['name'])
vdpa = item.get('vdpa')
# Configure switchdev mode when vdpa
# It has to happen before we set_numvfs
if vdpa and is_mlnx:
configure_switchdev(item['name'])
set_numvfs(item['name'], item['numvfs'])
# Configure switchdev, unbind driver and configure vdpa
if item.get('link_mode') == "switchdev" and is_mlnx:
logger.info(f"{item['name']}: Mellanox card")
vf_pcis_list = get_vf_pcis_list(item['name'])
for vf_pci in vf_pcis_list:
if not vdpa:
# For DPDK, we need to unbind the driver
_driver_unbind(vf_pci)
else:
if vf_pci not in vdpa_devices:
configure_vdpa_vhost_device(vf_pci)
else:
logger.info(
f"{item['name']}: vDPA device already created "
f"for {vf_pci}"
)
if vdpa:
common.restorecon('/dev/vhost-*')
logger.info(f"{item['name']}: Adding udev rules")
# Adding a udev rule to make vf-representors unmanaged by
# NetworkManager
add_udev_rule_to_unmanage_vf_representors_by_nm()
# Adding a udev rule to save the sriov_pf name
trigger_udev_rule = add_udev_rule_for_sriov_pf(item['name'])\
or trigger_udev_rule
trigger_udev_rule = add_udev_rule_for_vf_representors(
item['name']) or trigger_udev_rule
if not vdpa:
# This is used for the sriov_bind_config
dpdk_vfs_pcis_list += vf_pcis_list
# Configure flow steering mode, default to smfs
configure_flow_steering(item['name'],
item.get('steering_mode', 'smfs'))
# Configure switchdev mode
configure_switchdev(item['name'])
# Add sriovpf to vf_lag_sriov_pfs_list if it's
# a linux bond member (lag_candidate)
if item.get('lag_candidate', False):
vf_lag_sriov_pfs_list.append(item['name'])
# Adding a udev rule to rename vf-representors
else:
trigger_udev_rule = add_udev_rule_for_vdpa_representors(
item['name']) or trigger_udev_rule
# Moving the sriov-PFs to switchdev mode will put the netdev
# interfaces in down state.
# In case we are running during initial deployment,
# bring the interfaces up.
# In case we are running as part of the sriov_config service
# after reboot, net config scripts, which run after
# sriov_config service will bring the interfaces up.
if execution_from_cli:
if_up_interface(item['name'])
if restart_openvswitch:
restart_ovs_and_pfs_netdevs()
if vf_lag_sriov_pfs_list and execution_from_cli:
_wait_for_lag_creation(vf_lag_sriov_pfs_list)
if dpdk_vfs_pcis_list and not vdpa:
sriov_bind_pcis_map = {_MLNX_DRIVER: dpdk_vfs_pcis_list}
if not execution_from_cli:
sriov_bind_config.update_sriov_bind_pcis_map(sriov_bind_pcis_map)
else:
sriov_bind_config.configure_sriov_bind_service()
sriov_bind_config.bind_vfs(sriov_bind_pcis_map)
# Trigger udev rules if there is new rules written
if trigger_udev_rule:
trigger_udev_rules()
udev_monitor_stop(observer)
def _wait_for_uplink_rep_creation(pf_name):
uplink_rep_phys_switch_id_path = f"/sys/class/net/{pf_name}/phys_switch_id"
for i in range(MAX_RETRIES):
if common.get_file_data(uplink_rep_phys_switch_id_path):
logger.info(f"{pf_name} Uplink representor ready")
break
time.sleep(1)
else:
raise RuntimeError(f"{pf_name}: Timeout waiting uplink representor")
def _wait_for_lag_creation(lag_sriov_pf_list):
for sriov_pf in lag_sriov_pf_list:
pf_pci = get_pf_pci(sriov_pf)
lag_path = MLNX_LAG_PATH.format(pf_pci=pf_pci)
if os.path.exists(lag_path):
for i in range(MAX_RETRIES):
lag_state = common.get_file_data(lag_path).strip()
if lag_state == "active":
logger.info(f"VF-LAG is enabled for interface {sriov_pf}"
f" after {i} retries")
break
time.sleep(1)
else:
raise RuntimeError("VF-LAG is not created for interface"
f" {sriov_pf} after {i} retries")
else:
logger.warning(f"Lag path {lag_path} does not exist for this "
"kernel, skipping..")
def create_rep_link_name_script():
with open(_REP_LINK_NAME_FILE, "w") as f:
f.write(_REP_LINK_NAME_DATA)
# Make the _REP_LINK_NAME_FILE executable
os.chmod(_REP_LINK_NAME_FILE, 0o755)
def add_udev_rule_for_sriov_pf(pf_name):
logger.info(f"{pf_name}: adding udev rules for sriov")
pf_pci = get_pf_pci(pf_name)
udev_data_line = 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\
f'KERNELS=="{pf_pci}", NAME="{pf_name}"'
return add_udev_rule(udev_data_line, _UDEV_RULE_FILE)
def add_udev_rule_for_legacy_sriov_pf(pf_name, numvfs):
logger.info(f"{pf_name}: adding udev rules for legacy sriov: {numvfs}")
udev_line = f'KERNEL=="{pf_name}", '\
f'RUN+="/bin/os-net-config-sriov -n %k:{numvfs}"'
pattern = f'KERNEL=="{pf_name}", RUN+="/bin/os-net-config-sriov -n'
return add_udev_rule(udev_line, _UDEV_LEGACY_RULE_FILE, pattern)
def add_udev_rule_for_vf_representors(pf_name):
logger.info(f"{pf_name}: adding udev rules for vf representators")
phys_switch_id_path = common.get_dev_path(pf_name,
"_phys_switch_id")
phys_switch_id = common.get_file_data(phys_switch_id_path).strip()
pf_pci = get_pf_pci(pf_name)
pf_fun_num_match = PF_FUNC_RE.search(pf_pci)
if not pf_fun_num_match:
logger.error(f"{pf_name}: Failed to get function number "
"and so failed to create a udev rule for renaming "
"its vf-represent")
return
pf_fun_num = pf_fun_num_match.group(1)
udev_data_line = 'SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}'\
'=="%s", ATTR{phys_port_name}=="pf%svf*", '\
'IMPORT{program}="%s $attr{phys_port_name}", '\
'NAME="%s_$env{NUMBER}"' % (phys_switch_id,
pf_fun_num,
_REP_LINK_NAME_FILE,
pf_name)
create_rep_link_name_script()
return add_udev_rule(udev_data_line, _UDEV_RULE_FILE)
def add_udev_rule_for_vdpa_representors(pf_name):
logger.info(f"{pf_name}: adding udev rules for vdpa representators")
udev_lines = ""
for vf, att in vf_to_pf.items():
mac = common.interface_mac(vf)
vadd = VF_PCI_RE.search(att.get('device'))
if not vadd:
logger.error(
f"{att.get('device')}/{vf}: Failed to get pf/vf numbers "
"and so failed to create a udev rule for renaming vdpa dev"
)
continue
vdpa_rep = f"vdpa{vadd.group(1)}p{vadd.group(2)}vf{vadd.group(3)}"
logger.info(f"{vdpa_rep}: Adding udev representor rule.")
udev_lines += (
'SUBSYSTEM=="net", ACTION=="add", '
f'ATTR{{address}}=="{mac}", NAME="{vdpa_rep}"\n'
)
return add_udev_rule(udev_lines, _UDEV_RULE_FILE)
def add_udev_rule_to_unmanage_vf_representors_by_nm():
logger.info("adding udev rules to unmanage vf representators")
udev_data_line = 'SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}'\
'!="", ATTR{phys_port_name}=="pf*vf*", '\
'ENV{NM_UNMANAGED}="1"'
return add_udev_rule(udev_data_line, _UDEV_RULE_FILE)
def add_udev_rule(udev_data, udev_file, pattern=None):
logger.debug(f"adding udev rule to {udev_file}: {udev_data}")
trigger_udev_rule = False
udev_data = udev_data.strip()
if not pattern:
pattern = udev_data
if not os.path.exists(udev_file):
with open(udev_file, "w") as f:
data = "# This file is autogenerated by os-net-config\n"\
f"{udev_data}\n"
f.write(data)
else:
file_data = common.get_file_data(udev_file)
udev_lines = file_data.splitlines()
if pattern in file_data:
if udev_data in udev_lines:
return trigger_udev_rule
with open(udev_file, "w") as f:
for line in udev_lines:
if pattern in line:
f.write(udev_data + "\n")
else:
f.write(line + "\n")
else:
with open(udev_file, "a") as f:
f.write(udev_data + "\n")
reload_udev_rules()
trigger_udev_rule = True
return trigger_udev_rule
def reload_udev_rules():
try:
processutils.execute('/usr/sbin/udevadm', 'control', '--reload-rules')
logger.info("udev rules reloaded successfully")
except processutils.ProcessExecutionError as exc:
logger.error(f"Failed to reload udev rules: {exc}")
raise
def trigger_udev_rules():
try:
processutils.execute('/usr/sbin/udevadm', 'trigger', '--action=add',
'--attr-match=subsystem=net')
logger.info("udev rules triggered successfully")
except processutils.ProcessExecutionError as exc:
logger.error(f"Failed to trigger udev rules: {exc}")
raise
def configure_switchdev(pf_name):
pf_pci = get_pf_pci(pf_name)
pf_device_id = get_pf_device_id(pf_name)
if pf_device_id == "0x1013" or pf_device_id == "0x1015":
try:
processutils.execute('/usr/sbin/devlink', 'dev', 'eswitch', 'set',
f'pci/{pf_pci}', 'inline-mode', 'transport')
except processutils.ProcessExecutionError as exc:
logger.error(f"{pf_name}: Failed to set inline-mode to transport "
f"for {pf_pci}: {exc}")
raise
try:
processutils.execute('/usr/sbin/devlink', 'dev', 'eswitch', 'set',
f'pci/{pf_pci}', 'mode', 'switchdev')
except processutils.ProcessExecutionError as exc:
logger.error(f"{pf_name}: Failed to set mode to switchdev for "
f"{pf_pci}: {exc}")
raise
logger.info(f"{pf_name}: Device pci/{pf_pci} set to switchdev mode.")
# WA to make sure that the uplink_rep is ready after moving to switchdev,
# as moving to switchdev will remove the sriov_pf and create uplink
# representor, so we need to make sure that uplink representor is ready
# before proceed
_wait_for_uplink_rep_creation(pf_name)
try:
processutils.execute('/usr/sbin/ethtool', '-K', pf_name,
'hw-tc-offload', 'on')
logger.info(f"{pf_name}: Enabled \"hw-tc-offload\" for PF.")
except processutils.ProcessExecutionError as exc:
logger.error(f"{pf_name}: Failed to enable hw-tc-offload: {exc}")
raise
def get_vdpa_vhost_devices():
logger.info(f"Getting list of vdpa devices")
try:
stdout, stderr = processutils.execute('vdpa', '-j', 'dev')
except processutils.ProcessExecutionError as exc:
logger.error(f"Failed to get vdpa vhost devices: {exc}")
raise
return loads(stdout)['dev']
def configure_vdpa_vhost_device(pci):
logger.info(f"{pci}: Creating vdpa device")
try:
processutils.execute('vdpa', 'dev', 'add', 'name', pci,
'mgmtdev', f'pci/{pci}')
except processutils.ProcessExecutionError as exc:
logger.error(f"{pci}: Failed to create vdpa vhost device: {exc}")
raise
def configure_flow_steering(pf_name, steering_mode):
pf_pci = get_pf_pci(pf_name)
try:
processutils.execute('/usr/sbin/devlink', 'dev', 'param', 'set',
f'pci/{pf_pci}', 'name', 'flow_steering_mode',
'value', steering_mode, 'cmode', 'runtime')
logger.info(f"{pf_name}: Device pci/{pf_pci} is set to"
" {steering_mode} steering mode.")
except processutils.ProcessExecutionError as exc:
logger.warning(f"{pf_name}: Could not set pci/{pf_pci} to"
f" {steering_mode} steering mode: {exc}")
def run_ip_config_cmd(*cmd, **kwargs):
logger.info("Running %s" % ' '.join(cmd))
try:
processutils.execute(*cmd, delay_on_retry=True, attempts=10, **kwargs)
except processutils.ProcessExecutionError as exc:
logger.error("Failed to execute %s: %s" % (' '.join(cmd), exc))
raise
def _pf_interface_up(pf_device):
if 'promisc' in pf_device:
run_ip_config_cmd('ip', 'link', 'set', 'dev', pf_device['name'],
'promisc', pf_device['promisc'])
logger.info(f"{pf_device['name']}: Bringing up PF")
run_ip_config_cmd('ip', 'link', 'set', 'dev', pf_device['name'], 'up')
def pf_configure_status(pf_device):
return pf_device['numvfs'] == get_numvfs(pf_device['name'])
def run_ip_config_cmd_safe(raise_error, *cmd, **kwargs):
try:
run_ip_config_cmd(*cmd)
except processutils.ProcessExecutionError:
if raise_error:
raise
def get_pf_pci(pf_name):
pf_pci_path = common.get_dev_path(pf_name, "uevent")
pf_info = common.get_file_data(pf_pci_path)
pf_pci = re.search(r'PCI_SLOT_NAME=(.*)', pf_info, re.MULTILINE).group(1)
return pf_pci
def get_pf_device_id(pf_name):
pf_device_path = common.get_dev_path(pf_name, "device")
pf_device_id = common.get_file_data(pf_device_path).strip()
return pf_device_id
def get_vf_pcis_list(pf_name):
vf_pcis_list = []
pf_files = os.listdir(common.get_dev_path(pf_name, "_device"))
for pf_file in pf_files:
if pf_file.startswith("virtfn"):
vf_info = common.get_file_data(common.get_dev_path(pf_name,
f"{pf_file}/uevent"))
vf_pcis_list.append(re.search(r'PCI_SLOT_NAME=(.*)',
vf_info, re.MULTILINE).group(1))
return vf_pcis_list
def if_down_interface(device):
logger.info(f"{device}: Running /sbin/ifdown")
try:
processutils.execute('/sbin/ifdown', device)
except processutils.ProcessExecutionError:
logger.error(f"{device}: Failed to ifdown")
raise
def if_up_interface(device):
logger.info(f"{device}: Running /sbin/ifup")
try:
processutils.execute('/sbin/ifup', device)
except processutils.ProcessExecutionError:
logger.error(f"{device}: Failed to ifup")
raise
def configure_sriov_vf():
sriov_map = common.get_sriov_map()
for item in sriov_map:
raise_error = True
if item['device_type'] == 'vf':
pf_name = item['device']['name']
vfid = item['device']['vfid']
base_cmd = ('ip', 'link', 'set', 'dev', pf_name, 'vf', str(vfid))
logger.info(f"{pf_name}: Configuring settings for VF: {vfid} "
f"VF name: {item['name']}")
raise_error = True
if 'macaddr' in item:
cmd = base_cmd + ('mac', item['macaddr'])
run_ip_config_cmd(*cmd)
if 'vlan_id' in item:
vlan_cmd = base_cmd + ('vlan', str(item['vlan_id']))
if 'qos' in item:
vlan_cmd = vlan_cmd + ('qos', str(item['qos']))
run_ip_config_cmd(*vlan_cmd)
if 'max_tx_rate' in item:
cmd = base_cmd + ('max_tx_rate', str(item['max_tx_rate']))
if item['max_tx_rate'] == 0:
raise_error = False
run_ip_config_cmd_safe(raise_error, *cmd)
if 'min_tx_rate' in item:
cmd = base_cmd + ('min_tx_rate', str(item['min_tx_rate']))
if item['min_tx_rate'] == 0:
raise_error = False
run_ip_config_cmd_safe(raise_error, *cmd)
if 'spoofcheck' in item:
cmd = base_cmd + ('spoofchk', item['spoofcheck'])
run_ip_config_cmd(*cmd)
if 'state' in item:
cmd = base_cmd + ('state', item['state'])
run_ip_config_cmd(*cmd)
if 'trust' in item:
cmd = base_cmd + ('trust', item['trust'])
run_ip_config_cmd(*cmd)
if 'promisc' in item:
run_ip_config_cmd('ip', 'link', 'set', 'dev', item['name'],
'promisc', item['promisc'])
if 'driver' in item:
common.set_driverctl_override(item['pci_address'],
item['driver'])
def parse_opts(argv):
parser = argparse.ArgumentParser(
description='Configure SR-IOV PF and VF interfaces using a YAML'
' config file format.')
parser.add_argument(
'-d', '--debug',
dest="debug",
action='store_true',
help="Print debugging output.",
required=False)
parser.add_argument(
'-v', '--verbose',
dest="verbose",
action='store_true',
help="Print verbose output.",
required=False)
parser.add_argument(
'-n', '--numvfs',
dest="numvfs",
action='store',
help="Provide the numvfs for device in the format <device>:<numvfs>",
required=False)
opts = parser.parse_args(argv[1:])
return opts
def main(argv=sys.argv, main_logger=None):
opts = parse_opts(argv)
if not main_logger:
main_logger = common.configure_logger(log_file=True)
common.logger_level(main_logger, opts.verbose, opts.debug)
if opts.numvfs:
if re.match(r"^\w+:\d+$", opts.numvfs):
device_name, numvfs = opts.numvfs.split(':')
set_numvfs(device_name, int(numvfs))
else:
main_logger.error(f"Invalid arguments for --numvfs {opts.numvfs}")
return 1
else:
# Configure the PF's
configure_sriov_pf()
# Configure the VFs
configure_sriov_vf()
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@ -1,77 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# 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 os
import fixtures
import testtools
_TRUE_VALUES = ('True', 'true', '1', 'yes')
class TestCase(testtools.TestCase):
"""Test case base class for all unit tests."""
stub_mapped_nics = True
def setUp(self):
"""Run before each test method to initialize test environment."""
super(TestCase, self).setUp()
self.stubbed_mapped_nics = {}
def dummy_mapped_nics(nic_mapping=None):
return self.stubbed_mapped_nics
if self.stub_mapped_nics:
self.stub_out('os_net_config.objects.mapped_nics',
dummy_mapped_nics)
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
try:
test_timeout = int(test_timeout)
except ValueError:
# If timeout value is invalid do not set a timeout.
test_timeout = 0
if test_timeout > 0:
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
self.useFixture(fixtures.NestedTempfile())
self.useFixture(fixtures.TempHomeDir())
if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
self.log_fixture = self.useFixture(fixtures.FakeLogger())
def stub_out(self, old, new):
"""Replace a function for the duration of the test.
Use the monkey patch fixture to replace a function for the
duration of a test. Useful when you want to provide fake
methods instead of mocks during testing.
This should be used instead of set.stubs.Set (which is based
on mox) going forward.
"""
self.useFixture(fixtures.MonkeyPatch(old, new))
def tearDown(self):
super(TestCase, self).tearDown()

View File

@ -1,438 +0,0 @@
dns-resolver:
config: {}
hostname:
config: dell-r640-oss-14.lab.eng.brq.redhat.com
running: dell-r640-oss-14.lab.eng.brq.redhat.com
interfaces:
- accept-all-mac-addresses: false
ethernet:
auto-negotiation: true
duplex: full
speed: 1000
sr-iov:
total-vfs: 0
vfs: []
ethtool:
coalesce:
adaptive-rx: true
adaptive-tx: true
rx-usecs: 50
rx-usecs-high: 0
tx-frames-irq: 256
tx-usecs: 50
tx-usecs-high: 0
feature:
highdma: true
hw-tc-offload: false
l2-fwd-offload: false
rx-checksum: true
rx-gro: true
rx-gro-list: false
rx-hashing: true
rx-ntuple-filter: true
rx-udp-gro-forwarding: false
rx-udp_tunnel-port-offload: true
rx-vlan-hw-parse: true
tx-checksum-ip-generic: true
tx-checksum-sctp: true
tx-generic-segmentation: true
tx-gre-csum-segmentation: true
tx-gre-segmentation: true
tx-gso-partial: true
tx-ipxip4-segmentation: true
tx-ipxip6-segmentation: true
tx-nocache-copy: false
tx-tcp-ecn-segmentation: true
tx-tcp-mangleid-segmentation: false
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
tx-udp_tnl-csum-segmentation: true
tx-udp_tnl-segmentation: true
tx-vlan-hw-insert: true
pause:
autoneg: true
rx: false
tx: false
ring:
rx: 512
rx-max: 4096
tx: 512
tx-max: 4096
ipv4:
address: []
auto-dns: true
auto-gateway: true
auto-route-table-id: 0
auto-routes: true
dhcp: true
enabled: true
ipv6:
addr-gen-mode: eui64
address:
- ip: fe80::e643:4bff:fe5c:9680
prefix-length: 64
auto-dns: true
auto-gateway: true
auto-route-table-id: 0
auto-routes: true
autoconf: true
dhcp: true
enabled: true
lldp:
enabled: false
mac-address: E4:43:4B:5C:96:80
mtu: 1500
name: eno1
state: up
type: ethernet
wait-ip: any
- accept-all-mac-addresses: false
ethernet:
auto-negotiation: false
duplex: full
speed: 10000
sr-iov:
total-vfs: 0
vfs: []
ethtool:
coalesce:
adaptive-rx: true
adaptive-tx: true
rx-usecs: 50
rx-usecs-high: 0
tx-frames-irq: 256
tx-usecs: 50
tx-usecs-high: 0
feature:
highdma: true
hw-tc-offload: false
l2-fwd-offload: false
rx-checksum: true
rx-gro: true
rx-gro-list: false
rx-hashing: true
rx-ntuple-filter: true
rx-udp-gro-forwarding: false
rx-udp_tunnel-port-offload: true
rx-vlan-hw-parse: true
tx-checksum-ip-generic: true
tx-checksum-sctp: true
tx-generic-segmentation: true
tx-gre-csum-segmentation: true
tx-gre-segmentation: true
tx-gso-partial: true
tx-ipxip4-segmentation: true
tx-ipxip6-segmentation: true
tx-nocache-copy: false
tx-tcp-ecn-segmentation: true
tx-tcp-mangleid-segmentation: false
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
tx-udp_tnl-csum-segmentation: true
tx-udp_tnl-segmentation: true
tx-vlan-hw-insert: true
pause:
autoneg: false
rx: false
tx: false
ring:
rx: 512
rx-max: 4096
tx: 512
tx-max: 4096
ipv4:
enabled: false
ipv6:
enabled: false
mac-address: E4:43:4B:5C:96:81
mtu: 1500
name: eno2
state: down
type: ethernet
- accept-all-mac-addresses: false
ethernet:
auto-negotiation: false
duplex: full
speed: 10000
sr-iov:
total-vfs: 0
vfs: []
ethtool:
coalesce:
adaptive-rx: true
adaptive-tx: true
rx-usecs: 50
rx-usecs-high: 0
tx-frames-irq: 256
tx-usecs: 50
tx-usecs-high: 0
feature:
highdma: true
hw-tc-offload: false
l2-fwd-offload: false
rx-checksum: true
rx-gro: true
rx-gro-list: false
rx-hashing: true
rx-ntuple-filter: true
rx-udp-gro-forwarding: false
rx-udp_tunnel-port-offload: true
rx-vlan-hw-parse: true
tx-checksum-ip-generic: true
tx-checksum-sctp: true
tx-generic-segmentation: true
tx-gre-csum-segmentation: true
tx-gre-segmentation: true
tx-gso-partial: true
tx-ipxip4-segmentation: true
tx-ipxip6-segmentation: true
tx-nocache-copy: false
tx-tcp-ecn-segmentation: true
tx-tcp-mangleid-segmentation: false
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
tx-udp_tnl-csum-segmentation: true
tx-udp_tnl-segmentation: true
tx-vlan-hw-insert: true
pause:
autoneg: false
rx: false
tx: false
ring:
rx: 512
rx-max: 4096
tx: 512
tx-max: 4096
ipv4:
enabled: false
ipv6:
enabled: false
mac-address: E4:43:4B:5C:96:82
mtu: 1500
name: em1
state: down
type: ethernet
- accept-all-mac-addresses: false
ethernet:
auto-negotiation: false
duplex: full
speed: 10000
sr-iov:
total-vfs: 0
vfs: []
ethtool:
coalesce:
adaptive-rx: true
adaptive-tx: true
rx-usecs: 50
rx-usecs-high: 0
tx-frames-irq: 256
tx-usecs: 50
tx-usecs-high: 0
feature:
highdma: true
hw-tc-offload: false
l2-fwd-offload: false
rx-checksum: true
rx-gro: true
rx-gro-list: false
rx-hashing: true
rx-ntuple-filter: true
rx-udp-gro-forwarding: false
rx-udp_tunnel-port-offload: true
rx-vlan-hw-parse: true
tx-checksum-ip-generic: true
tx-checksum-sctp: true
tx-generic-segmentation: true
tx-gre-csum-segmentation: true
tx-gre-segmentation: true
tx-gso-partial: true
tx-ipxip4-segmentation: true
tx-ipxip6-segmentation: true
tx-nocache-copy: false
tx-tcp-ecn-segmentation: true
tx-tcp-mangleid-segmentation: false
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
tx-udp_tnl-csum-segmentation: true
tx-udp_tnl-segmentation: true
tx-vlan-hw-insert: true
pause:
autoneg: false
rx: false
tx: false
ring:
rx: 512
rx-max: 4096
tx: 512
tx-max: 4096
ipv4:
enabled: false
ipv6:
enabled: false
mac-address: E4:43:4B:5C:96:83
mtu: 1500
name: em2
state: down
type: ethernet
- accept-all-mac-addresses: false
ethernet:
auto-negotiation: true
duplex: full
speed: 40000
sr-iov:
total-vfs: 0
vfs: []
ethtool:
coalesce:
adaptive-rx: true
adaptive-tx: true
rx-frames: 128
rx-usecs: 8
tx-frames: 128
tx-usecs: 8
feature:
hw-tc-offload: true
rx-all: false
rx-checksum: true
rx-fcs: false
rx-gro: true
rx-gro-list: false
rx-hashing: true
rx-lro: false
rx-ntuple-filter: false
rx-udp-gro-forwarding: false
rx-udp_tunnel-port-offload: true
rx-vlan-filter: true
rx-vlan-hw-parse: true
tx-checksum-ip-generic: true
tx-generic-segmentation: true
tx-gre-segmentation: true
tx-gso-partial: true
tx-ipxip4-segmentation: true
tx-ipxip6-segmentation: true
tx-nocache-copy: false
tx-tcp-mangleid-segmentation: false
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
tx-udp_tnl-segmentation: true
tx-vlan-hw-insert: true
tx-vlan-stag-hw-insert: true
pause:
autoneg: false
rx: true
tx: true
ring:
rx: 1024
rx-max: 8192
tx: 1024
tx-max: 8192
ipv4:
enabled: false
ipv6:
enabled: false
mac-address: 98:03:9B:7F:9E:48
mtu: 1500
name: enp59s0f0np0
state: down
type: ethernet
- accept-all-mac-addresses: false
ethernet:
auto-negotiation: true
duplex: full
speed: 40000
sr-iov:
total-vfs: 0
vfs: []
ethtool:
coalesce:
adaptive-rx: true
adaptive-tx: true
rx-frames: 128
rx-usecs: 8
tx-frames: 128
tx-usecs: 8
feature:
hw-tc-offload: true
rx-all: false
rx-checksum: true
rx-fcs: false
rx-gro: true
rx-gro-list: false
rx-hashing: true
rx-lro: false
rx-ntuple-filter: false
rx-udp-gro-forwarding: false
rx-udp_tunnel-port-offload: true
rx-vlan-filter: true
rx-vlan-hw-parse: true
tx-checksum-ip-generic: true
tx-generic-segmentation: true
tx-gre-segmentation: true
tx-gso-partial: true
tx-ipxip4-segmentation: true
tx-ipxip6-segmentation: true
tx-nocache-copy: false
tx-tcp-mangleid-segmentation: false
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
tx-udp_tnl-segmentation: true
tx-vlan-hw-insert: true
tx-vlan-stag-hw-insert: true
pause:
autoneg: false
rx: true
tx: true
ring:
rx: 1024
rx-max: 8192
tx: 1024
tx-max: 8192
ipv4:
enabled: false
ipv6:
enabled: false
mac-address: 98:03:9B:7F:9E:49
mtu: 1500
name: enp59s0f1np1
state: down
type: ethernet
- accept-all-mac-addresses: false
ethtool:
feature:
rx-gro: true
rx-gro-list: false
rx-udp-gro-forwarding: false
tx-generic-segmentation: true
tx-gso-list: true
tx-sctp-segmentation: true
tx-tcp-ecn-segmentation: true
tx-tcp-mangleid-segmentation: true
tx-tcp-segmentation: true
tx-tcp6-segmentation: true
tx-udp-segmentation: true
ipv4:
address:
- ip: 127.0.0.1
prefix-length: 8
enabled: true
ipv6:
address:
- ip: ::1
prefix-length: 128
enabled: true
mac-address: 00:00:00:00:00:00
mtu: 65536
name: lo
state: up
type: loopback
route-rules:
config: []
routes:
config: []

View File

@ -1,451 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, 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.
from io import StringIO
import os.path
import random
import re
import sys
import yaml
import os_net_config
from os_net_config import cli
from os_net_config import common
from os_net_config.tests import base
REALPATH = os.path.dirname(os.path.realpath(__file__))
SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc',
'os-net-config', 'samples')
class TestCli(base.TestCase):
def setUp(self):
super(TestCli, self).setUp()
rand = str(int(random.random() * 100000))
common.SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml'
common._LOG_FILE = '/tmp/' + rand + 'os_net_config.log'
sys.stdout = StringIO()
sys.stderr = StringIO()
def stub_is_ovs_installed():
return True
self.stub_out('os_net_config.utils.is_ovs_installed',
stub_is_ovs_installed)
def tearDown(self):
super(TestCli, self).tearDown()
if os.path.isfile(common._LOG_FILE):
os.remove(common._LOG_FILE)
if os.path.isfile(common.SRIOV_CONFIG_FILE):
os.remove(common.SRIOV_CONFIG_FILE)
def run_cli(self, argstr, exitcodes=(0,)):
for s in [sys.stdout, sys.stderr]:
s.flush()
s.truncate(0)
s.seek(0)
ret = cli.main(argstr.split())
self.assertIn(ret, exitcodes)
sys.stdout.flush()
sys.stderr.flush()
stdout = sys.stdout.getvalue()
stderr = sys.stderr.getvalue()
return (stdout, stderr)
def stub_get_stored_pci_address(self, ifname, noop):
if 'eth0' in ifname:
return "0000:00:07.0"
if 'eth1' in ifname:
return "0000:00:08.0"
if 'eth2' in ifname:
return "0000:00:09.0"
if 'em3' in ifname:
return "0000:00:03.0"
if 'em1' in ifname:
return "0000:00:01.0"
def test_bond_noop_output(self):
bond_yaml = os.path.join(SAMPLE_BASE, 'bond.yaml')
bond_json = os.path.join(SAMPLE_BASE, 'bond.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % bond_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % bond_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=br-ctlplane',
'DEVICE=em2',
'DEVICE=em1',
'DEVICE=bond1',
'DEVICETYPE=ovs']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_ivs_noop_output(self):
ivs_yaml = os.path.join(SAMPLE_BASE, 'ivs.yaml')
ivs_json = os.path.join(SAMPLE_BASE, 'ivs.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=nic2',
'DEVICE=nic3',
'DEVICE=api201',
'DEVICE=storage202',
'DEVICETYPE=ivs']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_bridge_noop_output(self):
bridge_yaml = os.path.join(SAMPLE_BASE, 'bridge_dhcp.yaml')
bridge_json = os.path.join(SAMPLE_BASE, 'bridge_dhcp.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=eni --noop '
'--exit-on-validation-errors '
'-c %s' % bridge_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=eni --noop '
'--exit-on-validation-errors '
'-c %s' % bridge_json)
self.assertEqual('', stderr)
sanity_devices = ['iface br-ctlplane inet dhcp',
'iface em1',
'ovs_type OVSBridge']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_vlan_noop_output(self):
vlan_yaml = os.path.join(SAMPLE_BASE, 'bridge_vlan.yaml')
vlan_json = os.path.join(SAMPLE_BASE, 'bridge_vlan.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % vlan_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % vlan_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=br-ctlplane',
'DEVICE=em1',
'DEVICE=vlan16',
'DEVICETYPE=ovs']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_interface_noop_output(self):
interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml')
interface_json = os.path.join(SAMPLE_BASE, 'interface.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % interface_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % interface_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=em1',
'BOOTPROTO=static',
'IPADDR=192.0.2.1']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_bridge_noop_rootfs(self):
for provider in ('ifcfg', 'eni'):
bond_yaml = os.path.join(SAMPLE_BASE, 'bridge_dhcp.yaml')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=%s --noop '
'--exit-on-validation-errors '
'--root-dir=/rootfs '
'-c %s' % (provider, bond_yaml))
self.assertEqual('', stderr)
self.assertIn('File: /rootfs/', stdout_yaml)
def test_interface_noop_detailed_exit_codes(self):
interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s --detailed-exit-codes'
% interface_yaml, exitcodes=(2,))
def test_interface_noop_detailed_exit_codes_no_changes(self):
interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml')
class TestImpl(os_net_config.NetConfig):
def add_interface(self, interface):
pass
def apply(self, cleanup=False, activate=True):
# this fake implementation returns no changes
return {}
self.stub_out('os_net_config.impl_ifcfg.IfcfgNetConfig', TestImpl)
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s --detailed-exit-codes'
% interface_yaml, exitcodes=(0,))
def test_sriov_noop_output(self):
def test_get_vf_devname(device, vfid):
return device + '_' + str(vfid)
def test_get_pci_address(ifname, noop):
return '0000:79:10.2'
def test_interface_mac(name):
return 'AA:BB:CC:DD:EE:FF'
self.stub_out('os_net_config.utils.get_vf_devname',
test_get_vf_devname)
self.stub_out('os_net_config.utils.get_pci_address',
test_get_pci_address)
self.stub_out('os_net_config.common.interface_mac',
test_interface_mac)
ivs_yaml = os.path.join(SAMPLE_BASE, 'sriov_pf.yaml')
ivs_json = os.path.join(SAMPLE_BASE, 'sriov_pf.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_yaml)
self.assertEqual('', stderr)
contents = common.get_file_data(common.SRIOV_CONFIG_FILE)
sriov_config_yaml = yaml.safe_load(contents)
os.remove(common.SRIOV_CONFIG_FILE)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_json)
self.assertEqual('', stderr)
contents = common.get_file_data(common.SRIOV_CONFIG_FILE)
sriov_config_json = yaml.safe_load(contents)
sanity_devices = ['DEVICE=p2p1',
'DEVICE=p2p1_5',
'DEVICE=p2p1_1',
'DEVICE=br-vfs',
'DEVICE=br-bond',
'TYPE=OVSBridge']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
self.assertCountEqual(sriov_config_yaml, sriov_config_json)
def test_sriov_vf_with_dpdk_noop_output(self):
def test_get_vf_devname(device, vfid):
return device + '_' + str(vfid)
def test_get_pci_address(ifname, noop):
return '0000:79:10.2'
self.stub_out('os_net_config.utils.get_vf_devname',
test_get_vf_devname)
self.stub_out('os_net_config.utils.get_pci_address',
test_get_pci_address)
ivs_yaml = os.path.join(SAMPLE_BASE, 'sriov_pf_ovs_dpdk.yaml')
ivs_json = os.path.join(SAMPLE_BASE, 'sriov_pf_ovs_dpdk.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_yaml)
self.assertEqual('', stderr)
contents = common.get_file_data(common.SRIOV_CONFIG_FILE)
sriov_config_yaml = yaml.safe_load(contents)
os.remove(common.SRIOV_CONFIG_FILE)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_json)
self.assertEqual('', stderr)
contents = common.get_file_data(common.SRIOV_CONFIG_FILE)
sriov_config_json = yaml.safe_load(contents)
sanity_devices = ['DEVICE=p2p1',
'DEVICE=p2p1_5',
'DEVICE=br-vfs',
'TYPE=OVSUserBridge',
'DEVICE=dpdk0',
'TYPE=OVSDPDKPort']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
self.assertCountEqual(sriov_config_yaml, sriov_config_json)
def test_ovs_dpdk_bond_noop_output(self):
ivs_yaml = os.path.join(SAMPLE_BASE, 'ovs_dpdk_bond.yaml')
ivs_json = os.path.join(SAMPLE_BASE, 'ovs_dpdk_bond.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=br-link',
'TYPE=OVSUserBridge',
'DEVICE=dpdkbond0',
'TYPE=OVSDPDKBond']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_nfvswitch_noop_output(self):
nfvswitch_yaml = os.path.join(SAMPLE_BASE, 'nfvswitch.yaml')
nfvswitch_json = os.path.join(SAMPLE_BASE, 'nfvswitch.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % nfvswitch_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % nfvswitch_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=nic2',
'DEVICE=nic3',
'DEVICE=api201',
'DEVICE=storage202',
'DEVICETYPE=nfvswitch']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_ovs_dpdk_noop_output(self):
ivs_yaml = os.path.join(SAMPLE_BASE, 'ovs_dpdk.yaml')
ivs_json = os.path.join(SAMPLE_BASE, 'ovs_dpdk.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % ivs_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=br-link',
'TYPE=OVSUserBridge',
'DEVICE=dpdk0',
'TYPE=OVSDPDKPort']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_nic_mapping_report_output(self):
mapping_report = os.path.join(SAMPLE_BASE, 'mapping_report.yaml')
def dummy_mapped_nics(nic_mapping=None):
return nic_mapping
self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics)
stdout, stderr = self.run_cli('ARG0 --interfaces '
'--exit-on-validation-errors '
'-m %s' % mapping_report)
self.assertEqual('', stderr)
stdout_list = yaml.safe_load(stdout)
self.assertEqual(stdout_list['nic1'], 'em1')
self.assertEqual(stdout_list['nic2'], 'em2')
self.assertEqual(stdout_list['nic3'], 'em4')
self.assertEqual(stdout_list['nic4'], 'em3')
def test_nic_mapping_report_with_explicit_interface_name(self):
mapping_report = os.path.join(SAMPLE_BASE, 'mapping_report.yaml')
def dummy_mapped_nics(nic_mapping=None):
return nic_mapping
self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics)
stdout, stderr = self.run_cli('ARG0 --interfaces em2 em3 '
'--exit-on-validation-errors '
'-m %s' % mapping_report)
self.assertEqual('', stderr)
stdout_list = yaml.safe_load(stdout)
self.assertNotIn('em1', stdout_list.keys())
self.assertNotIn('em1', stdout_list.values())
self.assertEqual(stdout_list['em2'], 'em2')
self.assertEqual(stdout_list['em3'], 'em3')
self.assertNotIn('em4', stdout_list.keys())
self.assertNotIn('em4', stdout_list.values())
def test_contrail_vrouter_noop_output(self):
cvi_yaml = os.path.join(SAMPLE_BASE, 'contrail_vrouter.yaml')
cvi_json = os.path.join(SAMPLE_BASE, 'contrail_vrouter.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % cvi_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % cvi_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=vhost0',
'BIND_INT=em3',
'DEVICETYPE=vhost',
'TYPE=kernel_mode']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_contrail_vrouter_vlan_noop_output(self):
cvi_yaml = os.path.join(SAMPLE_BASE, 'contrail_vrouter_vlan.yaml')
cvi_json = os.path.join(SAMPLE_BASE, 'contrail_vrouter_vlan.json')
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % cvi_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'-c %s' % cvi_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=vhost0',
'BIND_INT=vlan100',
'DEVICETYPE=vhost',
'TYPE=kernel_mode']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
self.assertEqual(stdout_yaml, stdout_json)
def test_contrail_vrouter_dpdk_noop_output(self):
timestamp_rex = re.compile(
(r'contrail_vrouter_dpdk\.(yaml|json)|^[\d]{4}-[\d]{2}-[\d]{2} '
r'[\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3} '),
flags=re.M
)
cvi_yaml = os.path.join(SAMPLE_BASE, 'contrail_vrouter_dpdk.yaml')
cvi_json = os.path.join(SAMPLE_BASE, 'contrail_vrouter_dpdk.json')
self.stub_out('os_net_config.utils.get_stored_pci_address',
self.stub_get_stored_pci_address)
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'--debug '
'-c %s' % cvi_yaml)
self.assertEqual('', stderr)
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
'--exit-on-validation-errors '
'--debug '
'-c %s' % cvi_json)
self.assertEqual('', stderr)
sanity_devices = ['DEVICE=vhost0',
'BIND_INT=0000:00:03.0',
'DEVICETYPE=vhost',
'TYPE=dpdk']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
stdout_yaml = timestamp_rex.sub('', stdout_yaml)
stdout_json = timestamp_rex.sub('', stdout_json)
self.assertEqual(stdout_yaml, stdout_json)

View File

@ -1,407 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, 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 tempfile
from oslo_concurrency import processutils
import os_net_config
from os_net_config import common
from os_net_config import impl_eni
from os_net_config import objects
from os_net_config.tests import base
_AUTO = "auto eth0\n"
_v4_IFACE_NO_IP = _AUTO + "iface eth0 inet manual\n"
_V4_IFACE_STATIC_IP = _AUTO + """iface eth0 inet static
address 192.168.1.2
netmask 255.255.255.0
"""
_IFACE_HOTPLUG = """allow-hotplug eth0
iface eth0 inet static
address 192.168.1.2
netmask 255.255.255.0
"""
_V4_IFACE_STATIC_IP_MULTIPLE = (_V4_IFACE_STATIC_IP + _AUTO +
"""iface eth0 inet static
address 10.0.0.2
netmask 255.0.0.0
""")
_V6_IFACE_STATIC_IP = _AUTO + """iface eth0 inet6 static
address fe80::2677:3ff:fe7d:4c
netmask 128
"""
_V6_IFACE_STATIC_IP_MULTIPLE = (_V6_IFACE_STATIC_IP + _AUTO +
"""iface eth0 inet6 static
address 2001:abcd::2
netmask 64
""")
_IFACE_DHCP = _AUTO + "iface eth0 inet dhcp\n"
_OVS_PORT_BASE = _AUTO + "allow-br0 eth0\n"
_OVS_PORT_IFACE = _OVS_PORT_BASE + """iface eth0 inet manual
ovs_bridge br0
ovs_type OVSPort
"""
_OVS_BRIDGE_DHCP = """auto br0
allow-ovs br0
iface br0 inet dhcp
ovs_type OVSBridge
ovs_ports eth0
pre-up ip addr flush dev eth0
"""
_OVS_BRIDGE_DHCP_STANDALONE = _OVS_BRIDGE_DHCP + (
" ovs_extra set bridge br0 fail_mode=standalone "
"-- del-controller br0\n")
_OVS_BRIDGE_DHCP_SECURE = _OVS_BRIDGE_DHCP + \
" ovs_extra set bridge br0 fail_mode=secure\n"
_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE = _OVS_BRIDGE_DHCP + \
" ovs_extra set bridge br0 other-config:hwaddr=a1:b2:c3:d4:e5\n"
_OVS_BRIDGE_DHCP_OVS_EXTRA = _OVS_BRIDGE_DHCP + \
" ovs_extra set bridge br0 other-config:hwaddr=a1:b2:c3:d4:e5" + \
" -- br-set-external-id br0 bridge-id br0\n"
_VLAN_NO_IP = """auto vlan5
iface vlan5 inet manual
vlan-raw-device eth0
"""
_VLAN_OVS_PORT = """auto vlan5
allow-br0 vlan5
iface vlan5 inet manual
ovs_bridge br0
ovs_type OVSIntPort
ovs_options tag=5
"""
_RTS = """up route add -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1
down route del -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1
up route add -net 172.20.0.0 netmask 255.255.255.0 gw 192.168.1.5 metric 100
down route del -net 172.20.0.0 netmask 255.255.255.0 gw 192.168.1.5 metric 100
"""
class TestENINetConfig(base.TestCase):
def setUp(self):
super(TestENINetConfig, self).setUp()
def stub_is_ovs_installed():
return True
self.stub_out('os_net_config.utils.is_ovs_installed',
stub_is_ovs_installed)
self.provider = impl_eni.ENINetConfig()
self.if_name = 'eth0'
def tearDown(self):
super(TestENINetConfig, self).tearDown()
def get_interface_config(self, name="eth0"):
return self.provider.interfaces[name]
def get_route_config(self):
return self.provider.routes[self.if_name]
def _default_interface(self, addr=[], rts=[], hotplug=False):
return objects.Interface(self.if_name, addresses=addr, routes=rts,
hotplug=hotplug)
def test_interface_no_ip(self):
interface = self._default_interface()
self.provider.add_interface(interface)
self.assertEqual(_v4_IFACE_NO_IP, self.get_interface_config())
def test_add_interface_with_v4(self):
v4_addr = objects.Address('192.168.1.2/24')
interface = self._default_interface([v4_addr])
self.provider.add_interface(interface)
self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config())
def test_add_interface_with_hotplug(self):
v4_addr = objects.Address('192.168.1.2/24')
interface = self._default_interface(addr=[v4_addr], hotplug=True)
self.provider.add_interface(interface)
self.assertEqual(_IFACE_HOTPLUG, self.get_interface_config())
def test_add_interface_with_v4_multiple(self):
v4_addresses = [objects.Address('192.168.1.2/24'),
objects.Address('10.0.0.2/8')]
interface = self._default_interface(v4_addresses)
self.provider.add_interface(interface)
self.assertEqual(_V4_IFACE_STATIC_IP_MULTIPLE,
self.get_interface_config())
def test_add_interface_with_v6(self):
v6_addr = objects.Address('fe80::2677:3ff:fe7d:4c')
interface = self._default_interface([v6_addr])
self.provider.add_interface(interface)
self.assertEqual(_V6_IFACE_STATIC_IP, self.get_interface_config())
def test_add_interface_with_v6_multiple(self):
v6_addresses = [objects.Address('fe80::2677:3ff:fe7d:4c'),
objects.Address('2001:abcd::2/64')]
interface = self._default_interface(v6_addresses)
self.provider.add_interface(interface)
self.assertEqual(_V6_IFACE_STATIC_IP_MULTIPLE,
self.get_interface_config())
def test_add_interface_dhcp(self):
interface = self._default_interface()
interface.use_dhcp = True
self.provider.add_interface(interface)
self.assertEqual(_IFACE_DHCP, self.get_interface_config())
def test_add_interface_with_both_v4_and_v6(self):
v4_addr = objects.Address('192.168.1.2/24')
v6_addr = objects.Address('fe80::2677:3ff:fe7d:4c')
interface = self._default_interface([v4_addr, v6_addr])
self.provider.add_interface(interface)
self.assertEqual(_V4_IFACE_STATIC_IP + _V6_IFACE_STATIC_IP,
self.get_interface_config())
def test_add_ovs_port_interface(self):
interface = self._default_interface()
interface.ovs_port = True
interface.bridge_name = 'br0'
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
def test_network_with_routes(self):
route1 = objects.Route('192.168.1.1', '172.19.0.0/24')
route2 = objects.Route('192.168.1.5', '172.20.0.0/24',
route_options="metric 100")
v4_addr = objects.Address('192.168.1.2/24')
interface = self._default_interface([v4_addr], [route1, route2])
self.provider.add_interface(interface)
self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config())
self.assertEqual(_RTS, self.get_route_config())
def test_network_ovs_bridge_with_dhcp(self):
interface = self._default_interface()
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface])
self.provider.add_bridge(bridge)
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
self.assertEqual(_OVS_BRIDGE_DHCP, self.provider.bridges['br0'])
def test_network_ovs_bridge_with_standalone_fail_mode(self):
interface = self._default_interface()
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface],
fail_mode='standalone')
self.provider.add_bridge(bridge)
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
self.assertEqual(_OVS_BRIDGE_DHCP_STANDALONE,
self.provider.bridges['br0'])
def test_network_ovs_bridge_with_secure_fail_mode(self):
interface = self._default_interface()
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface],
fail_mode='secure')
self.provider.add_bridge(bridge)
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
self.assertEqual(_OVS_BRIDGE_DHCP_SECURE,
self.provider.bridges['br0'])
def test_network_ovs_bridge_with_dhcp_and_primary_interface(self):
def test_interface_mac(name):
return "a1:b2:c3:d4:e5"
self.stub_out('os_net_config.common.interface_mac', test_interface_mac)
interface = objects.Interface(self.if_name, primary=True)
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface])
self.provider.add_bridge(bridge)
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
self.assertEqual(_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE,
self.provider.bridges['br0'])
def test_network_ovs_bridge_with_dhcp_and_primary_with_ovs_extra(self):
def test_interface_mac(name):
return "a1:b2:c3:d4:e5"
self.stub_out('os_net_config.common.interface_mac', test_interface_mac)
interface = objects.Interface(self.if_name, primary=True)
ovs_extra = "br-set-external-id br0 bridge-id br0"
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface],
ovs_extra=[ovs_extra])
self.provider.add_bridge(bridge)
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA,
self.provider.bridges['br0'])
def test_network_ovs_bridge_with_dhcp_and_primary_with_ovs_format(self):
def test_interface_mac(name):
return "a1:b2:c3:d4:e5"
self.stub_out('os_net_config.common.interface_mac', test_interface_mac)
interface = objects.Interface(self.if_name, primary=True)
ovs_extra = "br-set-external-id {name} bridge-id {name}"
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface],
ovs_extra=[ovs_extra])
self.provider.add_bridge(bridge)
self.provider.add_interface(interface)
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA,
self.provider.bridges['br0'])
def test_vlan(self):
vlan = objects.Vlan('eth0', 5)
self.provider.add_vlan(vlan)
self.assertEqual(_VLAN_NO_IP, self.get_interface_config('vlan5'))
def test_vlan_mtu_1500(self):
vlan = objects.Vlan('eth0', 5, mtu=1500)
self.provider.add_vlan(vlan)
expected = _VLAN_NO_IP + ' mtu 1500\n'
self.assertEqual(expected, self.get_interface_config('vlan5'))
def test_vlan_ovs_bridge_int_port(self):
vlan = objects.Vlan('eth0', 5)
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[vlan])
self.provider.add_bridge(bridge)
self.provider.add_vlan(vlan)
self.assertEqual(_VLAN_OVS_PORT, self.get_interface_config('vlan5'))
class TestENINetConfigApply(base.TestCase):
def setUp(self):
super(TestENINetConfigApply, self).setUp()
self.temp_config_file = tempfile.NamedTemporaryFile()
self.ifup_interface_names = []
def test_config_path(prefix):
return self.temp_config_file.name
self.stub_out(
'os_net_config.impl_eni._network_config_path', test_config_path)
def stub_is_ovs_installed():
return True
self.stub_out('os_net_config.utils.is_ovs_installed',
stub_is_ovs_installed)
def test_execute(*args, **kwargs):
if args[0] == '/sbin/ifup':
self.ifup_interface_names.append(args[1])
pass
self.stub_out('oslo_concurrency.processutils.execute', test_execute)
self.provider = impl_eni.ENINetConfig()
def tearDown(self):
self.temp_config_file.close()
super(TestENINetConfigApply, self).tearDown()
def test_network_apply(self):
route1 = objects.Route('192.168.1.1', '172.19.0.0/24')
route2 = objects.Route('192.168.1.5', '172.20.0.0/24',
route_options="metric 100")
v4_addr = objects.Address('192.168.1.2/24')
interface = objects.Interface('eth0', addresses=[v4_addr],
routes=[route1, route2])
self.provider.add_interface(interface)
self.provider.apply()
iface_data = common.get_file_data(self.temp_config_file.name)
self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data)
self.assertIn('eth0', self.ifup_interface_names)
def test_apply_noactivate(self):
route1 = objects.Route('192.168.1.1', '172.19.0.0/24')
route2 = objects.Route('192.168.1.5', '172.20.0.0/24',
route_options="metric 100")
v4_addr = objects.Address('192.168.1.2/24')
interface = objects.Interface('eth0', addresses=[v4_addr],
routes=[route1, route2])
self.provider.add_interface(interface)
self.provider.apply(activate=False)
iface_data = common.get_file_data(self.temp_config_file.name)
self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data)
self.assertEqual([], self.ifup_interface_names)
def test_dhcp_ovs_bridge_network_apply(self):
interface = objects.Interface('eth0')
bridge = objects.OvsBridge('br0', use_dhcp=True,
members=[interface])
self.provider.add_interface(interface)
self.provider.add_bridge(bridge)
self.provider.apply()
iface_data = common.get_file_data(self.temp_config_file.name)
self.assertEqual((_OVS_BRIDGE_DHCP + _OVS_PORT_IFACE), iface_data)
self.assertIn('eth0', self.ifup_interface_names)
self.assertIn('br0', self.ifup_interface_names)
def _failed_execute(*args, **kwargs):
if kwargs.get('check_exit_code', True):
raise processutils.ProcessExecutionError('Test stderr',
'Test stdout',
str(kwargs))
def test_interface_failure(self):
self.stub_out('oslo_concurrency.processutils.execute',
self._failed_execute)
v4_addr = objects.Address('192.168.1.2/24')
interface = objects.Interface('em1', addresses=[v4_addr])
self.provider.add_interface(interface)
self.assertRaises(os_net_config.ConfigurationError,
self.provider.apply)
self.assertEqual(1, len(self.provider.errors))
def test_interface_failure_multiple(self):
self.stub_out('oslo_concurrency.processutils.execute',
self._failed_execute)
v4_addr = objects.Address('192.168.1.2/24')
interface = objects.Interface('em1', addresses=[v4_addr])
v4_addr2 = objects.Address('192.168.2.2/24')
interface2 = objects.Interface('em2', addresses=[v4_addr2])
self.provider.add_interface(interface)
self.provider.add_interface(interface2)
self.assertRaises(os_net_config.ConfigurationError,
self.provider.apply)
# Even though the first one failed, we should have attempted both
self.assertEqual(2, len(self.provider.errors))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, 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.
"""
test_os_net_config
----------------------------------
Tests for `os_net_config` module.
"""
from os_net_config.tests import base
class TestOs_net_config(base.TestCase):
def test_something(self):
pass

View File

@ -1,53 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat, 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 os
import os.path
import random
from os_net_config import sriov_bind_config
from os_net_config.tests import base
from os_net_config import utils
class TestSriovBindConfig(base.TestCase):
"""Unit tests for methods defined in sriov_bind_config.py"""
def setUp(self):
super(TestSriovBindConfig, self).setUp()
rand = str(int(random.random() * 100000))
sriov_bind_config._SRIOV_BIND_CONFIG_FILE = '/tmp/' + rand +\
'sriov_bind_config.yaml'
sriov_bind_config._PCI_DRIVER_BIND_FILE_PATH = '/tmp/' + rand +\
'%(driver)s/bind'
def tearDown(self):
super(TestSriovBindConfig, self).tearDown()
if os.path.isfile(sriov_bind_config._SRIOV_BIND_CONFIG_FILE):
os.remove(sriov_bind_config._SRIOV_BIND_CONFIG_FILE)
def test_bind_vfs(self):
"""Test SR-IOV VFs binding"""
vfs_driver = "mlx5_core"
sriov_bind_pcis_map = {vfs_driver: ['0000:03:00.2', '0000:03:00.3']}
os.makedirs(sriov_bind_config._PCI_DRIVER_BIND_FILE_PATH %
{"driver": vfs_driver})
utils.write_yaml_config(sriov_bind_config._SRIOV_BIND_CONFIG_FILE,
sriov_bind_pcis_map)
sriov_bind_config.bind_vfs()

View File

@ -1,628 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat, 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 os
import os.path
import random
import shutil
import tempfile
from os_net_config import common
from os_net_config import sriov_config
from os_net_config.tests import base
from os_net_config import utils
class TestSriovConfig(base.TestCase):
"""Unit tests for methods defined in sriov_config.py"""
def setUp(self):
super(TestSriovConfig, self).setUp()
rand = str(int(random.random() * 100000))
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
common._LOG_FILE = '/tmp/' + rand + 'os_net_config.log'
sriov_config._UDEV_RULE_FILE = '/tmp/' + rand + 'etc_udev_rules.d'\
'80-persistent-os-net-config.rules'
sriov_config._UDEV_LEGACY_RULE_FILE = '/tmp/' + rand + 'etc_udev_'\
'rules.d_70-os-net-config-sriov.rules'
sriov_config._IFUP_LOCAL_FILE = '/tmp/' + rand + 'sbin_ifup-local'
sriov_config._RESET_SRIOV_RULES_FILE = '/tmp/' + rand + 'etc_udev_'\
'rules.d_70-tripleo-reset-sriov.rules'
sriov_config._ALLOCATE_VFS_FILE = '/tmp/' + rand + 'etc_sysconfig_'\
'allocate_vfs'
common.SRIOV_CONFIG_FILE = '/tmp/' + rand + 'sriov_config.yaml'
sriov_config._REP_LINK_NAME_FILE = '/tmp/' + rand + 'rep_link.sh'
def tearDown(self):
super(TestSriovConfig, self).tearDown()
if os.path.isfile(common._LOG_FILE):
os.remove(common._LOG_FILE)
if os.path.isfile(common.SRIOV_CONFIG_FILE):
os.remove(common.SRIOV_CONFIG_FILE)
if os.path.isfile(sriov_config._IFUP_LOCAL_FILE):
os.remove(sriov_config._IFUP_LOCAL_FILE)
shutil.rmtree(common.SYS_CLASS_NET)
if os.path.isfile(sriov_config._RESET_SRIOV_RULES_FILE):
os.remove(sriov_config._RESET_SRIOV_RULES_FILE)
if os.path.isfile(sriov_config._ALLOCATE_VFS_FILE):
os.remove(sriov_config._ALLOCATE_VFS_FILE)
if os.path.isfile(sriov_config._UDEV_LEGACY_RULE_FILE):
os.remove(sriov_config._UDEV_LEGACY_RULE_FILE)
def _write_numvfs(self, ifname, numvfs=0):
os.makedirs(common.get_dev_path(ifname, '_device'))
numvfs_file = common.get_dev_path(ifname, 'sriov_numvfs')
with open(numvfs_file, 'w') as f:
f.write(str(numvfs))
def _save_action(self, action):
try:
self._action_order.append(action)
except AttributeError:
self._action_order = [action]
def setUp_udev_stubs(self):
def udev_monitor_setup_stub():
self._save_action('udev_monitor_setup')
return
self.stub_out('os_net_config.sriov_config.udev_monitor_setup',
udev_monitor_setup_stub)
def udev_monitor_start_stub(observer):
self._save_action('udev_monitor_start')
return
self.stub_out('os_net_config.sriov_config.udev_monitor_start',
udev_monitor_start_stub)
def udev_monitor_stop_stub(observer):
self._save_action('udev_monitor_stop')
return
self.stub_out('os_net_config.sriov_config.udev_monitor_stop',
udev_monitor_stop_stub)
def trigger_udev_rules_stub():
self._save_action('trigger_udev_rules')
return
self.stub_out('os_net_config.sriov_config.trigger_udev_rules',
trigger_udev_rules_stub)
def reload_udev_rules_stub():
self._save_action('reload_udev_rules')
return
self.stub_out('os_net_config.sriov_config.reload_udev_rules',
reload_udev_rules_stub)
def test_add_udev_rules(self):
"""Test Add udev rules
"""
def get_pf_pci_stub(name):
pci_address = {"p2p1": "0000:01:01.0",
"p2p2": "0000:01:02.0",
"p2p3": "0000:01:03.0"}
return pci_address[name]
self.stub_out('os_net_config.sriov_config.get_pf_pci',
get_pf_pci_stub)
self.setUp_udev_stubs()
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\
'KERNELS=="0000:01:01.0", NAME="p2p1"\n'
sriov_config.add_udev_rule_for_sriov_pf("p2p1")
f = open(sriov_config._UDEV_RULE_FILE, 'r')
self.assertEqual(exp_udev_content, f.read())
def test_append_udev_rules(self):
"""Test adding udev rules
"""
def get_pf_pci_stub(name):
pci_address = {"p2p1": "0000:01:01.0",
"p2p2": "0000:01:02.0",
"p2p3": "0000:01:03.0"}
return pci_address[name]
self.stub_out('os_net_config.sriov_config.get_pf_pci',
get_pf_pci_stub)
self.setUp_udev_stubs()
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\
'KERNELS=="0000:01:01.0", NAME="p2p1"\n' \
'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\
'KERNELS=="0000:01:02.0", NAME="p2p2"\n'
udev_content = '# This file is autogenerated by os-net-config\n'\
'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\
'KERNELS=="0000:01:01.0", NAME="p2p1"\n'
udev_file = open(sriov_config._UDEV_RULE_FILE, "w")
udev_file.write(udev_content)
udev_file.close()
sriov_config.add_udev_rule_for_sriov_pf("p2p2")
f = open(sriov_config._UDEV_RULE_FILE, 'r')
self.assertEqual(exp_udev_content, f.read())
def test_add_legacy_udev_rules(self):
"""Test Add udev rules for legacy sriov
"""
self.setUp_udev_stubs()
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'
sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p1", 8)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
self.assertEqual(exp_udev_content, f.read())
def test_modify_legacy_udev_rules(self):
"""Test modifying udev rules for legacy sriov
"""
self.setUp_udev_stubs()
udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:10"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n'
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n'
udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w")
udev_file.write(udev_content)
udev_file.close()
sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p1", 8)
f = open(udev_file.name, 'r')
self.assertEqual(exp_udev_content, f.read())
def test_same_legacy_udev_rules(self):
"""Test without changing udev rules for legacy sriov
"""
self.setUp_udev_stubs()
udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n'
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n'
udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w")
udev_file.write(udev_content)
udev_file.close()
sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p2", 10)
f = open(udev_file.name, 'r')
self.assertEqual(exp_udev_content, f.read())
def test_append_legacy_udev_rules(self):
"""Test appending udev rules for legacy sriov
"""
self.setUp_udev_stubs()
udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n'
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' \
'KERNEL=="p2p3", RUN+="/bin/os-net-config-sriov -n %k:12"\n'
udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w")
udev_file.write(udev_content)
udev_file.close()
sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p3", 12)
f = open(udev_file.name, 'r')
self.assertEqual(exp_udev_content, f.read())
def setUp_pf_stubs(self, vendor_id="0x8086"):
run_cmd = []
self.setUp_udev_stubs()
def run_ip_config_cmd_stub(*args, **kwargs):
run_cmd.append(' '.join(args))
self.stub_out('os_net_config.sriov_config.run_ip_config_cmd',
run_ip_config_cmd_stub)
def cleanup_puppet_config_stub():
return
self.stub_out('os_net_config.sriov_config.cleanup_puppet_config',
cleanup_puppet_config_stub)
def _wait_for_vf_creation_stub(pf_name, numvfs):
self._save_action('_wait_for_vf_creation')
return
self.stub_out('os_net_config.sriov_config._wait_for_vf_creation',
_wait_for_vf_creation_stub)
def get_vendor_id_stub(ifname):
return vendor_id
self.stub_out('os_net_config.common.get_vendor_id',
get_vendor_id_stub)
def configure_switchdev_stub(pf_name):
self._save_action('configure_switchdev')
return
self.stub_out('os_net_config.sriov_config.configure_switchdev',
configure_switchdev_stub)
self.set_numvfs = sriov_config.set_numvfs
self.get_numvfs = sriov_config.get_numvfs
def get_numvfs_stub(*args):
self._save_action('get_numvfs')
return self.get_numvfs(*args)
self.stub_out('os_net_config.sriov_config.get_numvfs',
get_numvfs_stub)
def set_numvfs_stub(*args):
self._save_action('set_numvfs')
return self.set_numvfs(*args)
self.stub_out('os_net_config.sriov_config.set_numvfs',
set_numvfs_stub)
def get_pf_pci_stub(name):
pci_address = {"p2p1": "0000:01:01.0",
"p2p2": "0000:01:02.0",
"p2p3": "0000:01:03.0"}
return pci_address[name]
self.stub_out('os_net_config.sriov_config.get_pf_pci',
get_pf_pci_stub)
def get_vdpa_vhost_devices_stub():
self._save_action('get_vdpa_vhost_devices')
return
self.stub_out('os_net_config.sriov_config.get_vdpa_vhost_devices',
get_vdpa_vhost_devices_stub)
def load_kmods_stub(mods):
return
self.stub_out('os_net_config.sriov_config.load_kmods',
load_kmods_stub)
def modprobe_stub(*args):
out = """vdpa x
vhost_vdpa x
"""
return out, "hello"
self.stub_out('oslo_concurrency.processutils.execute',
modprobe_stub)
def reload_udev_rules_stub():
self._save_action('reload_udev_rules')
return
self.stub_out('os_net_config.sriov_config.reload_udev_rules',
reload_udev_rules_stub)
def test_list_kmods(self):
self.setUp_pf_stubs()
self.assertEqual([], common.list_kmods(["vhost_vdpa", "vdpa"]))
self.assertEqual(["test"], common.list_kmods(["test", "vdpa"]))
def test_configure_sriov_pf(self):
"""Test the numvfs setting for SR-IOV PF
Test the udev rules created for legacy mode of SR-IOV PF
"""
self.setUp_pf_stubs()
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:10"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n'
exp_actions = [
'udev_monitor_setup',
'udev_monitor_start',
'get_numvfs',
'reload_udev_rules',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'get_numvfs',
'reload_udev_rules',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'udev_monitor_stop',
]
pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10,
"promisc": "on", "link_mode": "legacy"},
{"device_type": "pf", "name": "p2p2", "numvfs": 12,
"promisc": "off", "link_mode": "legacy"}]
for ifname in ['p2p1', 'p2p2']:
self._write_numvfs(ifname)
self._action_order = []
utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
self.assertEqual(exp_udev_content, f.read())
self.assertEqual(10, sriov_config.get_numvfs('p2p1'))
self.assertEqual(12, sriov_config.get_numvfs('p2p2'))
def test_configure_sriov_pf_nicpart(self):
"""Test the udev rules created for legacy mode of SR-IOV PF
In this case, the VF(s) are already bound/attached
"""
self.setUp_pf_stubs()
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n'
exp_actions = [
'udev_monitor_setup',
'udev_monitor_start',
'get_numvfs',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'get_numvfs',
'reload_udev_rules',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'udev_monitor_stop',
]
pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10,
"promisc": "on", "link_mode": "legacy"},
{"device_type": "pf", "name": "p2p2", "numvfs": 12,
"promisc": "off", "link_mode": "legacy"},
{"device": {"name": "p2p1", "vfid": 0},
"device_type": "vf", "name": "p2p1v0", "max_tx_rate": 0,
"min_tx_rate": 0, "pci_address": "0000:18:0a.0",
"trust": "on", "spoofcheck": "off"}]
for ifname in ['p2p1', 'p2p2']:
self._write_numvfs(ifname)
self._action_order = []
utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
self.assertEqual(exp_udev_content, f.read())
self.assertEqual(12, sriov_config.get_numvfs('p2p2'))
def test_configure_sriov_pf_non_nicpart(self):
"""Test the udev rules created for legacy mode of SR-IOV PF
In this case, the nic partitioned VF(s) are not attached
"""
self.setUp_pf_stubs()
exp_udev_content = '# This file is autogenerated by os-net-config\n'\
'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:10"\n'\
'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n'
exp_actions = [
'udev_monitor_setup',
'udev_monitor_start',
'get_numvfs',
'reload_udev_rules',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'get_numvfs',
'reload_udev_rules',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'udev_monitor_stop',
]
pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10,
"promisc": "on", "link_mode": "legacy"},
{"device_type": "pf", "name": "p2p2", "numvfs": 12,
"promisc": "off", "link_mode": "legacy"},
{"device": {"name": "eno3", "vfid": 1},
"device_type": "vf", "name": "eno3v0", "max_tx_rate": 0,
"min_tx_rate": 0, "pci_address": "0000:18:0e.1",
"trust": "on", "spoofcheck": "off"}]
for ifname in ['p2p1', 'p2p2']:
self._write_numvfs(ifname)
self._action_order = []
utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
self.assertEqual(exp_udev_content, f.read())
self.assertEqual(10, sriov_config.get_numvfs('p2p1'))
self.assertEqual(12, sriov_config.get_numvfs('p2p2'))
def test_configure_vdpa_pf(self):
"""Test the vdpa PF
"""
self.setUp_pf_stubs(common.MLNX_VENDOR_ID)
exp_actions = [
'udev_monitor_setup',
'udev_monitor_start',
'get_vdpa_vhost_devices',
'get_numvfs',
'configure_switchdev',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'reload_udev_rules',
'reload_udev_rules',
'reload_udev_rules',
'reload_udev_rules',
'get_numvfs',
'configure_switchdev',
'set_numvfs',
'get_numvfs',
'_wait_for_vf_creation',
'get_numvfs',
'reload_udev_rules',
'reload_udev_rules',
'reload_udev_rules',
'trigger_udev_rules',
'udev_monitor_stop',
]
pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10,
"vdpa": True, "link_mode": "switchdev"},
{"device_type": "pf", "name": "p2p2", "numvfs": 12,
"vdpa": True, "link_mode": "switchdev"}]
for ifname in ['p2p1', 'p2p2']:
self._write_numvfs(ifname)
self._action_order = []
utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
self.assertEqual(10, sriov_config.get_numvfs('p2p1'))
self.assertEqual(12, sriov_config.get_numvfs('p2p2'))
def test_cleanup_puppet_config_deprecation(self):
"""Test the cleanup of puppet-tripleo generated config file.
Usecase: The ifup-local has the default content generated by
puppet-tripleo
"""
content = '#!/bin/bash\n'\
'/etc/sysconfig/allocate_vfs $1'
f = open(sriov_config._RESET_SRIOV_RULES_FILE, "w+")
f.close()
f = open(sriov_config._ALLOCATE_VFS_FILE, "w+")
f.close()
f = open(sriov_config._IFUP_LOCAL_FILE, "w+")
f.write(content)
f.close()
sriov_config.cleanup_puppet_config()
self.assertEqual(False,
os.path.exists(sriov_config._RESET_SRIOV_RULES_FILE))
self.assertEqual(False,
os.path.exists(sriov_config._ALLOCATE_VFS_FILE))
self.assertEqual(False,
os.path.exists(sriov_config._IFUP_LOCAL_FILE))
def test_cleanup_puppet_config_new(self):
"""Test the cleanup of puppet-tripleo generated config file.
Usecase: When os-net-config is run on fresh deployments, all these
files will not exist.
"""
sriov_config.cleanup_puppet_config()
self.assertEqual(False,
os.path.exists(sriov_config._RESET_SRIOV_RULES_FILE))
self.assertEqual(False,
os.path.exists(sriov_config._ALLOCATE_VFS_FILE))
self.assertEqual(False,
os.path.exists(sriov_config._IFUP_LOCAL_FILE))
def test_cleanup_puppet_config_modified(self):
"""Test the cleanup of puppet-tripleo generated config file
Usecase: When os-net-config is run first time after the deprecation
of NeutronSriovNumVFs and ifup-local has contents other than invoking
allocate_vfs.
"""
content = '#!/bin/bash\n'\
'/etc/sysconfig/allocate_vfs $1\n'\
'/usr/sbin/ifup eth0'
mod_content = '#!/bin/bash\n'\
'/usr/sbin/ifup eth0'
f = open(sriov_config._IFUP_LOCAL_FILE, "w+")
f.write(content)
f.close()
sriov_config.cleanup_puppet_config()
self.assertEqual(False,
os.path.exists(sriov_config._RESET_SRIOV_RULES_FILE))
self.assertEqual(False,
os.path.exists(sriov_config._ALLOCATE_VFS_FILE))
self.assertEqual(True,
os.path.exists(sriov_config._IFUP_LOCAL_FILE))
f = open(sriov_config._IFUP_LOCAL_FILE, "r")
self.assertEqual(mod_content, f.read())
def test_numvfs_config(self):
"""Test the numvfs config with valid arguments"""
self._write_numvfs('p2p1')
self.assertEqual(None, sriov_config.main(['ARG0', '-n', 'p2p1:15']))
self.assertEqual(15, sriov_config.get_numvfs('p2p1'))
def test_numvfs_invalid_params(self):
"""Test the numvfs config with invalid arguments"""
self._write_numvfs('p2p1')
self.assertEqual(1, sriov_config.main(['ARG0', '-n', 'p2p1:15a']))
self.assertEqual(0, sriov_config.get_numvfs('p2p1'))
def test_numvfs_preconfigured(self):
"""Test the numvfs config while its already configured"""
self._write_numvfs('p2p1', 10)
self.assertEqual(None, sriov_config.main(['ARG0', '-n', 'p2p1:15']))
self.assertEqual(10, sriov_config.get_numvfs('p2p1'))
def test_configure_sriov_vf(self):
"""Test configuration of SR-IOV VF settings"""
vf_config = [{"device_type": "vf", "device": {"name": "p2p1",
"vfid": 1}, "promisc": "on", "vlan_id": 101,
"qos": 5, "macaddr": "AA:BB:CC:DD:EE:FF",
"spoofcheck": "on", "state": "auto", "trust": "on",
"min_tx_rate": 0, "max_tx_rate": 100,
"name": "p2p1_1"}]
exp_cmds = ["ip link set dev p2p1 vf 1 mac AA:BB:CC:DD:EE:FF",
"ip link set dev p2p1 vf 1 vlan 101 qos 5",
"ip link set dev p2p1 vf 1 min_tx_rate 0",
"ip link set dev p2p1 vf 1 max_tx_rate 100",
"ip link set dev p2p1_1 promisc on",
"ip link set dev p2p1 vf 1 spoofchk on",
"ip link set dev p2p1 vf 1 state auto",
"ip link set dev p2p1 vf 1 trust on"]
run_cmd = []
def run_ip_config_cmd_stub(*args, **kwargs):
run_cmd.append(' '.join(args))
self.stub_out('os_net_config.sriov_config.run_ip_config_cmd',
run_ip_config_cmd_stub)
utils.write_yaml_config(common.SRIOV_CONFIG_FILE, vf_config)
sriov_config.configure_sriov_vf()
for cmd in exp_cmds:
self.assertIn(cmd, run_cmd)

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More