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:
parent
27915c67c8
commit
6ed93f8448
@ -1,7 +0,0 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = os_net_config
|
||||
omit = os_net_config/tests/*
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
53
.gitignore
vendored
53
.gitignore
vendored
@ -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
|
3
.mailmap
3
.mailmap
@ -1,3 +0,0 @@
|
||||
# Format is:
|
||||
# <preferred e-mail> <other e-mail 1>
|
||||
# <preferred e-mail> <other e-mail 2>
|
@ -1,4 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_path=./os_net_config/tests
|
||||
top_dir=./
|
||||
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
os-net-config Style Commandments
|
||||
================================
|
||||
|
||||
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/
|
175
LICENSE
175
LICENSE
@ -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.
|
42
README.rst
42
README.rst
@ -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.
|
||||
|
@ -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]
|
@ -1,2 +0,0 @@
|
||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
@ -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}
|
@ -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/
|
@ -1,4 +0,0 @@
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
.. include:: ../../CONTRIBUTING.rst
|
@ -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
|
@ -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`
|
@ -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
|
@ -1 +0,0 @@
|
||||
.. include:: ../../README.rst
|
@ -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
|
@ -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" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -1,15 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-ctlplane",
|
||||
"ovs_fail_mode": "secure",
|
||||
"use_dhcp": "true",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
ovs_fail_mode: secure
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -1,14 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "contrail_vrouter",
|
||||
"name": "vhost0",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em3"
|
||||
}
|
||||
],
|
||||
"mtu": 1500
|
||||
}
|
||||
]
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: contrail_vrouter
|
||||
name: vhost0
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em3
|
||||
mtu: 1500
|
@ -1,15 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "contrail_vrouter_dpdk",
|
||||
"name": "vhost0",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em3"
|
||||
}
|
||||
],
|
||||
"mtu": 1500,
|
||||
"driver": "vfio"
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -1,15 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "contrail_vrouter",
|
||||
"name": "vhost0",
|
||||
"members": [
|
||||
{
|
||||
"type": "vlan",
|
||||
"vlan_id": 100,
|
||||
"device": "em3"
|
||||
}
|
||||
],
|
||||
"mtu": 1500
|
||||
}
|
||||
]
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: contrail_vrouter
|
||||
name: vhost0
|
||||
members:
|
||||
-
|
||||
type: vlan
|
||||
vlan_id: 100
|
||||
device: em3
|
||||
mtu: 1500
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -1,9 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: linux_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
@ -1,8 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "linux_tap",
|
||||
"name": "tap0",
|
||||
"use_dhcp": true
|
||||
}
|
||||
]
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: linux_tap
|
||||
name: tap0
|
||||
use_dhcp: true
|
||||
|
@ -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
|
@ -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
|
@ -1,5 +0,0 @@
|
||||
interface_mapping:
|
||||
nic1: em1
|
||||
nic2: em2
|
||||
nic3: em4
|
||||
nic4: em3
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -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
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
@ -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"
|
@ -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)
|
@ -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))
|
@ -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}")
|
@ -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
@ -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
@ -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()
|
@ -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))
|
@ -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()
|
@ -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: []
|
@ -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)
|
@ -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
@ -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
|
@ -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()
|
@ -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
Loading…
Reference in New Issue
Block a user