1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

ifupdown2 2.0.0 release

This is a major update coming all at once from master-next branch
master-next branch was started with --orphan option which is basically a new
branch without history.

The major changes are:
    - repackaging
    - cleanup the directory tree
    - rewritte setup.py to allow install from deb file or pypi (pip install)
    - add a Makefile to make things (like building a deb) easier
    - review all debian files

Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
This commit is contained in:
Julien Fortin
2018-12-13 11:43:32 -08:00
parent a9c3c89431
commit d486dd0df0
126 changed files with 13568 additions and 10783 deletions

View File

@@ -1,6 +0,0 @@
- There is a state issue if multiple configuration blocks are present for the same interface in the interfaces file
- `ifquery -r` can give wrong result if dhclient is running + static addresses are configured
- `ifquery -r` status is success for success case and also for cases where there
is no support for query yet
- setup.py has ifupdown listed in data section instead of scripts: This is because default location for scripts is /usr/bin/. And ifupdown default location is /sbin. With newer versions we can specify --install-scripts directory. This needs to be fixed then.
- and more :)

96
Makefile Normal file
View File

@@ -0,0 +1,96 @@
.PHONY: clean clean-test clean-pyc clean-build docs help
.DEFAULT_GOAL := help
define BROWSER_PYSCRIPT
import os, webbrowser, sys
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT
define PRINT_HELP_PYSCRIPT
import re, sys
for line in sys.stdin:
match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
if match:
target, help = match.groups()
print("%-20s %s" % (target, help))
endef
export PRINT_HELP_PYSCRIPT
BROWSER := python -c "$$BROWSER_PYSCRIPT"
help:
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
clean-build: ## remove build artifacts
rm -fr build/
rm -fr dist/
rm -fr .eggs/
find . -name '*.egg-info' -exec rm -fr {} +
find . -name '*.egg' -exec rm -f {} +
clean-pyc: ## remove Python file artifacts
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +
clean-test: ## remove test and coverage artifacts
rm -fr .tox/
rm -f .coverage
rm -fr htmlcov/
rm -fr .pytest_cache
lint: ## check style with flake8
flake8 ifupdown2 tests
test: ## run tests quickly with the default Python
py.test
test-all: ## run tests on every Python version with tox
tox
coverage: ## check code coverage quickly with the default Python
coverage run --source ifupdown2 -m pytest
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/ifupdown2.rst
rm -f docs/modules.rst
sphinx-apidoc -o docs/ ifupdown2
$(MAKE) -C docs clean
$(MAKE) -C docs html
$(BROWSER) docs/_build/html/index.html
servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
testpy: ## package and upload to testpy
python setup.py sdist bdist_wheel
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
@echo "Install ifupdown2 from testpy 'pip install --index-url https://test.pypi.org/simple/ ifupdown2'"
release: dist ## package and upload a release
twine upload dist/*
dist: clean ## builds source and wheel package
python setup.py sdist
python setup.py bdist_wheel
ls -l dist
install: clean ## install the package to the active Python's site-packages
python setup.py install
deb: clean ## create a debian package (.deb)
debuild -b -rfakeroot -us -uc

162
README Normal file
View File

@@ -0,0 +1,162 @@
=========
ifupdown2
=========
Linux Interface Network Manager
* Free software: GNU General Public License v2
============
Installation
============
As of today (early june 2018), the preferred method to install ifupdown2, is by
building the source code (as it will always install the most recent stable
release). See `Installing latest stable release from sources`_ chapter.
Installing latest stable release from sources
---------------------------------------------
The sources for ifupdown2 can be downloaded from the `Github repo`_.
You can either clone the public repository:
.. code-block:: console
$ git clone git://github.com/CumulusNetworks/ifupdown2
Or download the `tarball`_:
.. code-block:: console
$ curl -OL https://github.com/CumulusNetworks/ifupdown2/tarball/master
Once you have a copy of the source, you should build a deb-package and install it
.. code-block:: console
$ cd ifupdown2 && make deb
The generated deb should be in the root directory (``../ifupdown2_2.0.0_all.deb``)
.. code-block:: console
$ dpkg -i ../ifupdown2_2.0.0_all.deb
We don't recommend using ``setup.py install`` directly, as it's still missing systemd/init.d scripts.
This capability should be added in the near future.
You might need to manually download dependencies. Mandatory dependencies:
.. code-block:: console
$ apt-get install dh-systemd python-all python-docutils rst2man iproute2 python-ipaddr python-argcomplete
Suggested dependencies:
.. code-block:: console
$ apt-get install ethtool bridge-utils python-gvgen python-mako
.. _Github repo: https://github.com/CumulusNetworks/ifupdown2
.. _tarball: https://github.com/CumulusNetworks/ifupdown2/tarball/master
============
Contributing
============
Contributions are welcome, and they are greatly appreciated! Every little bit
helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions
----------------------
Report Bugs
~~~~~~~~~~~
Report bugs at https://github.com/CumulusNetworks/ifupdown2/issues.
If you are reporting a bug, please include:
* Your operating system name and version (``uname -a``).
* Any details about your setup that might be helpful in troubleshooting.
* Content of configuration files such as ``/etc/network/interfaces``
* Detailed steps to reproduce the bug.
* Debug output of the ifupdown2 command (see ``--debug`` option)
Write Documentation
~~~~~~~~~~~~~~~~~~~
ifupdown2 could always use more documentation, whether as part of the
official ifupdown2 docs, in docstrings, or even on the web in blog posts,
articles, and such.
Submit Feedback
~~~~~~~~~~~~~~~
The best way to send feedback is to file an issue at https://github.com/CumulusNetworks/ifupdown2/issues.
If you are proposing a feature:
* Explain in detail how it would work.
* Keep the scope as narrow as possible, to make it easier to implement.
=======
Credits
=======
Development Lead
----------------
* Roopa Prabhu <roopa@cumulusnetworks.com>
* Julien Fortin <julien@cumulusnetworks.com>
Contributors
------------
* Nikhil Gajendrakumar <nikhil.gajendrakumar@gmail.com>
* Maximilian Wilhelm <max@sdn.clinic>
* Sven Auhagen <sven.auhagen@voleatech.de>
* skorpy <magnus@skorpy.space>
* Sam Tannous <stannous@cumulusnetworks.com>
* Wilson Kok <wkok@cumulusnetworks.com>
* John Berezovik <berezovik@gmail.com>
* Daniel Walton <dwalton76@gmail.com>
* Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
* Balakrishnan Raman <balkee@yahoo.com>
* Scott Emery <scotte@cumulusnetworks.com>
* Dave Olson <olson@cumulusnetworks.com>
* David Ahern <dsa@cumulusnetworks.com>
* Jonathan Toppins <>
* Nolan Leake <nolan@cumulusnetworks.com>
* Sergey Sudakovich <sergey@cumulusnetworks.com>
* Andy Gospodarek <>
* Satish Ashok <sashok@cumulusnetworks.com>
* Scott Laffer <slaffer@cumulusnetworks.com>
* Vidya Sagar Ravipati <vidya.ravipati@gmail.com>
* Marek Grzybowski <marek.grzybowski@rtbhouse.com>
* Gaudenz Steinlin <gaudenz@users.noreply.github.com>
* Nigel Kukard <nkukard@lbsd.net>
* Jeffrey <jeffrey.bosma@gmail.com>
* kokel <kokel@users.noreply.github.com>
Why not you too? :)
=======
History
=======
See changelog here: https://github.com/CumulusNetworks/ifupdown2/blob/master/debian/changelog
Credits
-------
This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage

View File

@@ -1,75 +0,0 @@
ifupdown2
=========
ifupdown2 is a alternate implementation of debian's network interface manager
ifupdown.
ifupdown2 provides the required infrastructure to parse, schedule and
manage interface configuration. Also provides default python addon modules
for network interface configuration.
Note: Previously ifupdown2 came as two packages: python-ifupdown2 and
python-ifupdown2-addons. python-ifupdown2-addons contents are now merged into
python-ifupdown2 package (python-ifupdown2-addons package is hence deprecated).
Install
=======
## dependencies
To install the mandatory dependencies please execute the following command:
```
apt-get install python-ipaddr
apt-get install python-argcomplete
```
More recommended dependencies:
```
apt-get install bridge-utils
apt-get install ethtool
```
## debian & Ubuntu
To get our lastest version that is available on the debian repositories for your current OS just type
`apt-get install ifupdown2`
## Ubuntu users (anything bellow version Artful)
We highly recommend that you build your own debs or WGET a deb from the debian repo as we have trouble backporting our latest fixes and features in Zesty, Xenial and bellow.
```
wget http://ftp.us.debian.org/debian/pool/main/i/ifupdown2/ifupdown2_1.0~git20170314-1_all.deb
dpkg -i ifupdown2_1.0~git20170314-1_all.deb
```
## build your own deb
If ever the repositories for your OS version doesn't include latest ifupdown2 you can always build your own deb
To buid on Ubuntu and debian you'll some extra packages:
```
apt-get install build-essential dh-systemd dh-make python-docutils
```
Then run the following commands:
```
dpkg-buildpackage -us -uc -d
```
On the master branch this simple command should produce a `.deb` file that you can install using `dpkg -i`
On the `debian-prep2` branch, you'll need to run:
```
cd /path/to/ifupdown2/source/folder
git archive --format=tar HEAD | xz -9 -c >../ifupdown2_1.0~git20170314.orig.tar.xz && dpkg-buildpackage -us -uc -d
```
Note that the name of the tar archive needs to match the latest version present in the changelog. We usually use the date of the upload to tag a new version. In this previous example it was `20170314`
If you are experiencing any issues please feel free to open a new issue.

View File

@@ -1,73 +0,0 @@
python-ifupdown2
================
This package is a replacement for the debian ifupdown package.
It is ifupdown re-written in python. It maintains the original ifupdown
pluggable architecture and extends it further.
The python-ifupdown2 package provides the infrastructure for
parsing /etc/network/interfaces file, loading, scheduling and state
management of interfaces.
It dynamically loads python modules from /usr/share/ifupdownaddons.
To remain compatible with other packages that depend on ifupdown,
it also executes scripts under /etc/network/.
To make the transition smoother, a python module under
/usr/share/ifupdownaddons will override a script by the same name under
/etc/network/.
It publishes an interface object which is passed to all loadble python
modules. For more details on adding a addon module, see the section on
adding python modules.
pluggable python modules:
=========================
Unlike original ifupdown, all interface configuration is moved to external
python modules. That includes inet, inet6 and dhcp configurations.
A set of default modules are included in the package.
python-ifupdown2 expects a few things from the pluggable modules:
- the module should implement a class by the same name
- the interface object (class iface) and the operation to be performed is
passed to the modules
- the python addon class should provide a few methods:
- run() : method to configure the interface.
- get_ops() : must return a list of operations it supports.
eg: 'pre-up', 'post-down'
- get_dependent_ifacenames() : must return a list of interfaces the
interface is dependent on. This is used to build the dependency list
for sorting and executing interfaces in dependency order.
- if the module supports -r option to ifquery, ie ability to construct the
ifaceobj from running state, it can optionally implement the
get_dependent_ifacenames_running() method, to return the list of
dependent interfaces derived from running state of the interface.
This is different from get_dependent_ifacenames() where the dependent
interfaces are derived from the interfaces config file (provided by the
user).
Example: Address handling module /usr/share/ifupdownaddons/address.py
build
=====
- get source
- install build dependencies:
apt-get install python-stdeb python-docutils
- cd <python-ifupdown2 sourcedir> && ./build.sh
(generates python-ifupdown2-<ver>.deb)
install
=======
- remove existing ifupdown package
dpkg -r ifupdown
- install python-ifupdown2 using `dpkg -i`
- or install from deb
dpkg -i python-ifupdown2-<ver>.deb

36
TODO
View File

@@ -1,36 +0,0 @@
TODO:
====
- support old ifupdown state file /run/network/ifstate. Because some app's seem to use it
- support for debian ifupdown methods: tunnel, v4tunnel, 6to4, ppp, wvdial, ipv4ll
- support for debian ifupdown ipv6 auto method
- support for debian ifupdown CAN address family
- Compat : support for LOGICAL interfaces
- dry-run improvement: It skips the cache completely. Which means It tells you the commands it would execute if the system is clean. Its not smart enought to say what it will really execute given the state of the system
- Ifquery does not report link status, mainly because it reports only in terms of /etc/network/interfaces attributes. Plan to fix that
- more Documentation
- Priorities for addon modules
- have ability to also run uninstall on interfaces that dont have any config
- ifup hotplug support (basically needs some testing and fixing broken things)
- -q quiet option
- support for /etc/networking.defaults
- implement legacy ifupdown mapping feature
- support for the following ifupdown options:
-o OPTION=VALUE set OPTION to VALUE as though it were in
/etc/network/interfaces
--no-mappings don't run any mappings
--no-scripts don't run any hook scripts
- parallel implementation
- Test all original ifupdown options for compatibility
- Test with ifupdown-extra, ifmetric, ifupdown-scripts-zg2
- export other environment variables to bash scripts (for backward compatibility):
IFACE physical name of the interface being processed
LOGICAL logical name of the interface being processed
ADDRFAM address family of the interface
METHOD method of the interface (e.g., static)
MODE start if run from ifup, stop if run from ifdown
PHASE as per MODE, but with finer granularity, distinguishing the pre-
up, post-up, pre-down and post-down phases.
VERBOSITY indicates whether --verbose was used; set to 1 if so, 0 if not.
PATH the command search path: /usr/local/sbin:/usr/local/bin:
/usr/sbin:/usr/bin:/sbin:/bin

View File

@@ -1,13 +0,0 @@
TODO:
====
- run python code guideline checker
- more code documentation
- move all cache handling to decorators in ifupdownaddons package
- input validation (present in some cases not all)
- support the vlan0004 style vlans
- ifquery coverage. currently it is at 80%.
- vxlan module
- fix and release ifaddon utility to manage module priorities
- Deep compare in query for address module (does not compare address attributes like scope)
- Maybe a pure netlink backend
- improve caching

View File

@@ -1,344 +0,0 @@
#!/usr/bin/python
#
# Copyright 2016-2017 Maximilian Wilhelm <max@sdn.clinic>
# Author: Maximilian Wilhelm, max@sdn.clinic
#
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
import logging
import re
import subprocess
class batman_adv (moduleBase):
""" ifupdown2 addon module to configure B.A.T.M.A.N. advanced interfaces """
_modinfo = {
'mhelp' : 'batman_adv module configures B.A.T.M.A.N. advanced interfaces.' +
'Every B.A.T.M.A.N. advanced interface needs at least on ethernet ' +
'interface to be creatable. You can specify a space separated list' +
'of interfaces by using the "batma-ifaces" paramater. If this parameter' +
'is set for an interfaces this module will do the magic.',
'attrs' : {
'batman-ifaces' : {
'help' : 'Interfaces to be part of this B.A.T.M.A.N. advanced instance',
'validvals' : [ '<interface-list>' ],
'required' : True,
},
'batman-ifaces-ignore-regex' : {
'help' : 'Interfaces to ignore when verifying configuration (regexp)',
'required' : False,
},
'batman-distributed-arp-table' : {
'help' : 'B.A.T.M.A.N. distributed ARP table',
'validvals' : [ 'enabled', 'disabled' ],
'required' : False,
'batman-attr' : True,
},
'batman-gw-mode' : {
'help' : 'B.A.T.M.A.N. gateway mode',
'validvals' : [ 'off', 'client', 'server' ],
'required' : False,
'example' : [ 'batman-gw-mode client' ],
'batman-attr' : True,
},
'batman-hop-penalty' : {
'help' : 'B.A.T.M.A.N. hop penalty',
'validvals' : [ '<number>' ],
'required' : False,
'batman-attr' : True,
},
'batman-multicast-mode' : {
'help' : 'B.A.T.M.A.N. multicast mode',
'validvals' : [ 'enabled', 'disabled' ],
'required' : False,
'batman-attr' : True,
},
}
}
_batman_attrs = {
}
def __init__ (self, *args, **kargs):
moduleBase.__init__ (self, *args, **kargs)
self.ipcmd = None
for longname, entry in self._modinfo['attrs'].items ():
if entry.get ('batman-attr', False) == False:
continue
attr = longname.replace ("batman-", "")
self._batman_attrs[attr] = {
'filename' : attr.replace ("-", "_"),
}
def _is_batman_device (self, ifaceobj):
if ifaceobj.get_attr_value_first ('batman-ifaces'):
return True
return False
def _get_batman_ifaces (self, ifaceobj ):
batman_ifaces = ifaceobj.get_attr_value_first ('batman-ifaces')
if batman_ifaces:
return sorted (batman_ifaces.split ())
return None
def _get_batman_ifaces_ignore_regex (self, ifaceobj):
ifaces_ignore_regex = ifaceobj.get_attr_value_first ('batman-ifaces-ignore-regex')
if ifaces_ignore_regex:
return re.compile (r"%s" % ifaces_ignore_regex)
return None
def _get_batman_attr (self, ifaceobj, attr):
if attr not in self._batman_attrs:
raise ValueError ("_get_batman_attr: Invalid or unsupported B.A.T.M.A.N. adv. attribute: %s" % attr)
value = ifaceobj.get_attr_value_first ('batman-%s' % attr)
if value:
return value
return None
def _read_current_batman_attr (self, ifaceobj, attr):
if attr not in self._batman_attrs:
raise ValueError ("_read_current_batman_attr: Invalid or unsupported B.A.T.M.A.N. adv. attribute: %s" % attr)
attr_file_name = self._batman_attrs[attr]['filename']
attr_file_path = "/sys/class/net/%s/mesh/%s" % (ifaceobj.name, attr_file_name)
try:
with open (attr_file_path, "r") as fh:
return fh.readline ().strip ()
except IOError as i:
raise Exception ("_read_current_batman_attr (%s) %s" % (attr, i))
except ValueError:
raise Exception ("_read_current_batman_attr: Integer value expected, got: %s" % value)
def _set_batman_attr (self, ifaceobj, attr, value):
if attr not in self._batman_attrs:
raise ValueError ("_set_batman_attr: Invalid or unsupported B.A.T.M.A.N. adv. attribute: %s" % attr)
attr_file_name = self._batman_attrs[attr]['filename']
attr_file_path = "/sys/class/net/%s/mesh/%s" % (ifaceobj.name, attr_file_name)
try:
with open (attr_file_path, "w") as fh:
fh.write ("%s\n" % value)
except IOError as i:
raise Exception ("_set_batman_attr (%s): %s" % (attr, i))
def _batctl_if (self, bat_iface, mesh_iface, op):
if op not in [ 'add', 'del' ]:
raise Exception ("_batctl_if() called with invalid \"op\" value: %s" % op)
try:
self.logger.debug ("Running batctl -m %s if %s %s" % (bat_iface, op, mesh_iface))
batctl_output = subprocess.check_output (["batctl", "-m", bat_iface, "if", op, mesh_iface], stderr = subprocess.STDOUT)
except subprocess.CalledProcessError as c:
raise Exception ("Command \"batctl -m %s if %s %s\" failed: %s" % (bat_iface, op, mesh_iface, c.output))
except Exception as e:
raise Exception ("_batctl_if: %s" % e)
def _find_member_ifaces (self, ifaceobj, ignore = True):
members = []
iface_ignore_re = self._get_batman_ifaces_ignore_regex (ifaceobj)
batctl_fh = subprocess.Popen (["batctl", "-m", ifaceobj.name, "if"], bufsize = 4194304, stdout = subprocess.PIPE).stdout
for line in batctl_fh.readlines ():
iface = line.split (':')[0]
if iface_ignore_re and iface_ignore_re.match (iface) and ignore:
continue
members.append (iface)
return sorted (members)
def get_dependent_ifacenames (self, ifaceobj, ifaceobjs_all=None):
if not self._is_batman_device (ifaceobj):
return None
ifaceobj.link_kind |= ifaceLinkKind.BATMAN_ADV
batman_ifaces = self._get_batman_ifaces (ifaceobj)
if batman_ifaces:
return batman_ifaces
return [None]
def _up (self, ifaceobj):
if self._get_batman_ifaces (ifaceobj) == None:
raise Exception ('could not determine batman interfacaes')
# Verify existance of batman interfaces (should be present already)
batman_ifaces = []
for iface in self._get_batman_ifaces (ifaceobj):
if not self.ipcmd.link_exists (iface):
self.logger.warn ('batman iface %s not present' % iface)
continue
batman_ifaces.append (iface)
if len (batman_ifaces) == 0:
raise Exception ("None of the configured batman interfaces are available!")
if_ignore_re = self._get_batman_ifaces_ignore_regex (ifaceobj)
# Is the batman main interface already present?
if self.ipcmd.link_exists (ifaceobj.name):
# Verify which member interfaces are present
members = self._find_member_ifaces (ifaceobj)
for iface in members:
if iface not in batman_ifaces:
self._batctl_if (ifaceobj.name, iface, 'del')
for iface in batman_ifaces:
if iface not in members:
self._batctl_if (ifaceobj.name, iface, 'add')
# Batman interfaces no present, add member interfaces to create it
else:
for iface in batman_ifaces:
self._batctl_if (ifaceobj.name, iface, 'add')
# Check/set any B.A.T.M.A.N. adv. set within interface configuration
for attr in self._batman_attrs:
value_cfg = self._get_batman_attr (ifaceobj, attr)
if value_cfg and value_cfg != self._read_current_batman_attr (ifaceobj, attr):
self._set_batman_attr (ifaceobj, attr, value_cfg)
if ifaceobj.addr_method == 'manual':
netlink.link_set_updown(ifaceobj.name, "up")
def _down (self, ifaceobj):
if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists (ifaceobj.name):
return
members = self._find_member_ifaces (ifaceobj)
for iface in members:
self._batctl_if (ifaceobj.name, iface, 'del')
# The main interface will automagically vanish after the last member
# interface has been deleted.
def _query_check (self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists (ifaceobj.name):
return
batman_ifaces_cfg = self._get_batman_ifaces (ifaceobj)
batman_ifaces_real = self._find_member_ifaces (ifaceobj, False)
# Produce list of all current interfaces, tag interfaces ignored by
# regex with () around the iface name.
batman_ifaces_real_tagged = []
iface_ignore_re_str = ifaceobj.get_attr_value_first ('batman-ifaces-ignore-regex')
iface_ignore_re = self._get_batman_ifaces_ignore_regex (ifaceobj)
# Assume everything's fine and wait for reality to prove us otherwise
ifaces_ok = 0
# Interfaces configured but not active?
for iface in batman_ifaces_cfg:
if iface not in batman_ifaces_real:
ifaces_ok = 1
# Interfaces active but not configured (or ignored)?
for iface in batman_ifaces_real:
if iface not in batman_ifaces_cfg:
if iface_ignore_re and iface_ignore_re.match (iface):
batman_ifaces_real_tagged.append ("(%s)" % iface)
continue
ifaces_ok = 1
else:
batman_ifaces_real_tagged.append (iface)
# Produce sorted list of active and ignored interfaces
ifaces_str = " ".join (batman_ifaces_real_tagged)
ifaceobjcurr.update_config_with_status ('batman-ifaces', ifaces_str, ifaces_ok)
ifaceobjcurr.update_config_with_status ('batman-ifaces-ignore-regex', iface_ignore_re_str, 0)
# Check any B.A.T.M.A.N. adv. set within interface configuration
for attr in self._batman_attrs:
value_cfg = self._get_batman_attr (ifaceobj, attr)
value_curr = self._read_current_batman_attr (ifaceobj, attr)
# Ignore this attribute if its'nt configured for this interface
if not value_cfg:
continue
value_ok = 0
if value_cfg != value_curr:
value_ok = 1
ifaceobjcurr.update_config_with_status ('batman-%s' % attr, value_curr, value_ok)
def _query_running (self, ifaceobjrunning):
if not self.ipcmd.link_exists (ifaceobjrunning.name):
return
# XXX Now what?
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check}
# XXX 'query-running' : _query_running}
def get_ops (self):
""" returns list of ops supported by this module """
return self._run_ops.keys ()
def _init_command_handlers (self):
if not self.ipcmd:
self.ipcmd = iproute2()
def run (self, ifaceobj, operation, query_ifaceobj = None, **extra_args):
""" run B.A.T.M.A.N. configuration on the interface object passed as argument
Args:
**ifaceobj** (object): iface object
**operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
'query-running'
Kwargs:
**query_ifaceobj** (object): query check ifaceobject. This is only
valid when op is 'query-checkcurr'. It is an object same as
ifaceobj, but contains running attribute values and its config
status. The modules can use it to return queried running state
of interfaces. status is success if the running state is same
as user required state in ifaceobj. error otherwise.
"""
op_handler = self._run_ops.get (operation)
if not op_handler:
return
if (operation != 'query-running' and not self._is_batman_device (ifaceobj)):
return
self._init_command_handlers ()
if operation == 'query-checkcurr':
op_handler (self, ifaceobj, query_ifaceobj)
else:
op_handler (self, ifaceobj)

View File

@@ -1,485 +0,0 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from sets import Set
from ifupdown.iface import *
import ifupdownaddons
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.bondutil import bondutil
from ifupdownaddons.iproute2 import iproute2
from ifupdown.netlink import netlink
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.utils import utils
class bond(moduleBase):
""" ifupdown2 addon module to configure bond interfaces """
overrides_ifupdown_scripts = ['ifenslave', ]
_modinfo = { 'mhelp' : 'bond configuration module',
'attrs' : {
'bond-use-carrier':
{'help' : 'bond use carrier',
'validvals' : ['yes', 'no', '0', '1'],
'default' : 'yes',
'example': ['bond-use-carrier yes']},
'bond-num-grat-arp':
{'help' : 'bond use carrier',
'validrange' : ['0', '255'],
'default' : '1',
'example' : ['bond-num-grat-arp 1']},
'bond-num-unsol-na' :
{'help' : 'bond slave devices',
'validrange' : ['0', '255'],
'default' : '1',
'example' : ['bond-num-unsol-na 1']},
'bond-xmit-hash-policy' :
{'help' : 'bond slave devices',
'validvals' : ['layer2', 'layer3+4', 'layer2+3'],
'default' : 'layer2',
'example' : ['bond-xmit-hash-policy layer2']},
'bond-miimon' :
{'help' : 'bond miimon',
'validrange' : ['0', '255'],
'default' : '0',
'example' : ['bond-miimon 0']},
'bond-mode' :
{'help': 'bond mode',
'validvals': ['0', 'balance-rr',
'1', 'active-backup',
'2', 'balance-xor',
'3', 'broadcast',
'4', '802.3ad',
'5', 'balance-tlb',
'6', 'balance-alb'],
'default': 'balance-rr',
'example': ['bond-mode 802.3ad']},
'bond-lacp-rate':
{'help' : 'bond lacp rate',
'validvals' : ['0', '1'],
'default' : '0',
'example' : ['bond-lacp-rate 0']},
'bond-min-links':
{'help' : 'bond min links',
'default' : '0',
'validrange' : ['0', '255'],
'example' : ['bond-min-links 0']},
'bond-ad-sys-priority':
{'help' : '802.3ad system priority',
'default' : '65535',
'validrange' : ['0', '65535'],
'example' : ['bond-ad-sys-priority 65535'],
'deprecated' : True,
'new-attribute' : 'bond-ad-actor-sys-prio'},
'bond-ad-actor-sys-prio':
{'help' : '802.3ad system priority',
'default' : '65535',
'validrange' : ['0', '65535'],
'example' : ['bond-ad-actor-sys-prio 65535']},
'bond-ad-sys-mac-addr':
{'help' : '802.3ad system mac address',
'default' : '00:00:00:00:00:00',
'validvals': ['<mac>', ],
'example' : ['bond-ad-sys-mac-addr 00:00:00:00:00:00'],
'deprecated' : True,
'new-attribute' : 'bond-ad-actor-system'},
'bond-ad-actor-system':
{'help' : '802.3ad system mac address',
'default' : '00:00:00:00:00:00',
'validvals': ['<mac>', ],
'example' : ['bond-ad-actor-system 00:00:00:00:00:00'],},
'bond-lacp-bypass-allow':
{'help' : 'allow lacp bypass',
'validvals' : ['yes', 'no', '0', '1'],
'default' : 'no',
'example' : ['bond-lacp-bypass-allow no']},
'bond-slaves' :
{'help' : 'bond slaves',
'required' : True,
'multivalue' : True,
'validvals': ['<interface-list>'],
'example' : ['bond-slaves swp1 swp2',
'bond-slaves glob swp1-2',
'bond-slaves regex (swp[1|2)'],
'aliases': ['bond-ports']},
'bond-updelay' :
{'help' : 'bond updelay',
'default' : '0',
'validrange' : ['0', '65535'],
'example' : ['bond-updelay 100']},
'bond-downdelay':
{'help' : 'bond downdelay',
'default' : '0',
'validrange' : ['0', '65535'],
'example' : ['bond-downdelay 100']}
}}
_bond_mode_num = {'0': 'balance-rr',
'1': 'active-backup',
'2': 'balance-xor',
'3': 'broadcast',
'4': '802.3ad',
'5': 'balance-tlb',
'6': 'balance-alb'}
_bond_mode_string = {'balance-rr': '0',
'active-backup': '1',
'balance-xor': '2',
'broadcast': '3',
'802.3ad': '4',
'balance-tlb': '5',
'balance-alb': '6'}
@staticmethod
def _get_readable_bond_mode(mode):
if mode in bond._bond_mode_num:
return bond._bond_mode_num[mode]
return mode
@staticmethod
def _get_num_bond_mode(mode):
if mode in bond._bond_mode_string:
return bond._bond_mode_string[mode]
return mode
def __init__(self, *args, **kargs):
ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self.bondcmd = None
def get_bond_slaves(self, ifaceobj):
slaves = ifaceobj.get_attr_value_first('bond-slaves')
if not slaves:
slaves = ifaceobj.get_attr_value_first('bond-ports')
return slaves
def _is_bond(self, ifaceobj):
if self.get_bond_slaves(ifaceobj):
return True
return False
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
""" Returns list of interfaces dependent on ifaceobj """
if not self._is_bond(ifaceobj):
return None
slave_list = self.parse_port_list(ifaceobj.name,
self.get_bond_slaves(ifaceobj),
ifacenames_all)
ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
# Also save a copy for future use
ifaceobj.priv_data = list(slave_list)
if ifaceobj.link_type != ifaceLinkType.LINK_NA:
ifaceobj.link_type = ifaceLinkType.LINK_MASTER
ifaceobj.link_kind |= ifaceLinkKind.BOND
ifaceobj.role |= ifaceRole.MASTER
return slave_list
def get_dependent_ifacenames_running(self, ifaceobj):
self._init_command_handlers()
return self.bondcmd.get_slaves(ifaceobj.name)
def _get_slave_list(self, ifaceobj):
""" Returns slave list present in ifaceobj config """
# If priv data already has slave list use that first.
if ifaceobj.priv_data:
return ifaceobj.priv_data
slaves = self.get_bond_slaves(ifaceobj)
if slaves:
return self.parse_port_list(ifaceobj.name, slaves)
else:
return None
def _is_clag_bond(self, ifaceobj):
if self.get_bond_slaves(ifaceobj):
attrval = ifaceobj.get_attr_value_first('clag-id')
if attrval and attrval != '0':
return True
return False
def fetch_attr(self, ifaceobj, attrname):
attrval = ifaceobj.get_attr_value_first(attrname)
# grab the defaults from the policy file in case the
# user did not specify something.
policy_default_val = policymanager.policymanager_api.\
get_iface_default(module_name=self.__class__.__name__,
ifname=ifaceobj.name,
attr=attrname)
if attrval:
if attrname == 'bond-mode':
attrval = bond._get_readable_bond_mode(attrval)
if attrval == '802.3ad':
dattrname = 'bond-min-links'
min_links = ifaceobj.get_attr_value_first(dattrname)
if not min_links:
min_links = self.bondcmd.get_min_links(ifaceobj.name)
if min_links == '0':
self.logger.warn('%s: attribute %s'
%(ifaceobj.name, dattrname) +
' is set to \'0\'')
elif policy_default_val:
return policy_default_val
return attrval
def _apply_master_settings(self, ifaceobj):
have_attrs_to_set = 0
linkup = False
bondcmd_attrmap = OrderedDict([('bond-mode' , 'mode'),
('bond-miimon' , 'miimon'),
('bond-use-carrier', 'use_carrier'),
('bond-lacp-rate' , 'lacp_rate'),
('bond-xmit-hash-policy' , 'xmit_hash_policy'),
('bond-min-links' , 'min_links'),
('bond-num-grat-arp' , 'num_grat_arp'),
('bond-num-unsol-na' , 'num_unsol_na'),
('bond-ad-sys-mac-addr' , 'ad_actor_system'),
('bond-ad-actor-system' , 'ad_actor_system'),
('bond-ad-sys-priority' , 'ad_actor_sys_prio'),
('bond-ad-actor-sys-prio' , 'ad_actor_sys_prio'),
('bond-lacp-bypass-allow', 'lacp_bypass'),
('bond-updelay', 'updelay'),
('bond-downdelay', 'downdelay')])
linkup = self.ipcmd.is_link_up(ifaceobj.name)
try:
# order of attributes set matters for bond, so
# construct the list sequentially
attrstoset = OrderedDict()
for k, dstk in bondcmd_attrmap.items():
v = self.fetch_attr(ifaceobj, k)
if v:
attrstoset[dstk] = v
if not attrstoset:
return
# support yes/no attrs
utils.support_yesno_attrs(attrstoset, ['use_carrier', 'lacp_bypass'])
have_attrs_to_set = 1
self.bondcmd.set_attrs(ifaceobj.name, attrstoset,
self.ipcmd.link_down if linkup else None)
except:
raise
finally:
if have_attrs_to_set and linkup:
netlink.link_set_updown(ifaceobj.name, 'up')
def _add_slaves(self, ifaceobj):
runningslaves = []
slaves = self._get_slave_list(ifaceobj)
if not slaves:
self.logger.debug('%s: no slaves found' %ifaceobj.name)
return
if not ifupdownflags.flags.PERFMODE:
runningslaves = self.bondcmd.get_slaves(ifaceobj.name);
clag_bond = self._is_clag_bond(ifaceobj)
for slave in Set(slaves).difference(Set(runningslaves)):
if (not ifupdownflags.flags.PERFMODE and
not self.ipcmd.link_exists(slave)):
self.log_error('%s: skipping slave %s, does not exist'
%(ifaceobj.name, slave), ifaceobj,
raise_error=False)
continue
link_up = False
if self.ipcmd.is_link_up(slave):
netlink.link_set_updown(slave, "down")
link_up = True
# If clag bond place the slave in a protodown state; clagd
# will protoup it when it is ready
if clag_bond:
try:
netlink.link_set_protodown(slave, "on")
except Exception, e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
netlink.link_set_master(slave, ifaceobj.name)
if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
try:
netlink.link_set_updown(slave, "up")
except Exception, e:
self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
pass
if runningslaves:
for s in runningslaves:
if s not in slaves:
self.bondcmd.remove_slave(ifaceobj.name, s)
if clag_bond:
try:
netlink.link_set_protodown(s, "off")
except Exception, e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
def _up(self, ifaceobj):
try:
if not self.ipcmd.link_exists(ifaceobj.name):
self.bondcmd.create_bond(ifaceobj.name)
self._apply_master_settings(ifaceobj)
self._add_slaves(ifaceobj)
except Exception, e:
self.log_error(str(e), ifaceobj)
def _down(self, ifaceobj):
try:
self.bondcmd.delete_bond(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
slaves = None
if not self.bondcmd.bond_exists(ifaceobj.name):
self.logger.debug('bond iface %s' %ifaceobj.name +
' does not exist')
return
ifaceattrs = self.dict_key_subset(ifaceobj.config,
self.get_mod_attrs())
if not ifaceattrs: return
runningattrs = self._query_running_attrs(ifaceobj.name)
# support yes/no attributes
utils.support_yesno_attrs(runningattrs, ['bond-use-carrier',
'bond-lacp-bypass-allow'],
ifaceobj=ifaceobj)
# support for numerical bond-mode
mode = ifaceobj.get_attr_value_first('bond-mode')
if mode in bond._bond_mode_num:
if 'bond-mode' in runningattrs:
runningattrs['bond-mode'] = bond._get_num_bond_mode(runningattrs['bond-mode'])
bond_slaves = True
for k in ifaceattrs:
v = ifaceobj.get_attr_value_first(k)
if not v:
continue
if k == 'bond-slaves':
slaves = self._get_slave_list(ifaceobj)
continue
elif k == 'bond-ports':
bond_slaves = False
slaves = self._get_slave_list(ifaceobj)
continue
rv = runningattrs.get(k)
if not rv:
ifaceobjcurr.update_config_with_status(k, 'None', 1)
else:
ifaceobjcurr.update_config_with_status(k, rv,
1 if v != rv else 0)
runningslaves = runningattrs.get('bond-slaves')
if not slaves and not runningslaves:
return
retslave = 1
if slaves and runningslaves:
if slaves and runningslaves:
difference = set(slaves).symmetric_difference(runningslaves)
if not difference:
retslave = 0
# we want to display the same bond-slaves list as provided
# in the interfaces file but if this list contains regexes or
# globs, for now, we won't try to change it.
if 'regex' in slaves or 'glob' in slaves:
slaves = runningslaves
else:
ordered = []
for i in range(0, len(slaves)):
if slaves[i] in runningslaves:
ordered.append(slaves[i])
slaves = ordered
ifaceobjcurr.update_config_with_status('bond-slaves' if bond_slaves else 'bond-ports',
' '.join(slaves)
if slaves else 'None', retslave)
def _query_running_attrs(self, bondname):
bondattrs = {'bond-mode' :
self.bondcmd.get_mode(bondname),
'bond-miimon' :
self.bondcmd.get_miimon(bondname),
'bond-use-carrier' :
self.bondcmd.get_use_carrier(bondname),
'bond-lacp-rate' :
self.bondcmd.get_lacp_rate(bondname),
'bond-min-links' :
self.bondcmd.get_min_links(bondname),
'bond-ad-actor-system' :
self.bondcmd.get_ad_actor_system(bondname),
'bond-ad-actor-sys-prio' :
self.bondcmd.get_ad_actor_sys_prio(bondname),
'bond-xmit-hash-policy' :
self.bondcmd.get_xmit_hash_policy(bondname),
'bond-lacp-bypass-allow' :
self.bondcmd.get_lacp_bypass_allow(bondname),
'bond-num-unsol-na' :
self.bondcmd.get_num_unsol_na(bondname),
'bond-num-grat-arp' :
self.bondcmd.get_num_grat_arp(bondname),
'bond-updelay' :
self.bondcmd.get_updelay(bondname),
'bond-downdelay' :
self.bondcmd.get_downdelay(bondname)}
slaves = self.bondcmd.get_slaves(bondname)
if slaves:
bondattrs['bond-slaves'] = slaves
return bondattrs
def _query_running(self, ifaceobjrunning):
if not self.bondcmd.bond_exists(ifaceobjrunning.name):
return
bondattrs = self._query_running_attrs(ifaceobjrunning.name)
if bondattrs.get('bond-slaves'):
bondattrs['bond-slaves'] = ' '.join(bondattrs.get('bond-slaves'))
[ifaceobjrunning.update_config(k, v)
for k, v in bondattrs.items()
if v and v != self.get_mod_subattr(k, 'default')]
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-running' : _query_running,
'query-checkcurr' : _query_check}
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
if not self.bondcmd:
self.bondcmd = bondutil()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run bond configuration on the interface object passed as argument
Args:
**ifaceobj** (object): iface object
**operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
'query-running'
Kwargs:
**query_ifaceobj** (object): query check ifaceobject. This is only
valid when op is 'query-checkcurr'. It is an object same as
ifaceobj, but contains running attribute values and its config
status. The modules can use it to return queried running state
of interfaces. status is success if the running state is same
as user required state in ifaceobj. error otherwise.
"""
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if operation != 'query-running' and not self._is_bond(ifaceobj):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

File diff suppressed because it is too large Load Diff

View File

@@ -1,88 +0,0 @@
#!/usr/bin/python
# This should be pretty simple and might not really even need to exist.
# The key is that we need to call link_create with a type of "dummy"
# since that will translate to 'ip link add loopbackX type dummy'
# The config file should probably just indicate that the type is
# loopback or dummy.
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
import ifupdown.ifupdownflags as ifupdownflags
import logging
class link(moduleBase):
_modinfo = {'mhelp' : 'create/configure link types. similar to ip-link',
'attrs' : {
'link-type' :
{'help' : 'type of link as in \'ip link\' command.',
'validvals' : ['dummy', 'veth'],
'example' : ['link-type <dummy|veth>']},
'link-down' :
{'help': 'keep link down',
'example' : ['link-down yes/no'],
'default' : 'no',
'validvals' : ['yes', 'no']}}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
def _is_my_interface(self, ifaceobj):
if ifaceobj.get_attr_value_first('link-type'):
return True
return False
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if ifaceobj.get_attr_value_first('link-down') == 'yes':
ifaceobj.link_privflags |= ifaceLinkPrivFlags.KEEP_LINK_DOWN
def _up(self, ifaceobj):
self.ipcmd.link_create(ifaceobj.name,
ifaceobj.get_attr_value_first('link-type'))
def _down(self, ifaceobj):
if (not ifupdownflags.flags.PERFMODE and
not self.ipcmd.link_exists(ifaceobj.name)):
return
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists(ifaceobj.name):
ifaceobjcurr.update_config_with_status('link-type', 'None', 1)
else:
link_type = ifaceobj.get_attr_value_first('link-type')
if self.ipcmd.link_get_kind(ifaceobj.name) == link_type:
ifaceobjcurr.update_config_with_status('link-type',
link_type, 0)
else:
ifaceobjcurr.update_config_with_status('link-type',
link_type, 1)
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check}
def get_ops(self):
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if (operation != 'query-running' and
not self._is_my_interface(ifaceobj)):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

View File

@@ -1,63 +0,0 @@
#!/usr/bin/python
# This should be pretty simple and might not really even need to exist.
# The key is that we need to call link_create with a type of "dummy"
# since that will translate to 'ip link add loopbackX type dummy'
# The config file should probably just indicate that the type is
# loopback or dummy.
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
import logging
class loopback(moduleBase):
_modinfo = {'mhelp' : 'configure extra loopback module based on ' +
'dummy device' }
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
def _is_loopback_by_name(self, ifacename):
return 'loop' in ifacename
def _up(self, ifaceobj):
if self._is_loopback_by_name(ifaceobj.name):
self.ipcmd.link_create(ifaceobj.name, 'dummy')
def _down(self, ifaceobj):
if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
return
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists(ifaceobj.name):
return
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check}
def get_ops(self):
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if (operation != 'query-running' and
not self._is_loopback_by_name(ifaceobj.name)):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

View File

@@ -1,140 +0,0 @@
#!/usr/bin/python
try:
import os
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownflags as ifupdownflags
import logging
import hashlib
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdown.netlink import netlink
from ifupdown.exceptions import moduleNotSupported
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class ppp (moduleBase):
_modinfo = { 'mhelp' : 'create/configure ppp interfaces',
'attrs' : {
'provider' :
{ 'help' : 'Provider file in ppp',
'validvals' : ['<text>'],
'required' : True,
'example' : ['dsl-provider']},
'ppp-physdev' :
{ 'help' : 'Physical underlay device to use for ppp if any',
'validvals' : ['<interface>'],
'required' : False,
'example' : ['ppp-physdev eth1']},
}
}
def __init__ (self, *args, **kargs):
moduleBase.__init__ (self, *args, **kargs)
if not os.path.exists('/usr/bin/pon'):
raise moduleNotSupported('module init failed: no /usr/bin/pon found')
self.ipcmd = None
def _is_my_interface (self, ifaceobj):
if ifaceobj.addr_method == "ppp" and ifaceobj.get_attr_value_first ('provider'):
return True
return False
def _up (self, ifaceobj):
'''
Up the PPP connection
'''
provider = ifaceobj.get_attr_value_first ('provider')
old_config = None
old_provider = None
try:
ppp_file = os.path.join('/etc/ppp/peers', provider)
if not os.path.isfile(ppp_file):
self.log_warn('Invalid ppp provider file does not exist')
return
# Load state data
saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name)
if saved_ifaceobjs:
old_provider = saved_ifaceobjs[0].get_attr_value_first ('provider')
old_config = saved_ifaceobjs[0].get_attr_value_first ('provider_file')
config = hashlib.sha256(open(ppp_file, 'rb').read()).hexdigest()
# Always save the current config files hash
ifaceobj.update_config('provider_file', config)
if not self.ipcmd.link_exists(ifaceobj.name):
utils.exec_commandl(['/usr/bin/pon', provider], stdout=None, stderr=None)
elif old_config and old_config != config:
# Restart on config change
utils.exec_commandl(['/usr/bin/poff', provider], stdout=None, stderr=None)
utils.exec_commandl(['/usr/bin/pon', provider], stdout=None, stderr=None)
elif old_provider and old_provider != provider:
# Restart on provider change
utils.exec_commandl(['/usr/bin/poff', old_provider], stdout=None, stderr=None)
utils.exec_commandl(['/usr/bin/pon', provider], stdout=None, stderr=None)
except Exception, e:
self.log_warn (str (e))
def _down (self, ifaceobj):
if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists (ifaceobj.name):
return
try:
provider = ifaceobj.get_attr_value_first ('provider')
utils.exec_commandl(['/usr/bin/poff', provider], stdout=None, stderr=None)
except Exception, e:
self.log_warn (str (e))
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if not self._is_my_interface(ifaceobj):
return None
device = ifaceobj.get_attr_value_first ('ppp-physdev')
if device:
return [device]
return None
def _query_check (self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists(ifaceobj.name):
return
ifaceobjcurr.status = ifaceStatus.SUCCESS
def _query_running(self, ifaceobjrunning):
if not self.ipcmd.link_exists(ifaceobjrunning.name):
return
# Operations supported by this addon (yet).
_run_ops = {
'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check,
'query-running' : _query_running,
}
def get_ops (self):
return self._run_ops.keys()
def _init_command_handlers (self):
if not self.ipcmd:
self.ipcmd = iproute2 ()
def run (self, ifaceobj, operation, query_ifaceobj = None, **extra_args):
op_handler = self._run_ops.get (operation)
if not op_handler:
return
if operation != 'query-running' and not self._is_my_interface (ifaceobj):
return
self._init_command_handlers ()
if operation == 'query-checkcurr':
op_handler (self, ifaceobj, query_ifaceobj)
else:
op_handler (self, ifaceobj)

View File

@@ -1,192 +0,0 @@
#!/usr/bin/python
#
# Maximilian Wilhelm <max@rfc2324.org>
# -- Mon 10 Oct 2016 10:53:13 PM CEST
#
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
import logging
#
# TODO: Add checks for ipip tunnels.
#
class tunnel (moduleBase):
_modinfo = { 'mhelp' : 'create/configure GRE/IPIP/SIT and GRETAP tunnel interfaces',
'attrs' : {
'mode' :
{ 'help' : 'type of tunnel as in \'ip link\' command.',
'validvals' : ['gre', 'gretap', 'ipip', 'sit', 'vti', 'ip6gre', 'ipip6', 'ip6ip6', 'vti6'],
'required' : True,
'example' : ['mode gre']},
'local' :
{ 'help' : 'IP of local tunnel endpoint',
'validvals' : ['<ipv4>', '<ipv6>'],
'required' : True,
'example' : ['local 192.2.0.42']},
'endpoint' :
{ 'help' : 'IP of remote tunnel endpoint',
'validvals' : ['<ipv4>', '<ipv6>'],
'required' : True,
'example' : ['endpoint 192.2.0.23']},
'ttl' :
{ 'help' : 'TTL for tunnel packets',
'validvals' : ['<number>'],
'required' : False,
'example' : ['ttl 64']},
'tunnel-physdev' :
{ 'help' : 'Physical underlay device to use for tunnel packets',
'validvals' : ['<interface>'],
'required' : False,
'example' : ['tunnel-physdev eth1']},
}
}
def __init__ (self, *args, **kargs):
moduleBase.__init__ (self, *args, **kargs)
self.ipcmd = None
def _is_my_interface (self, ifaceobj):
if ifaceobj.addr_method == "tunnel" and ifaceobj.get_attr_value_first ('mode'):
return True
return False
def _has_config_changed (self, attrs_present, attrs_configured):
for attr in set (attrs_present.keys () + attrs_configured.keys ()):
# 'mode' is not present in attrs_configured and checked explicitly
if attr == "mode":
continue
if attrs_present.get (attr, None) != attrs_configured.get (attr, None):
return True
return False
def _up (self, ifaceobj):
attr_map = {
# attr_name -> ip route param name
'local' : 'local',
'endpoint' : 'remote',
'ttl' : 'ttl',
'tunnel-physdev' : 'dev',
}
mode = ifaceobj.get_attr_value_first ('mode')
attrs = {}
attrs_mapped = {}
# Only include attributes which have been set and map ifupdown2 names
# to attribute names expected by iproute
for attr, iproute_attr in attr_map.items ():
attr_val = ifaceobj.get_attr_value_first (attr)
if attr_val != None:
attrs_mapped[iproute_attr] = attr_val
attrs[attr] = attr_val
# Create the tunnel if it doesn't exist yet...
if not self.ipcmd.link_exists(ifaceobj.name):
self.ipcmd.tunnel_create (ifaceobj.name, mode, attrs_mapped)
return
# If it's present, check if there were changes
current_attrs = self.ipcmd.link_get_linkinfo_attrs (ifaceobj.name)
try:
if current_attrs and current_attrs['mode'] != mode or self._has_config_changed (current_attrs, attrs):
# Mode and some other changes are not possible without recreating the interface,
# so just recreate it IFF there have been changes.
self.ipcmd.link_delete (ifaceobj.name)
self.ipcmd.tunnel_create (ifaceobj.name, mode, attrs_mapped)
except Exception, e:
self.log_warn (str (e))
def _down (self, ifaceobj):
if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists (ifaceobj.name):
return
try:
self.ipcmd.link_delete (ifaceobj.name)
except Exception, e:
self.log_warn (str (e))
def get_dependent_ifacenames (self, ifaceobj, ifacenames_all=None):
if not self._is_my_interface (ifaceobj):
return None
device = ifaceobj.get_attr_value_first ('tunnel-physdev')
if device:
return [device]
return None
def _query_check_n_update (self, ifaceobj, ifaceobjcurr, attrname, attrval,
running_attrval):
if not ifaceobj.get_attr_value_first (attrname):
return
if running_attrval and attrval == running_attrval:
ifaceobjcurr.update_config_with_status (attrname, attrval, 0)
else:
ifaceobjcurr.update_config_with_status (attrname, running_attrval, 1)
def _query_check (self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists (ifaceobj.name):
return
tunattrs = self.ipcmd.link_get_linkinfo_attrs (ifaceobj.name)
if not tunattrs:
ifaceobjcurr.check_n_update_config_with_status_many (ifaceobj, self.get_mod_attrs (), -1)
return
for attr in self.get_mod_attrs ():
if not ifaceobj.get_attr_value_first (attr):
continue
# Validate all interface attributes set in the config.
# Remote any leading 'tunnel-' prefix in front of the attr name
# when accessing tunattrs parsed from 'ip -d link'.
self._query_check_n_update (ifaceobj, ifaceobjcurr, attr,
ifaceobj.get_attr_value_first (attr),
tunattrs.get (attr.replace ("tunnel-", "")))
# Operations supported by this addon (yet).
_run_ops = {
'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check
}
def get_ops (self):
return self._run_ops.keys()
def _init_command_handlers (self):
if not self.ipcmd:
self.ipcmd = iproute2 ()
def run (self, ifaceobj, operation, query_ifaceobj = None, **extra_args):
op_handler = self._run_ops.get (operation)
if not op_handler:
return
if operation != 'query-running' and not self._is_my_interface (ifaceobj):
return
self._init_command_handlers ()
if operation == 'query-checkcurr':
op_handler (self, ifaceobj, query_ifaceobj)
else:
op_handler (self, ifaceobj)

View File

@@ -1,308 +0,0 @@
#!/usr/bin/python
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdownaddons.systemutils import systemUtils
from ifupdown.netlink import netlink
from ipaddr import IPv4Address
import ifupdown.ifupdownflags as ifupdownflags
import logging
import ifupdown.policymanager as policymanager
import os
from sets import Set
class vxlan(moduleBase):
_modinfo = {'mhelp' : 'vxlan module configures vxlan interfaces.',
'attrs' : {
'vxlan-id' :
{'help' : 'vxlan id',
'validrange' : ['1', '16777214'],
'required' : True,
'example': ['vxlan-id 100']},
'vxlan-local-tunnelip' :
{'help' : 'vxlan local tunnel ip',
'validvals' : ['<ipv4>'],
'example': ['vxlan-local-tunnelip 172.16.20.103']},
'vxlan-svcnodeip' :
{'help' : 'vxlan id',
'validvals' : ['<ipv4>'],
'example': ['vxlan-svcnodeip 172.16.22.125']},
'vxlan-remoteip' :
{'help' : 'vxlan remote ip',
'validvals' : ['<ipv4>'],
'example': ['vxlan-remoteip 172.16.22.127']},
'vxlan-physdev' :
{'help' : 'vxlan physical device',
'example': ['vxlan-physdev eth1']},
'vxlan-learning' :
{'help' : 'vxlan learning yes/no',
'validvals' : ['yes', 'no', 'on', 'off'],
'example': ['vxlan-learning no'],
'default': 'yes'},
'vxlan-ageing' :
{'help' : 'vxlan aging timer',
'validrange' : ['0', '4096'],
'example': ['vxlan-ageing 300'],
'default': '300'},
'vxlan-purge-remotes' :
{'help' : 'vxlan purge existing remote entries',
'validvals' : ['yes', 'no'],
'example': ['vxlan-purge-remotes yes']}
}}
_clagd_vxlan_anycast_ip = ""
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
purge_remotes = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vxlan-purge-remotes')
if purge_remotes:
self._purge_remotes = utils.get_boolean_from_string(purge_remotes)
else:
self._purge_remotes = False
def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
if self._is_vxlan_device(ifaceobj):
ifaceobj.link_kind |= ifaceLinkKind.VXLAN
elif ifaceobj.name == 'lo':
clagd_vxlan_list = ifaceobj.get_attr_value('clagd-vxlan-anycast-ip')
if clagd_vxlan_list:
if len(clagd_vxlan_list) != 1:
self.log_warn('%s: multiple clagd-vxlan-anycast-ip lines, using first one'
% (ifaceobj.name,))
vxlan._clagd_vxlan_anycast_ip = clagd_vxlan_list[0]
# If we should use a specific underlay device for the VXLAN
# tunnel make sure this device is set up before the VXLAN iface.
physdev = ifaceobj.get_attr_value_first('vxlan-physdev')
if physdev:
return [ physdev ]
return None
def _is_vxlan_device(self, ifaceobj):
if ifaceobj.get_attr_value_first('vxlan-id'):
return True
return False
def _get_purge_remotes(self, ifaceobj):
if not ifaceobj:
return self._purge_remotes
purge_remotes = ifaceobj.get_attr_value_first('vxlan-purge-remotes')
if purge_remotes:
purge_remotes = utils.get_boolean_from_string(purge_remotes)
else:
purge_remotes = self._purge_remotes
return purge_remotes
def _vxlan_create(self, ifaceobj):
vxlanid = ifaceobj.get_attr_value_first('vxlan-id')
if vxlanid:
anycastip = self._clagd_vxlan_anycast_ip
group = ifaceobj.get_attr_value_first('vxlan-svcnodeip')
local = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
physdev = ifaceobj.get_attr_value_first('vxlan-physdev')
ageing = ifaceobj.get_attr_value_first('vxlan-ageing')
learning = utils.get_onoff_bool(ifaceobj.get_attr_value_first('vxlan-learning'))
purge_remotes = self._get_purge_remotes(ifaceobj)
if self.ipcmd.link_exists(ifaceobj.name):
vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name)
# on ifreload do not overwrite anycast_ip to individual ip
# if clagd has modified
if vxlanattrs:
running_localtunnelip = vxlanattrs.get('local')
if (anycastip and running_localtunnelip and
anycastip == running_localtunnelip):
local = running_localtunnelip
netlink.link_add_vxlan(ifaceobj.name, vxlanid,
local=local,
learning=learning,
ageing=ageing,
group=group,
physdev=physdev)
remoteips = ifaceobj.get_attr_value('vxlan-remoteip')
if purge_remotes or remoteips:
# figure out the diff for remotes and do the bridge fdb updates
# only if provisioned by user and not by an vxlan external
# controller.
peers = self.ipcmd.get_vxlan_peers(ifaceobj.name, group)
if local and remoteips and local in remoteips:
remoteips.remove(local)
cur_peers = set(peers)
if remoteips:
new_peers = set(remoteips)
del_list = cur_peers.difference(new_peers)
add_list = new_peers.difference(cur_peers)
else:
del_list = cur_peers
add_list = []
for addr in del_list:
try:
self.ipcmd.bridge_fdb_del(ifaceobj.name,
'00:00:00:00:00:00',
None, True, addr)
except:
pass
for addr in add_list:
try:
self.ipcmd.bridge_fdb_append(ifaceobj.name,
'00:00:00:00:00:00',
None, True, addr)
except:
pass
def _up(self, ifaceobj):
self._vxlan_create(ifaceobj)
def _down(self, ifaceobj):
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check_n_update(self, ifaceobj, ifaceobjcurr, attrname, attrval,
running_attrval):
if not ifaceobj.get_attr_value_first(attrname):
return
if running_attrval and attrval == running_attrval:
ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
else:
ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
def _query_check_n_update_addresses(self, ifaceobjcurr, attrname,
addresses, running_addresses):
if addresses:
for a in addresses:
if a in running_addresses:
ifaceobjcurr.update_config_with_status(attrname, a, 0)
else:
ifaceobjcurr.update_config_with_status(attrname, a, 1)
running_addresses = Set(running_addresses).difference(
Set(addresses))
[ifaceobjcurr.update_config_with_status(attrname, a, 1)
for a in running_addresses]
def _query_check(self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists(ifaceobj.name):
return
# Update vxlan object
vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name)
if not vxlanattrs:
ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
self.get_mod_attrs(), -1)
return
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-id',
ifaceobj.get_attr_value_first('vxlan-id'),
vxlanattrs.get('vxlanid'))
running_attrval = vxlanattrs.get('local')
attrval = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
if running_attrval == self._clagd_vxlan_anycast_ip:
# if local ip is anycast_ip, then let query_check to go through
attrval = self._clagd_vxlan_anycast_ip
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip',
attrval, running_attrval)
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-svcnodeip',
ifaceobj.get_attr_value_first('vxlan-svcnodeip'),
vxlanattrs.get('svcnode'))
purge_remotes = self._get_purge_remotes(ifaceobj)
if purge_remotes or ifaceobj.get_attr_value('vxlan-remoteip'):
# If purge remotes or if vxlan-remoteip's are set
# in the config file, we are owners of the installed
# remote-ip's, lets check and report any remote ips we don't
# understand
self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip',
ifaceobj.get_attr_value('vxlan-remoteip'),
vxlanattrs.get('remote', []))
learning = ifaceobj.get_attr_value_first('vxlan-learning')
if not learning:
learning = 'on'
running_learning = vxlanattrs.get('learning')
if learning == 'yes' and running_learning == 'on':
running_learning = 'yes'
elif learning == 'no' and running_learning == 'off':
running_learning = 'no'
if learning == running_learning:
ifaceobjcurr.update_config_with_status('vxlan-learning',
running_learning, 0)
else:
ifaceobjcurr.update_config_with_status('vxlan-learning',
running_learning, 1)
ageing = ifaceobj.get_attr_value_first('vxlan-ageing')
if not ageing:
ageing = self.get_mod_subattr('vxlan-ageing', 'default')
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-ageing',
ageing, vxlanattrs.get('ageing'))
physdev = ifaceobj.get_attr_value_first('vxlan-physdev')
if physdev:
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-physdev',
physdev, vxlanattrs.get('physdev'))
def _query_running(self, ifaceobjrunning):
vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name)
if not vxlanattrs:
return
attrval = vxlanattrs.get('vxlanid')
if attrval:
ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid'))
else:
# if there is no vxlan id, this is not a vxlan port
return
attrval = vxlanattrs.get('local')
if attrval:
ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval)
attrval = vxlanattrs.get('svcnode')
if attrval:
ifaceobjrunning.update_config('vxlan-svcnode', attrval)
purge_remotes = self._get_purge_remotes(None)
if purge_remotes:
# if purge_remotes is on, it means we own the
# remote ips. Query them and add it to the running config
attrval = vxlanattrs.get('remote')
if attrval:
[ifaceobjrunning.update_config('vxlan-remoteip', a)
for a in attrval]
attrval = vxlanattrs.get('learning')
if attrval and attrval == 'on':
ifaceobjrunning.update_config('vxlan-learning', 'on')
attrval = vxlanattrs.get('ageing')
if attrval:
ifaceobjrunning.update_config('vxlan-ageing', vxlanattrs.get('ageing'))
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check,
'query-running' : _query_running}
def get_ops(self):
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if (operation != 'query-running' and
not self._is_vxlan_device(ifaceobj)):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

View File

@@ -1,8 +0,0 @@
#!/bin/bash
TOPDIR=.
${TOPDIR}/scripts/genmanpages.sh ${TOPDIR}/man.rst ${TOPDIR}/man
python setup.py --command-packages=stdeb.command sdist_dsc bdist_deb

159
debian/changelog vendored
View File

@@ -1,51 +1,144 @@
ifupdown2 (1.1-cl3u10) UNRELEASED; urgency=medium
ifupdown2 (2.0.0) UNRELEASED; urgency=medium
* Package architecture refactoring and cleanups
* Package can be build/install as debian, pip or rpm package
* Makefile to easily perform tasks (i.e.: install, build, test, upload..)
* New. Enabled: traditional bridge support for mstpctl attributes
(portautoedge, portrestrrole)
-- Julien Fortin <julien@cumulusnetworks.com> Thu, 24 May 2018 15:42:42 +0200
ifupdown2 (1.1.18) RELEASED; urgency=medium
* Fix: Link down does not work on SVI configured in a VRF
* Fix: ifreload causes MTU to drop on bridge SVIs
* Fix: addons: addressvirtual: check if SVI name is first in routing table
* Fix: ifreload error on deleting bond slaves from an already configured bond
* Fix: ifupdown2 error is confusing when netmask is specified for vxlan-local-tunnelip
* Fix: ifupdown2 syntax check needed for vxlan interfaces
* Fix: vxlan-ageing default timer doesn't align with bridge-ageing
* Fix: Error with "ifreload -a -n" when MGMT VRF is not Applied
* Fix: using reserved VLAN range reports error but ifreload returns 0
* Fix: unable to set bridge-portmcrouter to "2"
* Fix: vxlan syntax-check warn on missing vxlan-local-tunnelip
* Fix: traditional bridge svi breaks when extra bridge added
* Fix: github #39: addons: vrf: fix vrf slave link kind
* New. Enabled: addons: vxlan: add support for vxlan-port attribute
-- Julien Fortin <julien@cumulusnetworks.com> Thu, 12 Apr 2018 11:10:04 +0200
ifupdown2 (1.1.17) RELEASED; urgency=medium
* Fix: ip[6]-forward attributes not set at boot
-- Julien Fortin <julien@cumulusnetworks.com> Thu, 08 Feb 2018 09:48:37 +0100
ifupdown2 (1.1.16) RELEASED; urgency=medium
* Fix: python exception on macvlans address dump
* Fix: eth0 doesn't acquire DHCP address when mgmt VRF is enabled
-- Julien Fortin <julien@cumulusnetworks.com> Tue, 09 Jan 2018 02:02:58 +0100
ifupdown2 (1.1.15) RELEASED; urgency=medium
* New. Enabled: bridge: add support for bridge-l2protocol-tunnel
* New. Enabled: bridge attributes, when removed reset to default
* New. Enabled: vxlan attributes, when removed reset to default
* New. Enabled: improve handling of optional resources (if missing bridge-utils/ethtool)
* Fix: policy "iface_defaults" not supported for MTU
* Fix: address module: handling of ipv4 & ipv6 (add/remove)
* Fix: warning for vlan reserved range
* Fix: MTU handling on bridge SVIs
-- Julien Fortin <julien@cumulusnetworks.com> Wed, 22 Nov 2017 19:07:43 +0100
ifupdown2 (1.1.14) RELEASED; urgency=medium
* New. Enabled: default policy for bridge MAC address
* Fix: ethtool: don't set link speed and duplex if autoneg is on
-- Julien Fortin <julien@cumulusnetworks.com> Wed, 25 Oct 2017 23:12:27 +0200
ifupdown2 (1.1.13) RELEASED; urgency=medium
* Fix: VRF: ssh session not killed on ifreload
-- Julien Fortin <julien@cumulusnetworks.com> Fri, 15 Sep 2017 22:43:12 +0200
ifupdown2 (1.1.12) RELEASED; urgency=medium
* New. Enabled: mpls-enable attribute
* New. Enabled: bond and bridge module moved to netlink configuration
* New. Enabled: handle a mix of auto and specified vrf table ids
* Fix: igmp attribute reset to defaults when removed from config
-- Julien Fortin <julien@cumulusnetworks.com> Mon, 07 Aug 2017 22:14:03 +0200
ifupdown2 (1.1.11) RELEASED; urgency=medium
* Fix: link-down attribute not applied on slave ports
* Fix: bug that prevented config of mtu below 1280
-- Julien Fortin <julien@cumulusnetworks.com> Thu, 18 May 2017 12:45:21 -0700
ifupdown2 (1.1.10) RELEASED; urgency=medium
* New. Enabled: drop the dependency to pkg_resources, hardcode version number (closes: #855401)
* New. Enabled: adjust allow-hotplug behavior to ifupdown (closes: #855598)
* Closes: CM-8424. bond: adding attribute bond-(up|down)delay
* New. Enabled: bond-lacp-rate support slow/fast argument
* New. Enabled: ifquery --syntax-help: add support for json output
* New. Enabled: vlan: add new attribute 'vlan-protocol'
* New. Enabled: address: add new attribute 'ip6-forward'
* New. Enabled: bridge: add new attribute 'bridge-mcstats'
* New. Enabled: bridge: add new attribute 'bridge-vlan-stats'
* New. Enabled: bridge: add new attribute 'bridge-vlan-protocol'
* New. Enabled: bridge: add new attribute 'bridge-arp-nd-suppress'
* Fix: bond: add attribute bond-(up|down)delay
* Fix: bridge-vids: --syntax-check accepts legacy syntax
-- Julien Fortin <julien@cumulusnetworks.com> Thu, 23 Feb 2017 10:50:14 +0100
-- Julien Fortin <julien@cumulusnetworks.com> Mon, 17 Apr 2017 06:18:04 +0200
ifupdown2 (1.1-cl3u9) RELEASED; urgency=medium
ifupdown2 (1.1.9) RELEASED; urgency=medium
* New. Enabled: support for bridge-learning attribute
-- Cumulus Networks <dev-support@cumulusnetworks.com> Mon, 06 Feb 2017 13:22:51 -0800
-- Julien Fortin <julien@cumulusnetworks.com> Mon, 06 Feb 2017 13:22:51 -0800
ifupdown2 (1.1-cl3u8) RELEASED; urgency=medium
ifupdown2 (1.1.8) RELEASED; urgency=medium
* New. Enabled: update link-speed values: add 25G and 50G
* New. Enabled: new 'link-down' [yes|no] attribute to keep link down
-- dev-support <dev-support@cumulusnetworks.com> Tue, 17 Jan 2017 08:39:29 +0100
-- Julien Fortin <julien@cumulusnetworks.com> Tue, 17 Jan 2017 08:39:29 +0100
ifupdown2 (1.1-cl3u7) RELEASED; urgency=medium
ifupdown2 (1.1.7) RELEASED; urgency=medium
* New. Enabled: fix for inet and inet6 dhcp on the same interface
* New. Enabled: syntax check to warn on common configuration mistakes
* New. Enabled: addons: bridge: disable ip fwding on a bridge with no ip
and no upperifaces
* Closes: CM-13221: fixes for MTU handling
* Closes: CM-13248: dhcpv6 fails if interface doesn't have link-local addr
* Fix: fixes for MTU handling
* Fix: dhcpv6 fails if interface doesn't have link-local addr
-- dev-support <dev-support@cumulusnetworks.com> Wed, 07 Dec 2016 05:48:45 +0100
-- Julien Fortin <julien@cumulusnetworks.com> Wed, 07 Dec 2016 05:48:45 +0100
ifupdown2 (1.1-cl3u6) RELEASED; urgency=medium
ifupdown2 (1.1.6) RELEASED; urgency=medium
* Closes: github #14. add environment variables passed to user scripts
* New. Enabled: addons may provide a list of ifupdown scripts to ignore
-- dev-support <dev-support@cumulusnetworks.com> Mon, 19 Sep 2016 16:37:36 -0700
-- Julien Fortin <julien@cumulusnetworks.com> Mon, 19 Sep 2016 16:37:36 -0700
ifupdown2 (1.1-cl3u5) RELEASED; urgency=medium
ifupdown2 (1.1.5) RELEASED; urgency=medium
* Closes: CM-12798. fix handling of EXISTS errors on address add
* Closes: CM-11214. fix handling of mtu on addressvirtual macvlan devices
* Closes: CM-12884. fix mako namespace handling
* Fix: handling of EXISTS errors on address add
* Fix: handling of mtu on addressvirtual macvlan devices
* Fix: mako namespace handling
-- dev-support <dev-support@cumulusnetworks.com> Fri, 16 Sep 2016 12:48:04 -0700
-- Julien Fortin <julien@cumulusnetworks.com> Fri, 16 Sep 2016 12:48:04 -0700
ifupdown2 (1.1-cl3u4) RELEASED; urgency=medium
ifupdown2 (1.1.4) RELEASED; urgency=medium
* Performance improvements
* New. Enabled: sbin: start-networking: support hotplug class from init script
@@ -53,24 +146,24 @@ ifupdown2 (1.1-cl3u4) RELEASED; urgency=medium
* New. Enabled: extend ifquery support for mstpctl addons
* New. Enabled: each addon may perform semantic and syntax checks by
implementing a custom method
* Closes: CM-11745. Support for address-virtual lines under a vrf slave
* Closes: CM-11718. Defaults for link attributes were not applied
* Closes: CM-11511. Disable IPv6 duplicate address detection on VRR interfaces
* Closes: CM-11485. Fix ifquery to extract vlan-id from iface if not preset
* Closes: CM-8623. Fix for ifquery -c bridge pvid error on a valid config
* Fix: Support for address-virtual lines under a vrf slave
* Fix: Defaults for link attributes were not applied
* Fix: Disable IPv6 duplicate address detection on VRR interfaces
* Fix: ifquery to extract vlan-id from iface if not preset
* Fix: ifquery -c bridge pvid error on a valid config
-- dev-support <dev-support@cumulusnetworks.com> Fri, 29 Jul 2016 08:55:50 -0700
-- Julien Fortin <julien@cumulusnetworks.com> Fri, 29 Jul 2016 08:55:50 -0700
ifupdown2 (1.1-cl3u3) RELEASED; urgency=medium
ifupdown2 (1.1.3) RELEASED; urgency=medium
* Closes: CM-11214. Interface configuration parsing error when keyword vlan
* Fix: Interface configuration parsing error when keyword vlan
is the interface name.
-- dev-support <dev-support@cumulusnetworks.com> Sun, 05 Jun 2016 08:55:50 -0700
-- Julien Fortin <julien@cumulusnetworks.com> Sun, 05 Jun 2016 08:55:50 -0700
ifupdown2 (1.1-cl3u2) RELEASED; urgency=medium
ifupdown2 (1.1.2) RELEASED; urgency=medium
* Closes: CM-10478. checks for invalid address-virtual attributes
* Fix: checks for invalid address-virtual attributes
* New. Deprecated: `mstpctl-stp` attribute
* New. Deprecated: lacp parameters: bond-ad-sys-priority, bond-ad-sys-mac-addr
* New. Enabled: addon module for configuring vrf
@@ -83,10 +176,10 @@ ifupdown2 (1.1-cl3u2) RELEASED; urgency=medium
* New. Enabled: bridge: disabling ipv6 on bridge if any VXLAN port
* New. Enabled: vrf awareness in dhcp addon module
-- dev-support <dev-support@cumulusnetworks.com> Tue, 3 May 2016 14:42:42 -0700
-- Julien Fortin <julien@cumulusnetworks.com> Tue, 3 May 2016 14:42:42 -0700
ifupdown2 (1.1-cl3u1) unstable; urgency=low
ifupdown2 (1.1.0) unstable; urgency=low
* Initial release.
-- dev-support <dev-support@cumulusnetworks.com> Thu, 20 Aug 2015 06:14:24 -0700
-- Roopa Prabhu <roopa@cumulusnetworks.com> Thu, 20 Aug 2015 06:14:24 -0700

4
debian/clean vendored
View File

@@ -1,4 +0,0 @@
man/ifquery.8
man/ifreload.8
man/ifup.8
man/ifupdown-addons-interfaces.5

19
debian/control vendored
View File

@@ -2,18 +2,23 @@ Source: ifupdown2
Section: admin
Priority: optional
Maintainer: Julien Fortin <julien@cumulusnetworks.com>
Build-Depends: debhelper (>=9),
dh-systemd,
dh-python,
python-all,
python-setuptools,
python-docutils
Standards-Version: 3.9.8
Build-Depends: python-setuptools, dh-python, python-all (>= 2.6.6-3), debhelper (>= 9~), python-docutils, dh-systemd
Homepage: https://github.com/CumulusNetworks/ifupdown2
X-Python-Version: >= 2.6
Homepage: https://github.com/cumulusnetworks/ifupdown2
X-Python-Version: >= 2.7
Package: ifupdown2
Architecture: all
Suggests: python-gvgen, python-mako
Replaces: ifupdown
Conflicts: ifupdown
Provides: ifupdown
Depends: ${python:Depends}, ${misc:Depends}, python-argcomplete, python-ipaddr, iproute2, isc-dhcp-client
Conflicts: ifupdown
Replaces: ifupdown
Depends: ${python:Depends}, ${misc:Depends}, iproute2, python-argcomplete, python-ipaddr
Suggests: isc-dhcp-client, bridge-utils, ethtool, python-gvgen, python-mako
Description: Network Interface Management tool similar to ifupdown
ifupdown2 is ifupdown re-written in Python. It replaces ifupdown and provides
the same user interface as ifupdown for network interface configuration.

10
debian/copyright vendored
View File

@@ -1,14 +1,14 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ifupdown2
Upstream-Contact: Roopa Prabhu <roopa@cumulusnetworks.com>, Julien Fortin <julien@cumulusnetworks.com>
Source: http://www.cumulusnetworks.com
Upstream-Contact: Julien Fortin <julien@cumulusnetworks.com>
Source: https://github.com/cumulusnetworks/ifupdown2
Files: *
Copyright: 2014 Cumulus Networks
Copyright: 2014,2015,2016,2017,2018 Cumulus Networks, Inc.
License: GPL-2
Files: debian/*
Copyright: 2014 Cumulus Networks
Copyright: 2014,2015,2016,2017,2018 Cumulus Networks, Inc.
License: GPL-2
License: GPL-2
@@ -25,4 +25,4 @@ License: GPL-2
along with this program. If not, see <http://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".

View File

@@ -1 +1 @@
completion/ifup
ifupdown2/completion/ifup

View File

@@ -1,3 +1,4 @@
/etc/network/interfaces.d/
/var/lib/ifupdown2/policy.d/
/var/lib/ifupdown2/hooks/
etc/network/interfaces.d/
etc/network/ifupdown2/policy.d/
var/lib/ifupdown2/hooks/
var/lib/ifupdown2/policy.d/

View File

@@ -1,3 +1,3 @@
sbin/ifupdown2 /usr/share/ifupdown2/
sbin/start-networking /usr/share/ifupdown2/sbin/
debian/networking /etc/default/
etc/default/networking /etc/default/
etc/network/ifupdown2/addons.conf /etc/network/ifupdown2/
etc/network/ifupdown2/ifupdown2.conf /etc/network/ifupdown2/

View File

@@ -1,6 +1,5 @@
usr/share/ifupdown2/__main__.py usr/share/ifupdown2/ifupdown2
usr/share/ifupdown2/ifupdown2 sbin/ifup
usr/share/ifupdown2/ifupdown2 sbin/ifdown
usr/share/ifupdown2/ifupdown2 sbin/ifquery
usr/share/ifupdown2/ifupdown2 sbin/ifreload
usr/share/man/man8/ifup.8.gz usr/share/man/man8/ifdown.8.gz

View File

@@ -1,4 +1,5 @@
man/ifup.8
man/ifdown.8
man/ifquery.8
man/ifreload.8
man/ifupdown-addons-interfaces.5

View File

@@ -1,6 +1,9 @@
[Unit]
Description=ifupdown2 networking initialization
Documentation=man:interfaces(5) man:ifup(8) man:ifdown(8)
DefaultDependencies=no
Before=shutdown.target
Conflicts=shutdown.target
[Service]
Type=oneshot
@@ -12,4 +15,4 @@ ExecStop=/usr/share/ifupdown2/sbin/start-networking stop
ExecReload=/usr/share/ifupdown2/sbin/start-networking reload
[Install]
WantedBy=basic.target network.target
WantedBy=basic.target network.target shutdown.target

View File

@@ -1,21 +1,49 @@
#!/bin/sh
# postinst script for ifupdown2
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
MYNAME="${0##*/}"
report() { echo "${MYNAME}: $*" ; }
report_warn() { report "Warning: $*" >&2 ; }
report_err() { report "Error: $*" >&2 ; }
fix_dhclient_file_with_space()
{
# because of a typo an older ifupdown2 version was creating lease file
# with trailing space. In case we still have users with such files we
# need to strip that trailing whitespace.
for filename in `find /var/lib/dhcp/ -name "dhclient.*.leases "`
do
if [ -f "$filename " ];
then
interface_name=`echo $filename | cut -d'.' -f2,3,4,5`
mv "$filename " /var/lib/dhcp/dhclient6.$interface_name
fi
done
}
process_etc_network_interfaces()
{
# Generic stuff done on all configurations
if [ -f /etc/network/interfaces ] ; then
if ! grep -q -E "^[[:space:]]*iface[[:space:]]+l[o0]([[:space:]]+inet([[:space:]]+loopback)?)?[[:space:]]*$" /etc/network/interfaces ; then
report_warn "No 'iface lo' definition found in /etc/network/interfaces"
fi
if ! grep -q "^[[:space:]]*\(allow-\|\)auto[[:space:]]\+\(.*[[:space:]]\+\|\)lo0\?\([[:space:]]\+\|$\)" /etc/network/interfaces ; then
report_warn "No 'auto lo' statement found in /etc/network/interfaces"
fi
else # ! -f /etc/network/interfaces
if [ -z "$2" ]; then
echo "Creating /etc/network/interfaces."
echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
echo "auto lo" >> /etc/network/interfaces
echo "iface lo inet loopback" >> /etc/network/interfaces
else
report_warn "/etc/network/interfaces does not exist"
fi
fi
}
process_udev()
{
@@ -35,52 +63,24 @@ process_udev()
fi
}
MYNAME="${0##*/}"
report() { echo "${MYNAME}: $*" ; }
report_warn() { report "Warning: $*" >&2 ; }
report_err() { report "Error: $*" >&2 ; }
case "$1" in
configure)
# work around to rename the existing dhclient6 lease file containing a space
for filename in `find /var/lib/dhcp/ -name "dhclient.*.leases "`
do
if [ -f "$filename " ];
then
interface_name=`echo $filename | cut -d'.' -f2,3,4,5`
mv "$filename " /var/lib/dhcp/dhclient6.$interface_name
fi
done
# Generic stuff done on all configurations
if [ -f /etc/network/interfaces ] ; then
if ! grep -q -E "^[[:space:]]*iface[[:space:]]+l[o0]([[:space:]]+inet([[:space:]]+loopback)?)?[[:space:]]*$" /etc/network/interfaces ; then
report_warn "No 'iface lo' definition found in /etc/network/interfaces"
fi
if ! grep -q "^[[:space:]]*\(allow-\|\)auto[[:space:]]\+\(.*[[:space:]]\+\|\)lo0\?\([[:space:]]\+\|$\)" /etc/network/interfaces ; then
report_warn "No 'auto lo' statement found in /etc/network/interfaces"
fi
else # ! -f /etc/network/interfaces
if [ -z "$2" ]; then
echo "Creating /etc/network/interfaces."
echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
echo "auto lo" >> /etc/network/interfaces
echo "iface lo inet loopback" >> /etc/network/interfaces
else
report_warn "/etc/network/interfaces does not exist"
fi
fi
fix_dhclient_file_with_space
process_etc_network_interfaces
process_udev
;;
chmod +x /usr/share/ifupdown2/__main__.py
;;
purge)
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

View File

@@ -1,91 +1,45 @@
#!/bin/sh
# postrm script for ifupdown2
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
MYNAME="${0##*/}"
report() { echo "${MYNAME}: $*" ; }
report_warn() { report "Warning: $*" >&2 ; }
report_err() { report "Error: $*" >&2 ; }
process_state_file()
{
rm -f /run/network/ifstatenew
}
process_udev()
{
if [ -e /etc/udev/rules.d/80-networking.rules ]; then
udevlink=$(readlink /etc/udev/rules.d/80-networking.rules 2>/dev/null || true)
[ -n "$udevlink" -a "$udevlink" = "/dev/null" ] && rm -f /etc/udev/rules.d/80-networking.rules
udevlink=$(readlink /etc/udev/rules.d/80-networking.rules 2>/dev/null || true)
[ -n "$udevlink" -a "$udevlink" = "/dev/null" ] && rm -f /etc/udev/rules.d/80-networking.rules
fi
if [ -e /etc/udev/rules.d/60-bridge-network-interface.rules ]; then
udevlink=$(readlink /etc/udev/rules.d/60-bridge-network-interface.rules 2>/dev/null || true)
[ -n "$udevlink" -a "$udevlink" = "/dev/null" ] && rm -f /etc/udev/rules.d/60-bridge-network-interface.rules
udevlink=$(readlink /etc/udev/rules.d/60-bridge-network-interface.rules 2>/dev/null || true)
[ -n "$udevlink" -a "$udevlink" = "/dev/null" ] && rm -f /etc/udev/rules.d/60-bridge-network-interface.rules
fi
}
postrm_remove()
{
process_udev
}
# Note: We don't remove /etc/network/interfaces
postrm_purge()
{
rm -f /run/network/ifstatenew
}
# restore file if we diverted it on install/upgrade
_postrm_divert()
{
diversions=$(dpkg-divert --list | grep "$1" | grep 'by ifupdown2$' | wc -l 2> /dev/null)
if [ $diversions -gt 0 ] ;
then
dpkg-divert --remove --package ifupdown2 --rename $1
fi
}
postrm_divert()
{
for filename in ifup ifdown ifquery ifreload
do
_postrm_divert "/usr/share/bash-completion/completions/$filename"
_postrm_divert "/etc/bash_completion.d/$filename"
done
}
case "$1" in
purge)
postrm_purge
;;
remove)
postrm_remove
postrm_divert
;;
abort-install|disappear|failed-upgrade|abort-upgrade)
postrm_divert
purge|remove|abort-install|disappear)
process_state_file
process_udev
;;
upgrade)
;;
upgrade|failed-upgrade|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#

View File

@@ -1,39 +0,0 @@
#! /bin/sh
MYNAME="${0##*/}"
report() { echo "${MYNAME}: $*" ; }
report_err() { report "Error: $*" >&2 ; }
preinst_divert()
{
diversions=$(dpkg-divert --list | grep "$1" | grep -v 'by ifupdown2$' | wc -l 2> /dev/null)
if [ $diversions -gt 0 ] ;
then
report_err "existing diversion for $1"
else
if [ -f $1 ];
then
dpkg-divert --add --package ifupdown2 --rename --divert "$1.disabled" "$1"
fi
fi
}
set -e
case "$1" in
install|upgrade)
for filename in ifup ifdown ifquery ifreload
do
preinst_divert "/usr/share/bash-completion/completions/$filename"
preinst_divert "/etc/bash_completion.d/$filename"
done
# workaround 3.0.0 internal install error. This can be removed in a
# few weeks.
if [ -f /etc/default/networking/networking.default ]; then
dpkg-maintscript-helper rm_conffile /etc/default/networking/networking.default 1.1 -- $@
rm -rf /etc/default/networking
fi
;;
esac
#DEBHELPER#

23
debian/networking vendored
View File

@@ -1,23 +0,0 @@
#
#
# Parameters for the networking service
#
#
# Change the below to yes if you want verbose logging to be enabled
VERBOSE="no"
# Change the below to yes if you want debug logging to be enabled
DEBUG="no"
# Change the below to yes if you want logging to go to syslog
SYSLOG="no"
# Exclude interfaces
EXCLUDE_INTERFACES=
# Set to 'yes' if you want to skip ifdown during system reboot
# and shutdown. This is of interest in large scale interface
# deployments where you dont want to wait for interface
# deconfiguration to speed up shutdown/reboot
SKIP_DOWN_AT_SYSRESET="yes"

View File

@@ -1,114 +0,0 @@
#!/bin/sh
# postinst script for ifupdown2
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
process_udev()
{
# override default udev bridge and hotplug rules because they interfere with
# networking init script
udev_user_rulesdir=/etc/udev/rules.d/
udev_sys_rulesdir=/lib/udev/rules.d/
if [ -e $udev_user_rulesdir ]; then
udev_ifupdown2_overrides="80-networking.rules
60-bridge-network-interface.rules"
for u in ${udev_ifupdown2_overrides}
do
if [ -e ${udev_sys_rulesdir}/$u -a ! -e ${udev_user_rulesdir}/$u ]; then
(cd ${udev_user_rulesdir} && ln -sf /dev/null $u)
fi
done
fi
}
MYNAME="${0##*/}"
report() { echo "${MYNAME}: $*" ; }
report_warn() { report "Warning: $*" >&2 ; }
report_err() { report "Error: $*" >&2 ; }
case "$1" in
configure)
# Create /etc/network/run
[ -d /run/network ] || mkdir -p /run/network
# for backward compatibility
if [ ! -f /etc/network/run ]; then
ln -sf /run/network /etc/network/run
fi
ln -sf /usr/share/python-ifupdown2/generate_interfaces.py \
/usr/share/doc/python-ifupdown2/examples/generate_interfaces.py
[ -d /etc/network/if-pre-up.d ] || mkdir -p /etc/network/if-pre-up.d
[ -d /etc/network/if-up.d ] || mkdir -p /etc/network/if-up.d
[ -d /etc/network/if-post-up.d ] || mkdir -p /etc/network/if-post-up.d
[ -d /etc/network/if-pre-down.d ] || mkdir -p /etc/network/if-pre-down.d
[ -d /etc/network/if-down.d ] || mkdir -p /etc/network/if-down.d
[ -d /etc/network/if-post-down.d ] || mkdir -p /etc/network/if-post-down.d
# Generic stuff done on all configurations
if [ -f /etc/network/interfaces ] ; then
# TODO: This should be handled with debconf and the script
# could introduce the line there directly
if ! grep -q "^[[:space:]]*iface[[:space:]]\+lo0\?[[:space:]]\+inet[[:space:]]\+loopback\>" /etc/network/interfaces ; then
report_warn "No 'iface lo' definition found in /etc/network/interfaces"
fi
if ! grep -q "^[[:space:]]*\(allow-\|\)auto[[:space:]]\+\(.*[[:space:]]\+\|\)lo0\?\([[:space:]]\+\|$\)" /etc/network/interfaces ; then
report_warn "No 'auto lo' statement found in /etc/network/interfaces"
fi
else # ! -f /etc/network/interfaces
if [ -z "$2" ]; then
echo "Creating /etc/network/interfaces."
echo "# interfaces(5) file used by ifup(8) and ifdown(8)" > /etc/network/interfaces
echo "auto lo" >> /etc/network/interfaces
echo "iface lo inet loopback" >> /etc/network/interfaces
else
report_warn "/etc/network/interfaces does not exist"
fi
fi
[ -e /sbin/ifup ] || ln -sf /sbin/ifupdown /sbin/ifup
[ -e /sbin/ifdown ] || ln -sf /sbin/ifupdown /sbin/ifdown
[ -e /sbin/ifquery ] || ln -sf /sbin/ifupdown /sbin/ifquery
[ -e /sbin/ifreload ] || ln -sf /sbin/ifupdown /sbin/ifreload
(cd /usr/share/man/man8/ && ln -sf /usr/share/man/man8/ifup.8.gz ifdown.8.gz)
mkdir -p /etc/network/interfaces.d/
process_udev
update-rc.d networking start 40 S . start 35 0 6 . >/dev/null
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@@ -1,71 +0,0 @@
#!/bin/sh
# postrm script for ifupdown2
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
process_udev()
{
udevlink=$(readlink /etc/udev/rules.d/80-networking.rules 2>/dev/null || true)
[ -n "$udevlink" -a "$udevlink" == "/dev/null" ] && rm -f /etc/udev/rules.d/80-networking.rules
udevlink=$(readlink /etc/udev/rules.d/60-bridge-network-interface.rules 2>/dev/null || true)
[ -n "$udevlink" -a "$udevlink" == "/dev/null" ] && rm -f /etc/udev/rules.d/60-bridge-network-interface.rules
}
postrm_remove()
{
rm -f /sbin/ifup /sbin/ifdown /sbin/ifquery
process_udev
update-rc.d networking remove >/dev/null
}
# Note: We don't remove /etc/network/interfaces
postrm_purge()
{
rm -f /var/tmp/network/ifstatenew
if [ -L /etc/network/run ] ; then
rm -f /etc/network/run
elif [ -d /etc/network/run ] ; then
rmdir --ignore-fail-on-non-empty /etc/network/run
fi
}
case "$1" in
purge)
postrm_purge
;;
remove)
postrm_remove
;;
upgrade|disappear|failed-upgrade|abort-install|abort-upgrade)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@@ -1,56 +0,0 @@
#!/bin/sh
# preinst script for newpkg
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
preinst_upgrade()
{
local oldver="$1"
local udev_user_rulesdir="/etc/udev/rules.d"
# we have to fixup the filesystem here as previous packages of
# ifupdown2 introduced a bug in the postrm script that require
# these files to exist, otherwise the postrm script will always
# fail.
local badver="0.1-cl2.5+2"
if dpkg --compare-versions "${oldver}" "lt" "${badver}"; then
local files="${udev_user_rulesdir}/80-networking.rules
${udev_user_rulesdir}/60-bridge-network-interface.rules"
for f in ${files}; do
echo "touching udev rule: ${f}"
test ! -e "${f}" && ln -s /dev/null "${f}" || \
/bin/echo -e "\tudev rule exists leaving"
done
fi
}
case "$1" in
install|upgrade)
preinst_upgrade "$2"
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

4
debian/rules vendored
View File

@@ -2,13 +2,13 @@
#export DH_VERBOSE=1
export PYBUILD_NAME=ifupdown2
export PYBUILD_INSTALL_ARGS=--install-lib=/usr/share/ifupdown2 --install-scripts=/usr/share/ifupdown2
export PYBUILD_INSTALL_ARGS=--install-lib=/usr/share/ --install-scripts=/usr/share/
%:
dh $@ --with python2 --with systemd --buildsystem=pybuild
override_dh_installman:
./scripts/genmanpages.sh ./man.rst ./man
./ifupdown2/man/genmanpages.sh ./ifupdown2/man ./man
dh_installman
override_dh_systemd_start:

View File

@@ -1 +1 @@
3.0 (git)
3.0 (native)

1
debian/watch vendored Normal file
View File

@@ -0,0 +1 @@
version=3

View File

@@ -1,49 +0,0 @@
#!/usr/bin/env bash
echo "Installing batman-adv module on debian/ubuntu"
echo ""
echo "Batman is a Layer2-Mesh protocol which uses Ethernet devices (like eth*,
vlans, etc.) to communicate with peers and provides access to the L2-mesh via
a batX interface. You can only create a batman instance if at least one batman-
-iface (read: an interface where the mesh protocol is spoken on) is present and
added to the batman-mesh-instance."
echo "More info: https://en.wikipedia.org/wiki/B.A.T.M.A.N."
echo ""
echo "installing batctl: apt-get install batctl"
apt-get install batctl
echo ""
echo ""
echo "loading batman-adv module: modprobe batman-adv"
modprobe batman-adv
echo ""
echo "usefull commands:
$ batctl if add \$IFACE
$ batctl -m bat0 if add \$IFACE"
echo "please read: man batctl"
echo ""
echo ""
echo "configuration example:
$ cat /etc/network/interfaces
auto bat0
iface bat0
batman-ifaces \$IFACE [\$IFACES...]
batman-ifaces-ignore-regex .*_nodes
batman-hop-penalty 23
address 192.0.2.42/24
$
$
$ ifreload -a
$ ifquery -a -c
auto bat0
iface bat0 [pass]
batman-ifaces tap0 tap1 [pass]
batman-ifaces-ignore-regex .*_nodes [pass]
batman-hop-penalty 23 [pass]
address 192.0.2.42/24 [pass]
$"

View File

@@ -1,12 +0,0 @@
auto eth0
iface eth0 inet dhcp
auto lo
iface lo inet
auto bat0
iface bat0
batman-ifaces tap0 tap1
batman-ifaces-ignore-regex .*_nodes
batman-hop-penalty 23
address 192.0.2.42/24

View File

@@ -3,10 +3,7 @@
import argparse
import sys
import subprocess
<<<<<<< HEAD
=======
import os
>>>>>>> cumulus/dev
""" This script prints to stdout /etc/network/interfaces entries for
requested interfaces.
@@ -34,21 +31,6 @@ import os
"""
<<<<<<< HEAD
def get_swp_interfaces():
porttab_path = '/var/lib/cumulus/porttab'
ports = []
ptfile = open(porttab_path, 'r')
for line in ptfile.readlines():
line = line.strip()
if '#' in line:
continue
try:
ports.append(line.split()[0])
except ValueError:
continue
=======
def get_pci_interfaces():
ports = []
FNULL = open(os.devnull, 'w')
@@ -90,12 +72,11 @@ def get_swp_interfaces():
if not ports:
print 'Error: No ports found in %s' % porttab_path
exit(1)
>>>>>>> cumulus/dev
return ports
def print_swp_defaults_header():
print '''
# ** This file is autogenerated by /usr/share/doc/python-ifupdown2/generate_interfaces.py **
# ** This file is autogenerated by /usr/share/doc/ifupdown2/generate_interfaces.py **
#
# This is /etc/network/interfaces section for all available swp
# ports on the system.
@@ -112,7 +93,7 @@ def print_swp_defaults_header():
def print_bridge_untagged_defaults_header():
print '''
# ** This file is autogenerated by /usr/share/doc/python-ifupdown2/generate_interfaces.py **
# ** This file is autogenerated by /usr/share/doc/ifupdown2/generate_interfaces.py **
#
# This is /etc/network/interfaces section for a bridge device with all swp
# ports in the system.
@@ -186,12 +167,6 @@ if args.bridgedefault and args.mergefile:
exit(1)
swp_intfs = get_swp_interfaces()
<<<<<<< HEAD
if not swp_intfs:
print 'error: no ports found'
exit(1)
=======
>>>>>>> cumulus/dev
if args.swpdefaults:
interfaces_print_swp_defaults(swp_intfs)

View File

@@ -4,13 +4,13 @@
# uplink1, peerlink and downlink are bond interfaces.
# 'bridge' is a vlan aware bridge with ports uplink1, peerlink
# and downlink (swp2-20).
#
#
# native vlan is by default 1
#
# 'bridge-vids' attribute is used to declare vlans.
# 'bridge-pvid' attribute is used to specify native vlans if other than 1
# 'bridge-access' attribute is used to declare access port
#
#
auto lo
iface lo

View File

@@ -7,13 +7,13 @@
#
# All ports inherit 'vlans 10 20-23' from the 'bridge-vids' attribute
# under the bridge
#
#
# native vlan is by default 1
#
# 'bridge-vids' attribute is used to declare vlans.
# 'bridge-pvid' attribute is used to specify native vlans if other than 1
# 'bridge-access' attribute is used to declare access port
#
#
# 'spine-bond host-bond-0[1-2]' are clag bonds and will be considered by
# clagd for dual connection. clag-id has to be a non-zero and has to match
# across the peer switches for the bonds to become dual connected.

View File

@@ -32,21 +32,12 @@ ethtool
.. autoclass:: ethtool
<<<<<<< HEAD
ifenslave
=========
.. automodule:: ifenslave
.. autoclass:: ifenslave
=======
bond
====
.. automodule:: bond
.. autoclass:: bond
>>>>>>> cumulus/dev
mstpctl
=======

View File

@@ -5,36 +5,14 @@ This package contains modules that provide helper methods
for ifupdown2 addon modules to interact directly with tools
like iproute2, brctl etc.
bridgeutils
LinkUtils
===========
Helper module to work with bridgeutil commands
Helper module to work with brctl, bonds, iproute2, mstpctl commands
.. automodule:: bridgeutils
.. automodule:: LinkUtils
.. autoclass:: brctl
<<<<<<< HEAD
ifenslaveutil
=============
=======
bondutil
========
>>>>>>> cumulus/dev
Helper module to interact with linux api to create bonds.
Currently this is via sysfs.
<<<<<<< HEAD
.. automodule:: ifenslaveutil
.. autoclass:: ifenslaveutil
=======
.. automodule:: bondutil
.. autoclass:: bondutil
>>>>>>> cumulus/dev
.. autoclass:: LinkUtils
dhclient
========
@@ -44,12 +22,3 @@ Helper module to interact with dhclient tools.
.. automodule:: dhclient
.. autoclass:: dhclient
iproute2
========
Helper module to interact with iproute2 tools.
.. automodule:: iproute2
.. autoclass:: iproute2

View File

@@ -10,7 +10,7 @@ Keep the following points in mind before you start configuring interfaces using
``ifupdown2``:
* IPv4 and IPv6 addresses for an interface can be listed in the same ``iface``
section. For examples, see ``/usr/share/doc/python-ifupdown2/examples/``.
section. For examples, see ``/usr/share/doc/ifupdown2/examples/``.
* Do not use a legacy interface alias. They are only supported for backward
compatibility with ``ifupdown``. They do get configured, but ``ifquery`` has
@@ -66,11 +66,7 @@ Man Pages
Configuration Files
===================
<<<<<<< HEAD
* /etc/network/interfaces
=======
* config file defined in ifupdown2.conf (default /etc/network/interfaces)
>>>>>>> cumulus/dev
ifupdown Built-in Interfaces
@@ -113,11 +109,7 @@ following example configuration::
bond-slaves swp29 swp30
bond-mode 802.3ad
bond-miimon 100
<<<<<<< HEAD
bond-use-carrier 1
=======
bond-use-carrier yes
>>>>>>> cumulus/dev
bond-lacp-rate 1
bond-min-links 1
bond-xmit-hash-policy layer3+4
@@ -128,11 +120,7 @@ following example configuration::
bond-slaves swp31 swp32
bond-mode 802.3ad
bond-miimon 100
<<<<<<< HEAD
bond-use-carrier 1
=======
bond-use-carrier yes
>>>>>>> cumulus/dev
bond-lacp-rate 1
bond-min-links 1
bond-xmit-hash-policy layer3+4
@@ -310,11 +298,7 @@ The contents of the sourced file used above are::
bond-slaves swp25 swp26
bond-mode 802.3ad
bond-miimon 100
<<<<<<< HEAD
bond-use-carrier 1
=======
bond-use-carrier yes
>>>>>>> cumulus/dev
bond-lacp-rate 1
bond-min-links 1
bond-xmit-hash-policy layer3+4
@@ -333,13 +317,10 @@ bridge ports and bond slaves::
iface br1
bridge-ports glob swp7-9.100 swp11.100 glob swp15-18.100
<<<<<<< HEAD
=======
auto br2
iface br2
bridge-ports glob swp[1-6]s[0-3].100
>>>>>>> cumulus/dev
Using Templates
===============
@@ -382,11 +363,7 @@ file, run::
bond-slaves swp25 swp26
bond-mode 802.3ad
bond-miimon 100
<<<<<<< HEAD
bond-use-carrier 1
=======
bond-use-carrier yes
>>>>>>> cumulus/dev
bond-lacp-rate 1
bond-min-links 1
bond-xmit-hash-policy layer3+4
@@ -402,11 +379,7 @@ does not match::
iface bond0
bond-mode 802.3ad (✓)
bond-miimon 100 (✓)
<<<<<<< HEAD
bond-use-carrier 1 (✓)
=======
bond-use-carrier yes (✓)
>>>>>>> cumulus/dev
bond-lacp-rate 1 (✓)
bond-min-links 1 (✓)
bond-xmit-hash-policy layer3+4 (✓)
@@ -444,17 +417,10 @@ the ``interfaces`` file. For complete syntax on the ``interfaces`` file, see
{
"auto": true,
"config": {
<<<<<<< HEAD
"bond-use-carrier": "1",
"bond-xmit-hash-policy": "layer3+4",
"bond-miimon": "100",
"bond-lacp-rate": "1",
=======
"bond-use-carrier": "yes",
"bond-xmit-hash-policy": "layer3+4",
"bond-miimon": "100",
"bond-lacp-rate": "1",
>>>>>>> cumulus/dev
"bond-min-links": "1",
"bond-slaves": "swp25 swp26",
"bond-mode": "802.3ad",

View File

@@ -9,7 +9,6 @@
# Description: Prepare /run/network directory, ifstate file and raise network interfaces, or take them down.
### END INIT INFO
PATH="/sbin:/bin"
RUN_DIR="/run/network"
IFSTATE_LOCKFILE="${RUN_DIR}/ifstatelock"
@@ -36,13 +35,13 @@ EXTRA_ARGS=
gen_examples() {
# Generate sample interfaces file. The interfaces files are
# generated under /usr/share/doc/python-ifupdown2/examples/
# generated under /usr/share/doc/ifupdown2/examples/
#
# generate files only at boot
[ -f ${IFSTATE_LOCKFILE} ] && return
python_ifupdown2_docdir="/usr/share/doc/python-ifupdown2"
python_ifupdown2_docdir="/usr/share/doc/ifupdown2"
swpfile=${python_ifupdown2_docdir}"/examples/swp_defaults"
bridgedefaultfile=${python_ifupdown2_docdir}"/examples/bridge_untagged_default"
interfaces_gen_script=${python_ifupdown2_docdir}"/examples/generate_interfaces.py"
@@ -147,7 +146,7 @@ start)
exclusions=$(process_exclusions)
perfoptions=$(perf_options)
log_action_begin_msg "Configuring network interfaces"
ifup -a $EXTRA_ARGS $exclusions $perfoptions
ifup -a $EXTRA_ARGS $exclusions $perfoptions
log_action_end_msg $?
;;

View File

@@ -1,8 +1,5 @@
pre-up,link
pre-up,tunnel
pre-up,ppp
pre-up,bond
pre-up,batman_adv
pre-up,vlan
pre-up,vxlan
pre-up,clagd
@@ -11,16 +8,16 @@ pre-up,bridge
pre-up,bridgevlan
pre-up,mstpctl
pre-up,vrf
pre-up,ethtool
up,dhcp
up,address
up,addressvirtual
up,usercmds
post-up,ethtool
post-up,usercmds
post-up,clagd
post-up,vxrd
pre-down,usercmds
pre-down,ethtool
pre-down,usercmds
pre-down,vxrd
pre-down,dhcp
down,addressvirtual
@@ -34,8 +31,5 @@ post-down,bridge
post-down,vxlan
post-down,vlan
post-down,bond
post-down,batman_adv
post-down,usercmds
post-down,link
post-down,tunnel
post-down,ppp

View File

@@ -29,7 +29,7 @@ disable_cli_interfacesfile=0
# are used. But when a mix of scripts and modules are used (which is the
# default case), you may get false warnings for attributes supported
# by scripts
addon_syntax_check=0
addon_syntax_check=1
# Support executing of ifupdown style scripts.
# Note that by default python addon modules override scripts with the same

View File

@@ -1,5 +0,0 @@
""" ifupdown2 package.
.. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
"""

View File

@@ -1,26 +0,0 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# ifupdown --
# exceptions
#
class Error(Exception):
"""Base class for exceptions in ifupdown"""
pass
class ifaceNotFoundError(Error):
pass
class invalidValueError(Error):
pass
class errorReadingStateError(Error):
pass
class moduleNotSupported(Error):
pass

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
#
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
#
class ifupdownConfig():
def __init__(self):
self.conf = {}
config = ifupdownConfig()

View File

@@ -1,155 +0,0 @@
#!/usr/bin/python
#
# Copyright 2016 Cumulus Networks, Inc. All rights reserved.
# Author: Julien Fortin, julien@cumulusnetworks.com
#
try:
from ifupdownaddons.utilsbase import utilsBase
import ifupdown.ifupdownflags as ifupdownflags
except ImportError, e:
raise ImportError(str(e) + "- required module not found")
class Netlink(utilsBase):
VXLAN_UDP_PORT = 4789
def __init__(self, *args, **kargs):
utilsBase.__init__(self, *args, **kargs)
try:
import sys
sys.path.insert(0, '/usr/share/ifupdown2/')
from nlmanager.nlmanager import NetlinkManager
# this should force the use of the local nlmanager
self._nlmanager_api = NetlinkManager(extra_debug=False)
except Exception as e:
self.logger.error('cannot initialize ifupdown2\'s '
'netlink manager: %s' % str(e))
raise
def get_iface_index(self, ifacename):
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.get_iface_index(ifacename)
except Exception as e:
raise Exception('%s: netlink: %s: cannot get ifindex: %s'
% (ifacename, ifacename, str(e)))
def link_add_vlan(self, vlanrawdevice, ifacename, vlanid):
self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s'
% (ifacename, vlanrawdevice, ifacename, vlanid))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(vlanrawdevice)
try:
return self._nlmanager_api.link_add_vlan(ifindex, ifacename, vlanid)
except Exception as e:
raise Exception('netlink: %s: cannot create vlan %s: %s'
% (vlanrawdevice, vlanid, str(e)))
def link_add_macvlan(self, ifacename, macvlan_ifacename):
self.logger.info('%s: netlink: ip link add link %s name %s type macvlan mode private'
% (ifacename, ifacename, macvlan_ifacename))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(ifacename)
try:
return self._nlmanager_api.link_add_macvlan(ifindex, macvlan_ifacename)
except Exception as e:
raise Exception('netlink: %s: cannot create macvlan %s: %s'
% (ifacename, macvlan_ifacename, str(e)))
def link_set_updown(self, ifacename, state):
self.logger.info('%s: netlink: ip link set dev %s %s'
% (ifacename, ifacename, state))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_set_updown(ifacename, state)
except Exception as e:
raise Exception('netlink: cannot set link %s %s: %s'
% (ifacename, state, str(e)))
def link_set_protodown(self, ifacename, state):
self.logger.info('%s: netlink: set link %s protodown %s'
% (ifacename, ifacename, state))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_set_protodown(ifacename, state)
except Exception as e:
raise Exception('netlink: cannot set link %s protodown %s: %s'
% (ifacename, state, str(e)))
def link_set_master(self, ifacename, master_dev, state=None):
self.logger.info('%s: netlink: ip link set dev %s master %s %s'
% (ifacename, ifacename, master_dev,
state if state else ''))
if ifupdownflags.flags.DRYRUN: return
try:
master = 0 if not master_dev else self.get_iface_index(master_dev)
return self._nlmanager_api.link_set_master(ifacename, master,
state=state)
except Exception as e:
raise Exception('netlink: %s: cannot set %s master %s: %s'
% (ifacename, ifacename, master_dev, str(e)))
def link_set_nomaster(self, ifacename, state=None):
self.logger.info('%s: netlink: ip link set dev %s nomaster %s'
% (ifacename, ifacename, state if state else ''))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_set_master(ifacename, 0,
state=state)
except Exception as e:
raise Exception('netlink: %s: cannot set %s nomaster: %s'
% (ifacename, ifacename, str(e)))
def link_add_bridge_vlan(self, ifacename, vlanid):
self.logger.info('%s: netlink: bridge vlan add vid %s dev %s'
% (ifacename, vlanid, ifacename))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(ifacename)
try:
return self._nlmanager_api.link_add_bridge_vlan(ifindex, vlanid)
except Exception as e:
raise Exception('netlink: %s: cannot create bridge vlan %s: %s'
% (ifacename, vlanid, str(e)))
def link_del_bridge_vlan(self, ifacename, vlanid):
self.logger.info('%s: netlink: bridge vlan del vid %s dev %s'
% (ifacename, vlanid, ifacename))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(ifacename)
try:
return self._nlmanager_api.link_del_bridge_vlan(ifindex, vlanid)
except Exception as e:
raise Exception('netlink: %s: cannot remove bridge vlan %s: %s'
% (ifacename, vlanid, str(e)))
def link_add_vxlan(self, ifacename, vxlanid, local=None, dstport=VXLAN_UDP_PORT,
group=None, learning='on', ageing=None, physdev=None):
cmd = 'ip link add %s type vxlan id %s dstport %s' % (ifacename,
vxlanid,
dstport)
cmd += ' local %s' % local if local else ''
cmd += ' ageing %s' % ageing if ageing else ''
cmd += ' remote %s' % group if group else ' noremote'
cmd += ' nolearning' if learning == 'off' else ''
cmd += ' dev %s' % physdev if physdev else ''
self.logger.info('%s: netlink: %s' % (ifacename, cmd))
if ifupdownflags.flags.DRYRUN: return
try:
if physdev:
physdev = self.get_iface_index (physdev)
return self._nlmanager_api.link_add_vxlan(ifacename,
vxlanid,
dstport=dstport,
local=local,
group=group,
learning=learning,
ageing=ageing,
physdev=physdev)
except Exception as e:
raise Exception('netlink: %s: cannot create vxlan %s: %s'
% (ifacename, vxlanid, str(e)))
netlink = Netlink()

View File

@@ -1,860 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
#
# Author: Scott Feldman, sfeldma@cumulusnetworks.com
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
#
from socket import NETLINK_ROUTE, AF_INET, AF_INET6
from string import printable
from ipaddr import *
from ctypes import *
from netlink import *
import logging
logger = logging.getLogger(__name__)
#
# from /usr/include/linux/rtnetlink.h
#
RTMGRP_LINK = 0x1
RTMGRP_IPV4_IFADDR = 0x10
RTMGRP_IPV4_ROUTE = 0x40
RTMGRP_IPV6_IFADDR = 0x100
RTMGRP_IPV6_ROUTE = 0x400
RTM_NEWLINK = 16
RTM_DELLINK = 17
RTM_GETLINK = 18
RTM_SETLINK = 19
RTM_NEWADDR = 20
RTM_DELADDR = 21
RTM_GETADDR = 22
RTM_NEWROUTE = 24
RTM_DELROUTE = 25
RTM_GETROUTE = 26
# Definitions used in routing table administration.
class Nlmsg(Structure):
def _stringify(self):
return string_at(addressof(self), sizeof(self))
def __eq__(self, other):
return self._stringify() == other._stringify() and \
self.__dict__ == other.__dict__
def to_rta(self):
return Rtattr.from_address(addressof(self) + NLMSG_ALIGN(sizeof(self)))
def pack_extra(self, extra, addr):
memmove(addr, addressof(extra), sizeof(extra))
return NLMSG_ALIGN(sizeof(extra))
def pack_rtas(self, rtas, addr):
total_len = 0
for rta_type, value in rtas.iteritems():
rta = Rtattr.from_address(addr)
rta.rta_type = rta_type
pack_fn = self.rta_fn(rta_type)
rta_len = NLMSG_ALIGN(pack_fn(rta, value))
total_len += rta_len
addr += rta_len
return total_len
def pack_rtas_new(self, rtas, addr, policy):
total_len = 0
for rta_type, value in rtas.iteritems():
if type(value) == dict:
rta = Rtattr.from_address(addr)
rta.rta_type = rta_type
rta.rta_len = RTA_LENGTH(0)
rta_len = NLMSG_ALIGN(rta.rta_len)
total_len += rta_len
addr += rta_len
pack_fn = policy.get(rta_type)
rta_len = NLMSG_ALIGN(pack_fn(addr, value))
rta.rta_len += rta_len
else:
rta = Rtattr.from_address(addr)
rta.rta_type = rta_type
pack_fn = policy.get(rta_type)
rta_len = NLMSG_ALIGN(pack_fn(rta, value))
total_len += rta_len
addr += rta_len
return total_len
def rta_linkinfo(self, addr, rtas):
total_len = 0
# Check interface kind
kind = rtas.get(IFLA_INFO_KIND)
if kind == 'vlan':
data_policy = self.rta_linkinfo_data_vlan_policy()
else:
data_policy = self.rta_linkinfo_data_macvlan_policy()
# Pack info kind
rta = Rtattr.from_address(addr)
rta.rta_type = IFLA_INFO_KIND
rta_len = NLMSG_ALIGN(self.rta_string(rta, kind))
total_len += rta_len
addr += rta_len
# nest start link info data
rta = Rtattr.from_address(addr)
rta.rta_type = IFLA_INFO_DATA
rta.rta_len = RTA_LENGTH(0)
rta_len = NLMSG_ALIGN(rta.rta_len)
total_len += rta_len
addr += rta_len
rta_len = self.pack_rtas_new(rtas.get(IFLA_INFO_DATA), addr,
data_policy)
rta.rta_len += rta_len
total_len += rta_len
addr += rta_len
return total_len
def rta_bridge_vlan_info(self, rta, value):
if value:
data = RTA_DATA(rta)
memmove(data, addressof(value), sizeof(value))
rta.rta_len = RTA_LENGTH(sizeof(value))
return rta.rta_len
def rta_af_spec(self, addr, rtas):
total_len = 0
# XXX: Check family (Assumes bridge family for now)
rta_len = self.pack_rtas_new(rtas, addr,
self.rta_bridge_af_spec_policy())
total_len += rta_len
return total_len
def unpack_rtas(self, which_ones=[]):
len = self.nlh.nlmsg_len - NLMSG_LENGTH(sizeof(self))
rta = self.to_rta()
rtas = {}
while RTA_OK(rta, len):
rta_type = rta.rta_type
if not which_ones or rta_type in which_ones:
unpack_fn = self.rta_fn(rta_type)
rtas[rta_type] = unpack_fn(rta)
len, rta = RTA_NEXT(rta, len)
return rtas
def dump_rtas(self):
rtas = self.unpack_rtas()
for type, value in rtas.iteritems():
print "rta", type, ":", value
class _IPv6Addr(BigEndianStructure):
_fields_ = [
('upper', c_uint64),
('lower', c_uint64),
]
class _IPv4Addr(BigEndianStructure):
_fields_ = [
('addr', c_uint32),
]
def rta_uint8(self, rta, value=None):
data = RTA_DATA(rta)
if value:
c_uint8.from_address(data).value = value
rta.rta_len = RTA_LENGTH(sizeof(c_uint8))
return rta.rta_len
else:
return c_uint8.from_address(data).value
def rta_uint16(self, rta, value=None):
data = RTA_DATA(rta)
if value:
c_uint16.from_address(data).value = value
rta.rta_len = RTA_LENGTH(sizeof(c_uint16))
return rta.rta_len
else:
return c_uint16.from_address(data).value
def rta_uint32(self, rta, value=None):
data = RTA_DATA(rta)
if value:
c_uint32.from_address(data).value = value
rta.rta_len = RTA_LENGTH(sizeof(c_uint32))
return rta.rta_len
else:
return c_uint32.from_address(data).value
def rta_string(self, rta, value=None):
data = RTA_DATA(rta)
if value:
s = create_string_buffer(value)
memmove(data, addressof(s), len(value))
rta.rta_len = RTA_LENGTH(len(value))
return rta.rta_len
else:
return c_char_p(data).value
def rta_addr(self, rta, value=None):
data = RTA_DATA(rta)
if value:
if isinstance(value, IPv4Address):
self._IPv4Addr.from_address(data).addr = value._ip
rta.rta_len = RTA_LENGTH(sizeof(self._IPv4Addr))
elif isinstance(value, IPv6Address):
addr = self._IPv6Addr.from_address(data)
addr.upper = value._ip >> 64
addr.lower = value._ip & 0xffffffffffffffff
rta.rta_len = RTA_LENGTH(sizeof(self._IPv6Addr))
else:
assert(False)
return rta.rta_len
else:
if RTA_PAYLOAD(rta) == 4:
addr = c_uint32.__ctype_be__.from_address(data).value
addr = IPv4Address(addr)
else:
addr = self._IPv6Addr.from_address(data)
addr = IPv6Address((addr.upper << 64) + addr.lower)
return addr
def rta_uint8_array(self, rta, value=None):
data = RTA_DATA(rta)
if value:
s = (c_uint8 * len(value)).from_buffer_copy(value)
memmove(data, addressof(s), len(value))
rta.rta_len = RTA_LENGTH(len(value))
return rta.rta_len
else:
array = (c_uint8 * RTA_PAYLOAD(rta))()
memmove(array, data, RTA_PAYLOAD(rta))
return array
def rta_uint32_array(self, rta, value=None):
if value:
assert(False)
else:
data = RTA_DATA(rta)
size = RTA_PAYLOAD(rta) / sizeof(c_uint32)
array = (c_uint32 * size)()
memmove(array, data, RTA_PAYLOAD(rta))
return array
def rta_multipath(self, rta, value=None):
# XXX implement this
return None
def rta_wtf(self, rta, value=None):
return None
def rta_none(self, rta, value=None):
return None
def rta_fn(self, rta_type):
return None
# rtm_type
RTN_UNSPEC = 0
RTN_UNICAST = 1 # Gateway or direct route
RTN_LOCAL = 2 # Accept locally
RTN_BROADCAST = 3 # Accept locally as broadcast,
# send as broadcast
RTN_ANYCAST = 4 # Accept locally as broadcast,
# but send as unicast
RTN_MULTICAST = 5 # Multicast route
RTN_BLACKHOLE = 6 # Drop
RTN_UNREACHABLE = 7 # Destination is unreachable
RTN_PROHIBIT = 8 # Administratively prohibited
RTN_THROW = 9 # Not in this table
RTN_NAT = 10 # Translate this address
RTN_XRESOLVE = 11 # Use external resolver
RTN_MAX = 11
# rtm_protocol
RTPROT_UNSPEC = 0
RTPROT_REDIRECT = 1 # Route installed by ICMP redirects;
# not used by current IPv4
RTPROT_KERNEL = 2 # Route installed by kernel
RTPROT_BOOT = 3 # Route installed during boot
RTPROT_STATIC = 4 # Route installed by administrator
# Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
# they are just passed from user and back as is.
# It will be used by hypothetical multiple routing daemons.
# Note that protocol values should be standardized in order to
# avoid conflicts.
RTPROT_GATED = 8 # Apparently, GateD
RTPROT_RA = 9 # RDISC/ND router advertisements
RTPROT_MRT = 10 # Merit MRT
RTPROT_ZEBRA = 11 # Zebra
RTPROT_BIRD = 12 # BIRD
RTPROT_DNROUTED = 13 # DECnet routing daemon
RTPROT_XORP = 14 # XORP
RTPROT_NTK = 15 # Netsukuku
RTPROT_DHCP = 16 # DHCP client
# rtm_scope
# Really it is not scope, but sort of distance to the destination.
# NOWHERE are reserved for not existing destinations, HOST is our
# local addresses, LINK are destinations, located on directly attached
# link and UNIVERSE is everywhere in the Universe.
# Intermediate values are also possible f.e. interior routes
# could be assigned a value between UNIVERSE and LINK.
RT_SCOPE_UNIVERSE = 0
# User defined values
RT_SCOPE_SITE = 200
RT_SCOPE_LINK = 253
RT_SCOPE_HOST = 254
RT_SCOPE_NOWHERE=255
# rtm_flags
RTM_F_NOTIFY = 0x100 # Notify user of route change
RTM_F_CLONED = 0x200 # This route is cloned
RTM_F_EQUALIZE = 0x400 # Multipath equalizer: NI
RTM_F_PREFIX = 0x800 # Prefix addresses
# Reserved table identifiers
RT_TABLE_UNSPEC = 0
# User defined values
RT_TABLE_COMPAT = 252
RT_TABLE_DEFAULT = 253
RT_TABLE_MAIN = 254
RT_TABLE_LOCAL = 255
RT_TABLE_MAX = 0xFFFFFFFF
# Generic structure for encapsulation of optional route information.
# It is reminiscent of sockaddr, but with sa_family replaced
# with attribute type.
class Rtattr(Structure):
_fields_ = [
('rta_len', c_uint16),
('rta_type', c_uint16),
]
# Routing message attributes
RTA_UNSPEC = 0
RTA_DST = 1
RTA_SRC = 2
RTA_IIF = 3
RTA_OIF = 4
RTA_GATEWAY = 5
RTA_PRIORITY = 6
RTA_PREFSRC = 7
RTA_METRICS = 8
RTA_MULTIPATH = 9
RTA_PROTOINFO = 10 # no longer used
RTA_FLOW = 11
RTA_CACHEINFO = 12
RTA_SESSION = 13 # no longer used
RTA_MP_ALGO = 14 # no longer used
RTA_TABLE = 15
RTA_MAX = 15
# Macros to handle rtattributes
RTA_ALIGNTO = 4
def RTA_ALIGN(len):
return (len + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)
def RTA_OK(rta, len):
return len >= sizeof(Rtattr) and \
rta.rta_len >= sizeof(Rtattr) and \
rta.rta_len <= len
def RTA_NEXT(rta, len):
cur = RTA_ALIGN(rta.rta_len)
rta = Rtattr.from_address(addressof(rta) + cur)
return len - cur, rta
def RTA_LENGTH(len):
return len + RTA_ALIGN(sizeof(Rtattr))
def RTA_SPACE(len):
return RTA_ALIGN(RTA_LENGTH(len))
def RTA_DATA(rta):
return addressof(rta) + RTA_LENGTH(0)
def RTA_PAYLOAD(rta):
return rta.rta_len - RTA_LENGTH(0)
RTNH_F_DEAD = 1 # Nexthop is dead (used by multipath)
RTNH_F_PERVASIVE = 2 # Do recursive gateway lookup
RTNH_F_ONLINK = 4 # Gateway is forced on link
# Reserved table identifiers
RT_TABLE_UNSPEC = 0
# User defined values
RT_TABLE_COMPAT = 252
RT_TABLE_DEFAULT = 253
RT_TABLE_MAIN = 254
RT_TABLE_LOCAL = 255
RT_TABLE_MAX = 0xFFFFFFFF
class Rtmsg(Nlmsg):
_fields_ = [
('rtm_family', c_uint8),
('rtm_dst_len', c_uint8),
('rtm_src_len', c_uint8),
('rtm_tos', c_uint8),
('rtm_table', c_uint8),
('rtm_protocol', c_uint8),
('rtm_scope', c_uint8),
('rtm_type', c_uint8),
('rtm_flags', c_uint32),
]
_table_str = {
RT_TABLE_UNSPEC: "unspecified",
RT_TABLE_COMPAT: "compat",
RT_TABLE_DEFAULT: "default",
RT_TABLE_MAIN: "main",
RT_TABLE_LOCAL: "local",
}
_proto_str = {
RTPROT_UNSPEC: "none",
RTPROT_REDIRECT: "redirect",
RTPROT_KERNEL: "kernel",
RTPROT_BOOT: "boot",
RTPROT_STATIC: "static",
RTPROT_GATED: "gated",
RTPROT_RA: "ra",
RTPROT_MRT: "mrtmrt",
RTPROT_ZEBRA: "zebra",
RTPROT_BIRD: "bird",
RTPROT_DNROUTED: "dnrouted",
RTPROT_XORP: "xorp",
RTPROT_NTK: "ntk",
RTPROT_DHCP: "dhcp",
}
_scope_str = {
RT_SCOPE_UNIVERSE: "universe",
RT_SCOPE_SITE: "site",
RT_SCOPE_LINK: "link",
RT_SCOPE_HOST: "host",
RT_SCOPE_NOWHERE: "nowhere",
}
_type_str = {
RTN_UNSPEC: "unspecified",
RTN_UNICAST: "unicast",
RTN_LOCAL: "local",
RTN_BROADCAST: "broadcast",
RTN_ANYCAST: "anycast",
RTN_MULTICAST: "multicast",
RTN_BLACKHOLE: "blackhole",
RTN_UNREACHABLE: "unreachable",
RTN_PROHIBIT: "prohibit",
RTN_THROW: "throw",
RTN_NAT: "nat",
RTN_XRESOLVE: "xresolve",
}
def dump(self):
print 'rtm_family', self.rtm_family
print 'rtm_dst_len', self.rtm_dst_len
print 'rtm_src_len', self.rtm_src_len
print 'rtm_tos', self.rtm_tos
print 'rtm_table', self._table_str.get(self.rtm_table, self.rtm_table)
print 'rtm_protocol', self._proto_str.get(self.rtm_protocol)
print 'rtm_scope', self._scope_str.get(self.rtm_scope)
print 'rtm_type', self._type_str.get(self.rtm_type)
print 'rtm_flags 0x%08x' % self.rtm_flags
def rta_fn(self, rta_type):
fns = {
RTA_DST: self.rta_addr,
RTA_SRC: self.rta_addr,
RTA_IIF: self.rta_uint32,
RTA_OIF: self.rta_uint32,
RTA_GATEWAY: self.rta_addr,
RTA_PRIORITY: self.rta_uint32,
RTA_PREFSRC: self.rta_addr,
RTA_METRICS: self.rta_uint32_array,
RTA_MULTIPATH: self.rta_multipath,
RTA_PROTOINFO: self.rta_none,
RTA_FLOW: self.rta_uint32,
RTA_CACHEINFO: self.rta_none,
RTA_SESSION: self.rta_none,
RTA_MP_ALGO: self.rta_none,
RTA_TABLE: self.rta_uint32,
}
return fns.get(rta_type)
class Rtgenmsg(Nlmsg):
_fields_ = [
('rtgen_family', c_uint8),
]
def dump(self):
print 'rtgen_family', self.rtgen_family
# New extended info filters for IFLA_EXT_MASK
RTEXT_FILTER_VF = (1 << 0)
# passes link level specific information, not dependent
# on network protocol.
IFLA_UNSPEC = 0
IFLA_ADDRESS = 1
IFLA_BROADCAST = 2
IFLA_IFNAME = 3
IFLA_MTU = 4
IFLA_LINK = 5
IFLA_QDISC = 6
IFLA_STATS = 7
IFLA_COST = 8
IFLA_PRIORITY = 9
IFLA_MASTER = 10
IFLA_WIRELESS = 11 # Wireless Extension event - see wireless.h
IFLA_PROTINFO = 12 # Protocol specific information for a link
IFLA_TXQLEN = 13
IFLA_MAP = 14
IFLA_WEIGHT = 15
IFLA_OPERSTATE = 16
IFLA_LINKMODE = 17
IFLA_LINKINFO = 18
IFLA_NET_NS_PID = 19
IFLA_IFALIAS = 20
IFLA_NUM_VF = 21 # Number of VFs if device is SR-IOV PF
IFLA_VFINFO_LIST = 22
IFLA_STATS64 = 23
IFLA_VF_PORTS = 24
IFLA_PORT_SELF = 25
IFLA_AF_SPEC = 26
IFLA_GROUP = 27 # Group the device belongs to
IFLA_NET_NS_FD = 28
IFLA_EXT_MASK = 29 # Extended info mask, VFs, etc
IFLA_MAX = 29
# IFLA_LINKINFO attributes
IFLA_INFO_UNSPEC = 0
IFLA_INFO_KIND = 1
IFLA_INFO_DATA = 2
IFLA_INFO_XSTATS = 3
IFLA_INFO_MAX = 4
# IFLA_LINKINFO_DATA attributes for vlan
IFLA_VLAN_UNSPEC = 0
IFLA_VLAN_ID = 1
# IFLA_LINKINFO_DATA attributes for macvlan
IFLA_MACVLAN_UNSPEC = 0
IFLA_MACVLAN_MODE = 1
# macvlan modes
MACVLAN_MODE_PRIVATE = 1
MACVLAN_MODE_VEPA = 2
MACVLAN_MODE_BRIDGE = 3
MACVLAN_MODE_PASSTHRU = 4
# BRIDGE IFLA_AF_SPEC attributes
IFLA_BRIDGE_FLAGS = 0
IFLA_BRIDGE_MODE = 1
IFLA_BRIDGE_VLAN_INFO = 2
# BRIDGE_VLAN_INFO flags
BRIDGE_VLAN_INFO_MASTER = 1
BRIDGE_VLAN_INFO_PVID = 2
BRIDGE_VLAN_INFO_UNTAGGED = 4
# Bridge flags
BRIDGE_FLAGS_MASTER = 1
BRIDGE_FLAGS_SELF = 2
class BridgeVlanInfo(Structure):
_fields_ = [
('flags', c_uint16),
('vid', c_uint16),
('vid_end', c_uint16),
]
class Ifinfomsg(Nlmsg):
_fields_ = [
('ifi_family', c_uint8),
('__ifi_pad', c_uint8),
('ifi_type', c_uint16), # ARPHRD_*
('ifi_index', c_int32), # Link index
('ifi_flags', c_uint32), # IFF_* flags
('ifi_change', c_uint32), # IFF_* change mask
]
def dump(self):
print 'ifi_family', self.ifi_family
print 'ifi_type', self.ifi_type
print 'ifi_index', self.ifi_index
print 'ifi_flags 0x%08x' % self.ifi_flags
print 'ifi_change 0x%08x' % self.ifi_change
def rta_linkinfo_data_vlan_policy(self):
fns = {
IFLA_VLAN_ID : self.rta_uint16,
}
return fns
def rta_linkinfo_data_macvlan_policy(self):
fns = {
IFLA_MACVLAN_MODE : self.rta_uint32,
}
return fns
def rta_linkinfo_policy(self):
fns = {
IFLA_INFO_KIND : self.rta_string,
IFLA_INFO_DATA : self.rta_linkinfo_data,
}
return fns
def rta_bridge_af_spec_policy(self):
# Assume bridge family for now
fns = {
IFLA_BRIDGE_FLAGS : self.rta_uint16,
IFLA_BRIDGE_VLAN_INFO : self.rta_bridge_vlan_info,
}
return fns
def rta_policy(self):
fns = {
IFLA_UNSPEC: self.rta_wtf,
IFLA_ADDRESS: self.rta_uint8_array,
IFLA_BROADCAST: self.rta_uint8_array,
IFLA_IFNAME: self.rta_string,
IFLA_MTU: self.rta_uint32,
IFLA_LINK: self.rta_uint32,
IFLA_QDISC: self.rta_string,
IFLA_STATS: self.rta_none,
IFLA_COST: self.rta_none,
IFLA_PRIORITY: self.rta_none,
IFLA_MASTER: self.rta_uint32,
IFLA_WIRELESS: self.rta_none,
IFLA_PROTINFO: self.rta_none,
IFLA_TXQLEN: self.rta_uint32,
IFLA_MAP: self.rta_none,
IFLA_WEIGHT: self.rta_uint32,
IFLA_OPERSTATE: self.rta_uint8,
IFLA_LINKMODE: self.rta_uint8,
IFLA_LINKINFO: self.rta_linkinfo,
IFLA_NET_NS_PID: self.rta_uint32,
IFLA_IFALIAS: self.rta_string,
IFLA_NUM_VF: self.rta_uint32,
IFLA_VFINFO_LIST: self.rta_none,
IFLA_STATS64: self.rta_none,
IFLA_VF_PORTS: self.rta_none,
IFLA_PORT_SELF: self.rta_none,
IFLA_AF_SPEC: self.rta_af_spec,
IFLA_GROUP: self.rta_none,
IFLA_NET_NS_FD: self.rta_none,
IFLA_EXT_MASK: self.rta_none,
}
return fns;
def rta_fn(self, rta_type):
fns = {
IFLA_UNSPEC: self.rta_wtf,
IFLA_ADDRESS: self.rta_uint8_array,
IFLA_BROADCAST: self.rta_uint8_array,
IFLA_IFNAME: self.rta_string,
IFLA_MTU: self.rta_uint32,
IFLA_LINK: self.rta_uint32,
IFLA_QDISC: self.rta_string,
IFLA_STATS: self.rta_none,
IFLA_COST: self.rta_none,
IFLA_PRIORITY: self.rta_none,
IFLA_MASTER: self.rta_uint32,
IFLA_WIRELESS: self.rta_none,
IFLA_PROTINFO: self.rta_none,
IFLA_TXQLEN: self.rta_uint32,
IFLA_MAP: self.rta_none,
IFLA_WEIGHT: self.rta_uint32,
IFLA_OPERSTATE: self.rta_uint8,
IFLA_LINKMODE: self.rta_uint8,
IFLA_LINKINFO: self.rta_linkinfo,
IFLA_NET_NS_PID: self.rta_uint32,
IFLA_IFALIAS: self.rta_string,
IFLA_NUM_VF: self.rta_uint32,
IFLA_VFINFO_LIST: self.rta_none,
IFLA_STATS64: self.rta_none,
IFLA_VF_PORTS: self.rta_none,
IFLA_PORT_SELF: self.rta_none,
IFLA_AF_SPEC: self.rta_af_spec,
IFLA_GROUP: self.rta_none,
IFLA_NET_NS_FD: self.rta_none,
IFLA_EXT_MASK: self.rta_none,
}
return fns.get(rta_type)
# passes address specific information
# Important comment:
# IFA_ADDRESS is prefix address, rather than local interface address.
# It makes no difference for normally configured broadcast interfaces,
# but for point-to-point IFA_ADDRESS is DESTINATION address,
# local address is supplied in IFA_LOCAL attribute.
IFA_UNSPEC = 0
IFA_ADDRESS = 1
IFA_LOCAL = 2
IFA_LABEL = 3
IFA_BROADCAST = 4
IFA_ANYCAST = 5
IFA_CACHEINFO = 6
IFA_MULTICAST = 7
IFA_MAX = 7
class Ifaddrmsg(Nlmsg):
_fields_ = [
('ifa_family', c_uint8),
('ifa_prefixlen', c_uint8), # The prefix length
('ifa_flags', c_uint8), # Flags
('ifa_scope', c_uint8), # Address scope
('ifa_index', c_uint32), # Link index
]
_family_str = {
AF_INET: "inet",
AF_INET6: "inet6",
}
def dump(self):
print 'ifa_family', self.ifa_family
print 'ifa_prefixlen', self.ifa_prefixlen
print 'ifa_flags 0x%02x' % self.ifa_flags
print 'ifa_scope', self.ifa_scope
print 'ifa_index', self.ifa_index
def rta_fn(self, rta_type):
fns = {
IFA_ADDRESS: self.rta_addr,
IFA_LOCAL: self.rta_addr,
IFA_LABEL: self.rta_string,
IFA_BROADCAST: self.rta_addr,
IFA_ANYCAST: self.rta_addr,
IFA_CACHEINFO: self.rta_none,
IFA_MULTICAST: self.rta_addr,
}
return fns.get(rta_type)
class RtNetlinkError(Exception):
def __init__(self, message):
Exception.__init__(self, message)
logger.error(message)
class RtNetlink(Netlink):
def __init__(self, pid):
Netlink.__init__(self, pid, NETLINK_ROUTE)
_rt_nlmsg_type_str = {
RTM_NEWROUTE: "RTM_NEWROUTE",
RTM_DELROUTE: "RTM_DELROUTE",
RTM_NEWLINK: "RTM_NEWLINK",
RTM_SETLINK: "RTM_SETLINK",
RTM_DELLINK: "RTM_DELLINK",
RTM_GETLINK: "RTM_GETLINK",
RTM_NEWADDR: "RTM_NEWADDR",
RTM_DELADDR: "RTM_DELADDR",
}
def _hexdump(self, buf):
while buf:
chunk = buf[:16]
buf = buf[16:]
nums = ["%02x" % c for c in chunk]
txt = [chr(c) if chr(c) in printable[:-5] else '.' for c in chunk]
print " ".join(nums).ljust(48), "".join(txt)
def dump(self, nlh):
nlmsg = self.nlmsg(nlh)
print
self._hexdump(self.sendbuf[:nlh.nlmsg_len])
print
nlh.dump()
print
nlmsg.dump()
print
nlmsg.dump_rtas()
def nlmsg(self, nlh):
nlmsg_struct = {
RTM_NEWROUTE: Rtmsg,
RTM_DELROUTE: Rtmsg,
RTM_GETROUTE: Rtmsg,
RTM_NEWLINK: Ifinfomsg,
RTM_SETLINK: Ifinfomsg,
RTM_DELLINK: Ifinfomsg,
RTM_GETLINK: Rtgenmsg,
RTM_NEWADDR: Ifaddrmsg,
RTM_DELADDR: Ifaddrmsg,
RTM_GETADDR: Rtgenmsg,
}
nldata = NLMSG_DATA(nlh)
nlmsg = nlmsg_struct[nlh.nlmsg_type].from_address(nldata)
nlmsg.nlh = nlh
return nlmsg
def _nl_cb(self, nlh):
# print "nl cb", self._rt_nlmsg_type_str[nlh.nlmsg_type]
if nlh.nlmsg_type in self._cbs:
nlmsg = self.nlmsg(nlh)
# validate nl length
if nlh.nlmsg_len - NLMSG_LENGTH(sizeof(nlmsg)) < 0:
raise RtNetlinkError("invalid nl length")
self._cbs[nlh.nlmsg_type](nlh, nlmsg)
def bind(self, groups, cbs):
self._cbs = cbs
Netlink.bind(self, groups, self._nl_cb)
def request(self, nlmsg_type, flags, extra, rtas={}):
nlh = Nlmsghdr.from_buffer(self.sendbuf)
nlh_p = addressof(nlh)
seq = self.seq
pid = self.pid
nlh.nlmsg_len = NLMSG_HDRLEN()
nlh.nlmsg_type = nlmsg_type
nlh.nlmsg_flags = flags
nlh.nlmsg_pid = pid
nlh.nlmsg_seq = seq
nlmsg = self.nlmsg(nlh)
nlh.nlmsg_len += nlmsg.pack_extra(extra, nlh_p + nlh.nlmsg_len)
nlh.nlmsg_len += nlmsg.pack_rtas_new(rtas, nlh_p + nlh.nlmsg_len,
nlmsg.rta_policy())
#self.dump(nlh)
self.sendall(string_at(nlh_p, nlh.nlmsg_len))
self.seq += 1
token = (pid, seq)
return token

View File

@@ -1,237 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
#
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
#
from os import getpid
from socket import AF_UNSPEC
from socket import AF_BRIDGE
from iff import IFF_UP
from rtnetlink import *
import os
import ifupdownmain
class rtnetlinkApi(RtNetlink):
bind_done = False
def __init__(self, pid):
RtNetlink.__init__(self, pid)
self.logger = logging.getLogger('ifupdown.' +
self.__class__.__name__)
self.bind(0, None)
self.bind_done = True
self.ifindexmap = {}
def do_bind(self):
if self.bind_done:
return True
self.bind(0, None)
self.bind_done = True
def get_ifindex(self, ifname):
ifindex = self.ifindexmap.get(ifname)
if not ifindex:
with open('/sys/class/net/%s/ifindex' %ifname, 'r') as f:
ifindex = int(f.read())
self.ifindexmap[ifname] = ifindex
return ifindex
def create_vlan(self, link, ifname, vlanid):
self.logger.info('rtnetlink: creating vlan interface %s' %ifname)
if ifupdownmain.ifupdownFlags.DRYRUN:
return
try:
ifindex = self.get_ifindex(link)
except Exception, e:
raise Exception('cannot determine ifindex for link %s (%s)'
%(link, str(e)))
ifm = Ifinfomsg(AF_UNSPEC)
rtas = {IFLA_IFNAME: ifname,
IFLA_LINK : ifindex,
IFLA_LINKINFO : {
IFLA_INFO_KIND : 'vlan',
IFLA_INFO_DATA : {
IFLA_VLAN_ID : vlanid,
}
}
}
token = self.request(RTM_NEWLINK,
NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def create_macvlan(self, ifname, link, mode='private'):
self.logger.info('rtnetlink: creating macvlan interface %s' %ifname)
if ifupdownmain.ifupdownFlags.DRYRUN:
return
try:
ifindex = self.get_ifindex(link)
except Exception, e:
raise Exception('cannot determine ifindex for link %s (%s)'
%(link, str(e)))
ifm = Ifinfomsg(AF_UNSPEC)
rtas = {IFLA_IFNAME: ifname,
IFLA_LINK : ifindex,
IFLA_LINKINFO : {
IFLA_INFO_KIND : 'macvlan',
IFLA_INFO_DATA : {
IFLA_MACVLAN_MODE : MACVLAN_MODE_PRIVATE,
}
}
}
token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST |
NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def link_set(self, ifname, state):
flags = 0
self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
if ifupdownmain.ifupdownFlags.DRYRUN:
return
if state == "up":
flags |= IFF_UP
else:
flags &= ~IFF_UP
ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
rtas = {IFLA_IFNAME: ifname}
token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def link_set_hwaddress(self, ifname, hwaddress):
flags = 0
self.logger.info('rtnetlink: setting link hwaddress %s %s' %(ifname, hwaddress))
if ifupdownmain.ifupdownFlags.DRYRUN:
return
flags &= ~IFF_UP
ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP)
rtas = {IFLA_IFNAME: ifname,
IFLA_ADDRESS : str(bytearray([int(a,16) for a in hwaddress.split(':')]))}
self.logger.info(rtas)
token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def addr_add(self, ifname, address, broadcast=None, peer=None, scope=None,
preferred_lifetime=None):
self.logger.info('rtnetlink: setting address')
if ifupdownmain.ifupdownFlags.DRYRUN:
return
try:
ifindex = self.get_ifindex(link)
except Exception, e:
raise Exception('cannot determine ifindex for link %s (%s)'
%(link, str(e)))
ifa_scope = RT_SCOPE_
if scope:
if scope == "universe":
ifa_scope = RT_SCOPE_UNIVERSE
elif scope == "site":
ifa_scope = RT_SCOPE_SITE
elif scope == "link":
ifa_scope = RT_SCOPE_LINK
elif scope == "host":
ifa_scope = RT_SCOPE_HOST
elif scope == "nowhere":
ifa_scope = RT_SCOPE_NOWHERE
rtas = {IFLA_ADDRESS: ifname}
ifa = Ifaddrmsg(AF_UNSPEC, ifa_scope=ifa_scope, ifa_index=ifindex)
token = self.request(RTM_NEWADDR, NLM_F_REQUEST | NLM_F_ACK, ifa, rtas)
self.process_wait([token])
def link_set_many(self, ifname, ifattrs):
_ifattr_to_rta_map = {'dev' : IFLA_NAME,
'address' : IFLA_ADDRESS,
'broadcast' : IFLA_BROADCAST,
'mtu' : IFLA_MTU,
'master' : IFLA_MASTER}
flags = 0
ifi_change = IFF_UP
rtas = {}
self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
if ifupdownmain.ifupdownFlags.DRYRUN:
return
if not ifattrs:
return
state = ifattrs.get('state')
if state == 'up':
flags |= IFF_UP
elif state == 'down':
flags &= ~IFF_UP
else:
ifi_change = 0
if ifi_change:
ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags)
else:
ifm = Ifinfomsg(AF_UNSPEC)
for attr, attrval in ifattrs.items():
rta_attr = _ifattr_to_rta_map.get(attr)
if rta_attr:
if attr == 'hwaddress':
rtas[rta_attr] = str(bytearray([int(a,16) for a in attrval.split(':')]))
else:
rtas[rta_attr] = attrval
token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def bridge_vlan(self, add=True, vid=None, dev=None, pvid=False,
untagged=False, master=True):
flags = 0
vflags = 0
if not vid or not dev:
return
self.logger.info('rtnetlink: bridge vlan add vid %s %s %s dev %s %s'
%(vid, 'untagged' if untagged else '',
'pvid' if pvid else '', dev,
'self' if self else ''))
if ifupdownmain.ifupdownFlags.DRYRUN:
return
try:
ifindex = self.get_ifindex(dev)
except Exception, e:
raise Exception('cannot determine ifindex for dev %s (%s)'
%(dev, str(e)))
if not master:
flags = BRIDGE_FLAGS_SELF
if pvid:
vflags = BRIDGE_VLAN_INFO_PVID
vflags |= BRIDGE_VLAN_INFO_UNTAGGED
elif untagged:
vflags |= BRIDGE_VLAN_INFO_UNTAGGED
ifm = Ifinfomsg(AF_BRIDGE, ifi_index=ifindex)
rtas = {IFLA_AF_SPEC: {
IFLA_BRIDGE_FLAGS: flags,
IFLA_BRIDGE_VLAN_INFO : BridgeVlanInfo(vflags, int(vid), int(vid))
}
}
if add:
token = self.request(RTM_SETLINK,
NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
else:
token = self.request(RTM_DELLINK,
NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def bridge_vlan_many(self, add=True, vids=[], dev=None, pvid=False,
untagged=False, master=True):
for v in vids:
self.bridge_vlan_add(add, v, dev, ispvid, isuntagged, master)
rtnl_api = rtnetlinkApi(os.getpid())

46
ifupdown2/__init__.py Normal file
View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__version__ = '2.0.0'
# Copyright (C) 2014,2015,2016,2017,2018 Cumulus Networks, Inc. All rights reserved
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# https://www.gnu.org/licenses/gpl-2.0-standalone.html
#
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# Julien Fortin, julien@cumulusnetworks.com
__license__ = 'GPL-2'
__status__ = 'Production'
__copyright__ = 'Copyright (C) 2014,2015,2016,2017,2018 Cumulus Networks, Inc.'
__authors__ = [
'Roopa Prabhu',
'Julien Fortin'
]
__credits__ = [
'Roopa Prabhu',
'Julien Fortin'
]
__emails__ = [
'roopa@cumulusnetworks.com',
'julien@cumulusnetworks.com'
]
__maintainer__ = 'Julien Fortin'
__email__ = 'julien@cumulusnetworks.com'

205
ifupdown2/__main__.py Executable file
View File

@@ -0,0 +1,205 @@
#!/usr/bin/python
#
# Copyright 2016 Cumulus Networks, Inc. All rights reserved.
# Author: Julien Fortin, julien@cumulusnetworks.com
#
#
import os
import re
import sys
import json
import errno
import struct
import select
import socket
import signal
try:
import ifupdown2.ifupdown.config as core_config
from ifupdown2.ifupdown.log import log
from ifupdown2 import __version__
core_config.__version__ = __version__
except:
import ifupdown.config as core_config
from ifupdown.log import log
core_config.__version__ = __import__('__init__').__version__
class Ifupdown2Complete(Exception):
def __init__(self, status):
self.status = status
class Ifupdown2Client:
def __init__(self, argv):
self.stdin = None
self.argv = argv
self.data = ''
self.HEADER_SIZE = 4
self.daemon_pid = -1
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
self.socket.connect('/var/run/ifupdown2d/uds')
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
signal.signal(signal.SIGQUIT, self.signal_handler)
try:
self.SO_PEERCRED = socket.SO_PEERCRED
except AttributeError:
# powerpc is the only non-generic we care about. alpha, mips,
# sparc, and parisc also have non-generic values.
machine = os.uname()[4]
if re.search(r'^(ppc|powerpc)', machine):
self.SO_PASSCRED = 20
self.SO_PEERCRED = 21
else:
self.SO_PASSCRED = 16
self.SO_PEERCRED = 17
try:
self.socket.setsockopt(socket.SOL_SOCKET, self.SO_PASSCRED, 1)
except Exception as e:
raise Exception('setsockopt: %s' % str(e))
except socket.error:
self.socket.close()
self.socket = None
sys.stderr.write("""
ERROR: %s could not connect to ifupdown2d
Try starting ifupdown2d with:
sudo systemctl start ifupdown2d
To configure ifupdown2d to start when the box boots:
sudo systemctl enable ifupdown2d
""" % argv[0])
def __del__(self):
if self.socket:
self.socket.close()
def signal_handler(self, sig, frame):
if self.daemon_pid > 0:
os.kill(self.daemon_pid, sig)
def read_data(self):
ready = select.select([self.socket], [], [])
if ready and ready[0] and ready[0][0] == self.socket:
d = self.socket.recv(65536)
if self.data:
self.data += d
else:
self.data = d
return True
return False
def get_packets(self):
"""
ifupdown2 output is divided into "json packets"
the first 4 bytes is the size of the next json
object to etract
"""
data_size = len(self.data)
if not data_size:
raise Ifupdown2Complete(status=1)
packets = []
try:
while data_size > 0:
packet_len = struct.unpack('=I', self.data[:self.HEADER_SIZE])[0]
packet_data = self.data[self.HEADER_SIZE:packet_len + self.HEADER_SIZE]
fmt = "=%ds" % packet_len
packets.append(json.loads(struct.unpack(fmt, packet_data)[0]))
self.data = self.data[self.HEADER_SIZE + packet_len:]
data_size -= self.HEADER_SIZE + packet_len
except:
pass
return packets
def process_packets(self, packets):
for packet in packets:
if 'pid' in packet:
self.daemon_pid = packet['pid']
if 'stdout' in packet:
sys.stdout.write(packet['stdout'])
if 'stderr' in packet:
sys.stderr.write(packet['stderr'])
if 'status' in packet:
raise Ifupdown2Complete(packet['status'])
def run(self):
status = 1
if self.socket:
for arg in ['-i', '--interfaces']:
try:
if self.argv[self.argv.index(arg) + 1] == '-':
self.stdin = sys.stdin.read()
continue
except (ValueError, IndexError):
pass
self.socket.send(json.dumps({
'argv': self.argv,
'stdin': self.stdin
}))
try:
while True:
try:
self.read_data()
self.process_packets(self.get_packets())
except Ifupdown2Complete as e:
status = e.status
break
except Exception as e:
if ((isinstance(e.args, tuple) and e[0] == 4)
or (hasattr(e, 'errno') and e.errno == errno.EINTR)):
pass
else:
raise
except Exception as e:
sys.stderr.write(str(e))
finally:
self.socket.close()
return status if status != None else 1
def ifupdown2_standalone():
try:
import ifupdown2.ifupdown.main as main_ifupdown2
except:
import ifupdown.main as main_ifupdown2
ifupdown2 = main_ifupdown2.Ifupdown2(daemon=False, uid=os.geteuid())
ifupdown2.parse_argv(sys.argv)
ifupdown2.update_logger()
return ifupdown2.main()
def main():
try:
if 'use_daemon=yes' in open(core_config.IFUPDOWN2_CONF_PATH).read():
return Ifupdown2Client(sys.argv).run()
else:
return ifupdown2_standalone()
except KeyboardInterrupt:
return 1
except Exception as e:
log.error(str(e))
return 1
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit(1)

View File

@@ -1,26 +1,38 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
from ipaddr import IPNetwork, IPv4Network, IPv6Network, _BaseV6
try:
from ipaddr import IPNetwork, IPv4Network, IPv6Network, IPv4Address, IPv6Address
from sets import Set
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.dhclient import dhclient
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdownaddons.dhclient import dhclient
import ifupdown.policymanager as policymanager
from ifupdown.netlink import netlink
import ifupdown.ifupdownconfig as ifupdownConfig
import ifupdown.ifupdownflags as ifupdownflags
from ifupdownaddons.dhclient import dhclient
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.statemanager as statemanager
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.ifupdownconfig as ifupdownconfig
class address(moduleBase):
""" ifupdown2 addon module to configure address, mtu, hwaddress, alias
@@ -81,7 +93,23 @@ class address(moduleBase):
{ 'help' : 'Anycast local IP address for ' +
'dual connected VxLANs',
'validvals' : ['<ipv4>', ],
'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']}}}
'example' : ['clagd-vxlan-anycast-ip 36.0.0.11']},
'ip-forward' :
{ 'help': 'ip forwarding flag',
'validvals': ['on', 'off'],
'default' : 'off',
'example' : ['ip-forward off']},
'ip6-forward' :
{ 'help': 'ipv6 forwarding flag',
'validvals': ['on', 'off'],
'default' : 'off',
'example' : ['ip6-forward off']},
'mpls-enable' :
{ 'help': 'mpls enable flag',
'validvals': ['yes', 'no'],
'default' : 'no',
'example' : ['mpls-enable yes']},
}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
@@ -89,6 +117,15 @@ class address(moduleBase):
self._bridge_fdb_query_cache = {}
self.default_mtu = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='mtu')
self.max_mtu = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='max_mtu')
self.ipforward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip-forward')
self.ip6forward = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='ip6-forward')
self.ifaces_defaults = policymanager.policymanager_api.get_iface_defaults(module_name=self.__class__.__name__)
self.enable_l3_iface_forwarding_checks = utils.get_boolean_from_string(
policymanager.policymanager_api.get_module_globals(
self.__class__.__name__,
'enable_l3_iface_forwarding_checks'
)
)
if not self.default_mtu:
self.default_mtu = '1500'
@@ -98,10 +135,63 @@ class address(moduleBase):
if self.max_mtu:
self.logger.info('address: using max mtu %s' %self.max_mtu)
self.lower_iface_mtu_checked_list = list()
def syntax_check(self, ifaceobj, ifaceobj_getfunc=None):
return (self.syntax_check_multiple_gateway(ifaceobj)
and self.syntax_check_addr_allowed_on(ifaceobj, True)
and self.syntax_check_mtu(ifaceobj, ifaceobj_getfunc))
and self.syntax_check_mtu(ifaceobj, ifaceobj_getfunc)
and self.syntax_check_sysctls(ifaceobj)
and self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc, syntax_check=True))
def syntax_check_enable_l3_iface_forwardings(self, ifaceobj, ifaceobj_getfunc, syntax_check=False):
if (self.enable_l3_iface_forwarding_checks
and (ifaceobj.link_kind & ifaceLinkKind.VLAN
or ifaceobj.link_kind & ifaceLinkKind.BRIDGE)
and not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
ifname = ifaceobj.name
vlan_addr = None
vlan_ipforward_off = None
for obj in ifaceobj_getfunc(ifname) or [ifaceobj]:
if not vlan_addr:
vlan_addr = obj.get_attr_value('address')
if not vlan_ipforward_off:
ip_forward_value = obj.get_attr_value_first('ip-forward')
if ip_forward_value and not utils.get_boolean_from_string(ip_forward_value):
vlan_ipforward_off = True
if vlan_addr and vlan_ipforward_off:
if syntax_check:
raise Exception(
'configuring ip-forward off and ip address(es) (%s) is not compatible'
% (', '.join(vlan_addr))
)
else:
raise Exception(
'%s: configuring ip-forward off and ip address(es) (%s) is not compatible'
% (ifname, ', '.join(vlan_addr))
)
return True
def syntax_check_sysctls(self, ifaceobj):
result = True
bridge_port = (ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT)
ipforward = ifaceobj.get_attr_value_first('ip-forward')
if bridge_port and ipforward:
result = False
self.log_error('%s: \'ip-forward\' is not supported for '
'bridge port' %ifaceobj.name)
ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
if bridge_port and ip6forward:
result = False
self.log_error('%s: \'ip6-forward\' is not supported for '
'bridge port' %ifaceobj.name)
return result
def syntax_check_mtu(self, ifaceobj, ifaceobj_getfunc):
mtu = ifaceobj.get_attr_value_first('mtu')
@@ -150,10 +240,7 @@ class address(moduleBase):
return False
def _get_hwaddress(self, ifaceobj):
hwaddress = ifaceobj.get_attr_value_first('hwaddress')
if hwaddress and hwaddress.startswith("ether"):
hwaddress = hwaddress[5:].strip()
return hwaddress
return utils.strip_hwaddress(ifaceobj.get_attr_value_first('hwaddress'))
def _process_bridge(self, ifaceobj, up):
hwaddress = self._get_hwaddress(ifaceobj)
@@ -161,8 +248,9 @@ class address(moduleBase):
is_vlan_dev_on_vlan_aware_bridge = False
is_bridge = self.ipcmd.is_bridge(ifaceobj.name)
if not is_bridge:
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
is_vlan_dev_on_vlan_aware_bridge = self.ipcmd.bridge_is_vlan_aware(bridgename)
if ((is_bridge and not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name))
or is_vlan_dev_on_vlan_aware_bridge):
@@ -250,8 +338,8 @@ class address(moduleBase):
def _inet_address_config(self, ifaceobj, ifaceobj_getfunc=None,
force_reapply=False):
squash_addr_config = (True if \
ifupdownConfig.config.get('addr_config_squash', \
'0') == '1' else False)
ifupdownconfig.config.get('addr_config_squash', \
'0') == '1' else False)
if (squash_addr_config and
not (ifaceobj.flags & ifaceobj.YOUNGEST_SIBLING)):
@@ -266,8 +354,12 @@ class address(moduleBase):
else:
ifaceobjlist = [ifaceobj]
module_name = self.__class__.__name__
ifname = ifaceobj.name
(addr_supported, newaddrs, newaddr_attrs) = self._inet_address_convert_to_cidr(ifaceobjlist)
newaddrs = utils.get_normalized_ip_addr(ifaceobj.name, newaddrs)
newaddrs = utils.get_ip_objs(module_name, ifname, newaddrs)
if not addr_supported:
return
if (not squash_addr_config and (ifaceobj.flags & iface.HAS_SIBLINGS)):
@@ -281,7 +373,7 @@ class address(moduleBase):
if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes':
# if perfmode is not set and purge addresses is not set to 'no'
# lets purge addresses not in the config
runningaddrs = utils.get_normalized_ip_addr(ifaceobj.name, self.ipcmd.addr_get(ifaceobj.name, details=False))
runningaddrs = self.ipcmd.get_running_addrs(ifaceobj, details=False)
# if anycast address is configured on 'lo' and is in running config
# add it to newaddrs so that ifreload doesn't wipe it out
@@ -289,35 +381,102 @@ class address(moduleBase):
if runningaddrs and anycast_addr and anycast_addr in runningaddrs:
newaddrs.append(anycast_addr)
if newaddrs == runningaddrs:
user_ip4, user_ip6, newaddrs = self.order_user_configured_addrs(newaddrs)
if newaddrs == runningaddrs or self.compare_running_ips_and_user_config(user_ip4, user_ip6, runningaddrs):
if force_reapply:
self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
return
try:
# if primary address is not same, there is no need to keep any.
# reset all addresses
if (newaddrs and runningaddrs and
(newaddrs[0] != runningaddrs[0])):
self.ipcmd.del_addr_all(ifaceobj.name)
if newaddrs and runningaddrs and newaddrs[0] != runningaddrs[0]:
skip_addrs = []
else:
self.ipcmd.del_addr_all(ifaceobj.name, newaddrs)
skip_addrs = newaddrs or []
for addr in runningaddrs or []:
if addr in skip_addrs:
continue
self.ipcmd.addr_del(ifaceobj.name, addr)
except Exception, e:
self.log_warn(str(e))
if not newaddrs:
return
self._inet_address_list_config(ifaceobj, newaddrs, newaddr_attrs)
def _add_delete_gateway(self, ifaceobj, gateways=[], prev_gw=[]):
vrf = ifaceobj.get_attr_value_first('vrf')
metric = ifaceobj.get_attr_value_first('metric')
for del_gw in list(set(prev_gw) - set(gateways)):
def compare_running_ips_and_user_config(self, user_ip4, user_ip6, running_addrs):
"""
We need to compare the user config ips and the running ips.
ip4 ordering matters (primary etc) but ip6 order doesn't matter
this function replaces the strict comparison previously in place
if newaddrs == running_addrs ?
We will compare if the ip4 ordering is correct, then check if all
ip6 are present in the list (without checking the ordering)
"""
if (user_ip4 or user_ip6) and not running_addrs:
return False
elif running_addrs and not user_ip4 and not user_ip6:
return False
elif not running_addrs and not user_ip4 and not user_ip6:
return True
len_ip4 = len(user_ip4)
len_running_addrs = len(running_addrs)
if len_ip4 > len_running_addrs:
return False
i = 0
while i < len_ip4:
if user_ip4[i] != running_addrs[i]:
return False
i += 1
if len_ip4 > 0:
running_ip6 = running_addrs[len_ip4:]
else:
running_ip6 = running_addrs
i = 0
len_ip6 = len(user_ip6)
for ip6 in running_ip6:
if ip6 not in user_ip6:
return False
i += 1
return i == len_ip6
def order_user_configured_addrs(self, user_config_addrs):
ip4 = []
ip6 = []
for a in user_config_addrs:
if isinstance(a, _BaseV6):
ip6.append(str(a))
else:
ip4.append(str(a))
return ip4, ip6, ip4 + ip6
def _delete_gateway(self, ifaceobj, gateways, vrf, metric):
for del_gw in gateways:
try:
self.ipcmd.route_del_gateway(ifaceobj.name, del_gw, vrf, metric)
except Exception as e:
self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
def _add_delete_gateway(self, ifaceobj, gateways=[], prev_gw=[]):
vrf = ifaceobj.get_attr_value_first('vrf')
metric = ifaceobj.get_attr_value_first('metric')
self._delete_gateway(ifaceobj, list(set(prev_gw) - set(gateways)),
vrf, metric)
for add_gw in gateways:
try:
self.ipcmd.route_add_gateway(ifaceobj.name, add_gw, vrf)
self.ipcmd.route_add_gateway(ifaceobj.name, add_gw, vrf, metric)
except Exception as e:
self.log_error('%s: %s' % (ifaceobj.name, str(e)))
@@ -358,14 +517,15 @@ class address(moduleBase):
if syntaxcheck:
lowerdev_mtu = lowerobj[0].get_attr_value_first('mtu')
else:
lowerdev_mtu = self.ipcmd.link_get_mtu(lowerobj[0].name)
lowerdev_mtu = self.ipcmd.link_get_mtu_sysfs(lowerobj[0].name)
if lowerdev_mtu and int(mtu) > int(lowerdev_mtu):
self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
%(ifaceobj.name, mtu, lowerobj[0].name, lowerdev_mtu))
retval = False
elif (not lowerobj[0].link_kind and
not (lowerobj[0].link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
self.default_mtu and (int(mtu) > int(self.default_mtu))):
not lowerdev_mtu and self.default_mtu and
(int(mtu) > int(self.default_mtu))):
# only check default mtu on lower device which is a physical interface
self.logger.warn('%s: vlan dev mtu %s is greater than lower realdev %s mtu %s'
%(ifaceobj.name, mtu, lowerobj[0].name, self.default_mtu))
@@ -394,17 +554,18 @@ class address(moduleBase):
if not running_mtu or (running_mtu != mtu):
self.ipcmd.link_set(u, 'mtu', mtu)
def _process_mtu_config(self, ifaceobj, ifaceobj_getfunc):
mtu = ifaceobj.get_attr_value_first('mtu')
def _process_mtu_config(self, ifaceobj, ifaceobj_getfunc, mtu):
if mtu:
if not self._check_mtu_config(ifaceobj, mtu, ifaceobj_getfunc):
return
running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
cached_running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name)
running_mtu = self.ipcmd.link_get_mtu_sysfs(ifaceobj.name)
if not running_mtu or (running_mtu and running_mtu != mtu):
self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
force = cached_running_mtu != running_mtu
self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu, force=force)
if (not ifupdownflags.flags.ALL and
not ifaceobj.link_kind and
ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'):
# This is additional cost to us, so do it only when
# ifupdown2 is called on a particular interface and
# it is a physical interface
@@ -420,12 +581,19 @@ class address(moduleBase):
if (self.default_mtu and running_mtu != self.default_mtu):
self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
return
if (ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0'
if (ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0'
and ifaceobj.lowerifaces):
# set vlan interface mtu to lower device mtu
if (ifaceobj.link_kind & ifaceLinkKind.VLAN):
lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.lowerifaces[0], refresh=True)
if not lower_iface_mtu == self.ipcmd.link_get_mtu(ifaceobj.name):
lower_iface = ifaceobj.lowerifaces[0]
if lower_iface not in self.lower_iface_mtu_checked_list:
lower_iface_mtu = self.ipcmd.link_get_mtu_sysfs(lower_iface)
self.ipcmd.cache_update([lower_iface, 'mtu'], lower_iface_mtu)
self.lower_iface_mtu_checked_list.append(lower_iface)
else:
lower_iface_mtu = self.ipcmd.link_get_mtu(lower_iface)
if lower_iface_mtu != self.ipcmd.link_get_mtu_sysfs(ifaceobj.name):
self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
elif (not (ifaceobj.name == 'lo') and not ifaceobj.link_kind and
@@ -443,10 +611,143 @@ class address(moduleBase):
if running_mtu != self.default_mtu:
self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
def _set_bridge_forwarding(self, ifaceobj):
""" set ip forwarding to 0 if bridge interface does not have a
ip nor svi """
if not ifaceobj.upperifaces and not ifaceobj.get_attr_value('address'):
# set forwarding = 0
if self.sysctl_get('net.ipv4.conf.%s.forwarding' %ifaceobj.name) == '1':
self.sysctl_set('net.ipv4.conf.%s.forwarding' %ifaceobj.name, 0)
if self.sysctl_get('net.ipv6.conf.%s.forwarding' %ifaceobj.name) == '1':
self.sysctl_set('net.ipv6.conf.%s.forwarding' %ifaceobj.name, 0)
else:
if self.sysctl_get('net.ipv4.conf.%s.forwarding' %ifaceobj.name) == '0':
self.sysctl_set('net.ipv4.conf.%s.forwarding' %ifaceobj.name, 1)
if self.sysctl_get('net.ipv6.conf.%s.forwarding' %ifaceobj.name) == '0':
self.sysctl_set('net.ipv6.conf.%s.forwarding' %ifaceobj.name, 1)
def _sysctl_config(self, ifaceobj):
setting_default_value = False
mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
if not mpls_enable:
setting_default_value = True
mpls_enable = self.get_mod_subattr('mpls-enable', 'default')
mpls_enable = utils.boolean_support_binary(mpls_enable)
# File read has been used for better performance
# instead of using sysctl command
if ifupdownflags.flags.PERFMODE:
running_mpls_enable = '0'
else:
running_mpls_enable = self.read_file_oneline(
'/proc/sys/net/mpls/conf/%s/input'
% ifaceobj.name
)
if mpls_enable != running_mpls_enable:
try:
self.sysctl_set('net.mpls.conf.%s.input'
%('/'.join(ifaceobj.name.split("."))),
mpls_enable)
except Exception as e:
if not setting_default_value:
ifaceobj.status = ifaceStatus.ERROR
self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
if (ifaceobj.link_kind & ifaceLinkKind.BRIDGE):
self._set_bridge_forwarding(ifaceobj)
return
if not self.syntax_check_sysctls(ifaceobj):
return
ipforward = ifaceobj.get_attr_value_first('ip-forward')
ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
if ifupdownflags.flags.PERFMODE:
if ipforward:
self.sysctl_set('net.ipv4.conf.%s.forwarding'
%('/'.join(ifaceobj.name.split("."))),
utils.boolean_support_binary(ipforward))
if ip6forward:
self.sysctl_set('net.ipv6.conf.%s.forwarding'
%('/'.join(ifaceobj.name.split("."))),
utils.boolean_support_binary(ip6forward))
return
bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
if bridge_port:
if ipforward:
self.log_error('%s: \'ip-forward\' is not supported for '
'bridge port' %ifaceobj.name)
if ip6forward:
self.log_error('%s: \'ip6-forward\' is not supported for '
'bridge port' %ifaceobj.name)
return
setting_default_value = False
if not ipforward:
setting_default_value = True
ipforward = (self.ipforward or
self.get_mod_subattr('ip-forward', 'default'))
ipforward = utils.boolean_support_binary(ipforward)
# File read has been used for better performance
# instead of using sysctl command
running_ipforward = self.read_file_oneline(
'/proc/sys/net/ipv4/conf/%s/forwarding'
%ifaceobj.name)
if ipforward != running_ipforward:
try:
self.sysctl_set('net.ipv4.conf.%s.forwarding'
%('/'.join(ifaceobj.name.split("."))),
ipforward)
except Exception as e:
if not setting_default_value:
ifaceobj.status = ifaceStatus.ERROR
self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
setting_default_value = False
if not ip6forward:
setting_default_value = True
ip6forward = (self.ip6forward or
self.get_mod_subattr('ip6-forward', 'default'))
ip6forward = utils.boolean_support_binary(ip6forward)
# File read has been used for better performance
# instead of using sysctl command
running_ip6forward = self.read_file_oneline(
'/proc/sys/net/ipv6/conf/%s/forwarding'
%ifaceobj.name)
if ip6forward != running_ip6forward:
try:
self.sysctl_set('net.ipv6.conf.%s.forwarding'
%('/'.join(ifaceobj.name.split("."))),
ip6forward)
except Exception as e:
# There is chance of ipv6 being removed because of,
# for example, setting mtu < 1280
# In such cases, log error only if user has configured
# ip6-forward
if not setting_default_value:
ifaceobj.status = ifaceStatus.ERROR
self.logger.error('%s: %s' %(ifaceobj.name, str(e)))
def process_mtu(self, ifaceobj, ifaceobj_getfunc):
mtu = ifaceobj.get_attr_value_first('mtu')
if not mtu:
default_iface_mtu = self.ifaces_defaults.get(ifaceobj.name, {}).get('mtu')
if default_iface_mtu:
try:
mtu = default_iface_mtu
int(default_iface_mtu)
except Exception as e:
self.logger.warning('%s: MTU value from policy file: %s' % (ifaceobj.name, str(e)))
return
self._process_mtu_config(ifaceobj, ifaceobj_getfunc, mtu)
def _up(self, ifaceobj, ifaceobj_getfunc=None):
if not self.ipcmd.link_exists(ifaceobj.name):
return
if not self.syntax_check_enable_l3_iface_forwardings(ifaceobj, ifaceobj_getfunc):
return
alias = ifaceobj.get_attr_value_first('alias')
current_alias = self.ipcmd.link_get_alias(ifaceobj.name)
if alias and alias != current_alias:
@@ -454,11 +755,13 @@ class address(moduleBase):
elif not alias and current_alias:
self.ipcmd.link_set_alias(ifaceobj.name, '')
self._sysctl_config(ifaceobj)
addr_method = ifaceobj.addr_method
force_reapply = False
try:
# release any stale dhcp addresses if present
if (addr_method not in ["dhcp", "ppp"] and not ifupdownflags.flags.PERFMODE and
if (addr_method != "dhcp" and not ifupdownflags.flags.PERFMODE and
not (ifaceobj.flags & iface.HAS_SIBLINGS)):
# if not running in perf mode and ifaceobj does not have
# any sibling iface objects, kill any stale dhclient
@@ -475,10 +778,11 @@ class address(moduleBase):
pass
self.ipcmd.batch_start()
if addr_method not in ["dhcp", "ppp"]:
if addr_method != "dhcp":
self._inet_address_config(ifaceobj, ifaceobj_getfunc,
force_reapply)
self._process_mtu_config(ifaceobj, ifaceobj_getfunc)
self.process_mtu(ifaceobj, ifaceobj_getfunc)
try:
self.ipcmd.batch_commit()
@@ -513,36 +817,39 @@ class address(moduleBase):
except Exception, e:
self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
if addr_method not in ["dhcp", "ppp"]:
gateways = ifaceobj.get_attr_value('gateway')
if not gateways:
gateways = []
prev_gw = self._get_prev_gateway(ifaceobj, gateways)
self._add_delete_gateway(ifaceobj, gateways, prev_gw)
return
gateways = ifaceobj.get_attr_value('gateway')
if not gateways:
gateways = []
prev_gw = self._get_prev_gateway(ifaceobj, gateways)
self._add_delete_gateway(ifaceobj, gateways, prev_gw)
def _down(self, ifaceobj, ifaceobj_getfunc=None):
try:
if not self.ipcmd.link_exists(ifaceobj.name):
return
addr_method = ifaceobj.addr_method
if addr_method not in ["dhcp", "ppp"]:
if addr_method != "dhcp":
if ifaceobj.get_attr_value_first('address-purge')=='no':
addrlist = ifaceobj.get_attr_value('address')
for addr in addrlist:
self.ipcmd.addr_del(ifaceobj.name, addr)
#self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0])
else:
elif not ifaceobj.link_kind:
# for logical interfaces we don't need to remove the ip addresses
# kernel will do it for us on 'ip link del'
self.ipcmd.del_addr_all(ifaceobj.name)
gateways = ifaceobj.get_attr_value('gateway')
if gateways:
self._delete_gateway(ifaceobj, gateways,
ifaceobj.get_attr_value_first('vrf'),
ifaceobj.get_attr_value_first('metric'))
mtu = ifaceobj.get_attr_value_first('mtu')
if (not ifaceobj.link_kind and mtu and
self.default_mtu and (mtu != self.default_mtu)):
self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu)
alias = ifaceobj.get_attr_value_first('alias')
if alias:
filename = '/sys/class/net/%s/ifalias' %ifaceobj.name
self.logger.info('executing echo "" > %s' %filename)
os.system('echo "" > %s' %filename)
self.write_file('/sys/class/net/%s/ifalias' % ifaceobj.name, '\n')
# XXX hwaddress reset cannot happen because we dont know last
# address.
@@ -579,14 +886,62 @@ class address(moduleBase):
def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
""" If the device is a bridge, make sure the addresses
are in the bridge """
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
if self.ipcmd.bridge_is_vlan_aware(bridgename):
fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
if not fdb_addrs or hwaddress not in fdb_addrs:
return False
return True
def _query_sysctl(self, ifaceobj, ifaceobjcurr):
bridge_port = ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT
ipforward = ifaceobj.get_attr_value_first('ip-forward')
if ipforward:
if bridge_port:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = ('\'ip-forward\' not supported ' +
'for bridge port')
ifaceobjcurr.update_config_with_status('ip-forward', 1, None)
else:
running_ipforward = self.read_file_oneline(
'/proc/sys/net/ipv4/conf/%s/forwarding'
%ifaceobj.name)
running_ipforward = utils.get_onff_from_onezero(
running_ipforward)
ifaceobjcurr.update_config_with_status('ip-forward',
running_ipforward,
ipforward != running_ipforward)
ip6forward = ifaceobj.get_attr_value_first('ip6-forward')
if ip6forward:
if bridge_port:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = ('\'ip6-forward\' not supported ' +
'for bridge port')
ifaceobjcurr.update_config_with_status('ip6-forward', 1, None)
else:
running_ip6forward = self.read_file_oneline(
'/proc/sys/net/ipv6/conf/%s/forwarding'
%ifaceobj.name)
running_ip6forward = utils.get_onff_from_onezero(
running_ip6forward)
ifaceobjcurr.update_config_with_status('ip6-forward',
running_ip6forward,
ip6forward != running_ip6forward)
mpls_enable = ifaceobj.get_attr_value_first('mpls-enable');
if mpls_enable:
running_mpls_enable = self.read_file_oneline(
'/proc/sys/net/mpls/conf/%s/input'
%ifaceobj.name)
running_mpls_enable = utils.get_yesno_from_onezero(
running_mpls_enable)
ifaceobjcurr.update_config_with_status('mpls-enable',
running_mpls_enable,
mpls_enable != running_mpls_enable)
return
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
runningaddrsdict = None
if not self.ipcmd.link_exists(ifaceobj.name):
@@ -611,12 +966,13 @@ class address(moduleBase):
0)
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
'alias', self.ipcmd.link_get_alias)
self._query_sysctl(ifaceobj, ifaceobjcurr)
# compare addresses
if addr_method in ["dhcp", "ppp"]:
if addr_method == 'dhcp':
return
addrs = utils.get_normalized_ip_addr(ifaceobj.name,
self._get_iface_addresses(ifaceobj))
runningaddrsdict = self.ipcmd.addr_get(ifaceobj.name)
runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobj)
# if anycast address is configured on 'lo' and is in running config
# add it to addrs so that query_check doesn't fail
anycast_addr = utils.get_normalized_ip_addr(ifaceobj.name, ifaceobj.get_attr_value_first('clagd-vxlan-anycast-ip'))
@@ -680,7 +1036,7 @@ class address(moduleBase):
ifaceobjrunning.addr_method = 'loopback'
else:
default_addrs = []
runningaddrsdict = self.ipcmd.addr_get(ifaceobjrunning.name)
runningaddrsdict = self.ipcmd.get_running_addrs(ifaceobjrunning)
if runningaddrsdict:
[ifaceobjrunning.update_config('address', addr)
for addr, addrattrs in runningaddrsdict.items()
@@ -695,6 +1051,10 @@ class address(moduleBase):
if alias:
ifaceobjrunning.update_config('alias', alias)
ipforward = self.read_file_oneline(
'/proc/sys/net/ipv4/conf/%s/forwarding'
%ifaceobjrunning.name)
_run_ops = {'up' : _up,
'down' : _down,
@@ -707,7 +1067,7 @@ class address(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None):
""" run address configuration on the interface object passed as argument

View File

@@ -1,22 +1,36 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
import ifupdown.ifupdownconfig as ifupdownConfig
import ifupdown.statemanager as statemanager
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
from ipaddr import IPNetwork, IPv4Network
import logging
import os
import glob
from ipaddr import IPNetwork, IPv6Network
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
except ImportError:
from ifupdown.iface import *
from ifupdown.netlink import netlink
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.ifupdownconfig as ifupdownconfig
class addressvirtual(moduleBase):
""" ifupdown2 addon module to configure virtual addresses """
@@ -46,8 +60,9 @@ class addressvirtual(moduleBase):
def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
# XXX: batch the addresses
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
if self.ipcmd.bridge_is_vlan_aware(bridgename):
[self.ipcmd.bridge_fdb_add(bridgename, addr,
vlan) for addr in hwaddress]
@@ -57,8 +72,9 @@ class addressvirtual(moduleBase):
def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
# XXX: batch the addresses
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
if self.ipcmd.bridge_is_vlan_aware(bridgename):
for addr in hwaddress:
try:
@@ -86,23 +102,24 @@ class addressvirtual(moduleBase):
def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
""" If the device is a bridge, make sure the addresses
are in the bridge """
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if ifaceobj.link_kind & ifaceLinkKind.VLAN:
bridgename = ifaceobj.lowerifaces[0]
vlan = self._get_vlan_id(ifaceobj)
if self.ipcmd.bridge_is_vlan_aware(bridgename):
fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
fdb_addrs = self._get_bridge_fdbs(bridgename, str(vlan))
if not fdb_addrs or hwaddress not in fdb_addrs:
return False
return True
def _fix_connected_route(self, ifaceobj, vifacename, addr):
#
# XXX: Hack to make sure the primary address
# XXX: Hack to make sure the primary address
# is the first in the routing table.
#
# We use `ip route get` on the vrr network to see which
# device the kernel returns. if it is the mac vlan device,
# flap the macvlan device to adjust the routing table entry.
#
#
# flapping the macvlan device makes sure the macvlan
# connected route goes through delete + add, hence adjusting
# the order in the routing table.
@@ -110,10 +127,15 @@ class addressvirtual(moduleBase):
try:
self.logger.info('%s: checking route entry ...' %ifaceobj.name)
ip = IPNetwork(addr)
# we don't support ip6 route fix yet
if type(ip) == IPv6Network:
return
route_prefix = '%s/%d' %(ip.network, ip.prefixlen)
dev = self.ipcmd.ip_route_get_dev(route_prefix)
if dev and dev == vifacename:
if dev and dev != ifaceobj.name:
self.logger.info('%s: preferred routing entry ' %ifaceobj.name +
'seems to be of the macvlan dev %s'
%vifacename +
@@ -122,13 +144,13 @@ class addressvirtual(moduleBase):
self.ipcmd.link_up(vifacename)
except Exception, e:
self.logger.debug('%s: fixing route entry failed (%s)'
%str(e))
% (ifaceobj.name, str(e)))
pass
def _handle_vrf_slaves(self, macvlan_ifacename, ifaceobj):
vrfname = self.ipcmd.link_get_master(ifaceobj.name)
if vrfname:
netlink.link_set_master(macvlan_ifacename, vrfname)
self.ipcmd.link_set(macvlan_ifacename, 'master', vrfname)
def _get_macs_from_old_config(self, ifaceobj=None):
""" This method returns a list of the mac addresses
@@ -154,7 +176,7 @@ class addressvirtual(moduleBase):
purge_existing = False if ifupdownflags.flags.PERFMODE else True
lower_iface_mtu = update_mtu = None
if ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0':
if ifupdownconfig.config.get('adjust_logical_dev_mtu', '1') != '0':
if ifaceobj.lowerifaces and address_virtual_list:
update_mtu = True
@@ -179,15 +201,23 @@ class addressvirtual(moduleBase):
link_created = False
macvlan_ifacename = '%s%d' %(macvlan_prefix, av_idx)
if not self.ipcmd.link_exists(macvlan_ifacename):
netlink.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
try:
netlink.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
except:
self.ipcmd.link_add_macvlan(ifaceobj.name, macvlan_ifacename)
link_created = True
# first thing we need to handle vrf enslavement
if (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE):
self._handle_vrf_slaves(macvlan_ifacename, ifaceobj)
ips = av_attrs[1:]
if mac != 'None':
mac = mac.lower()
# customer could have used UPPERCASE for MAC
self.ipcmd.link_set_hwaddress(macvlan_ifacename, mac)
hwaddress.append(mac)
self.ipcmd.addr_add_multiple(macvlan_ifacename, ips,
self.ipcmd.addr_add_multiple(ifaceobj, macvlan_ifacename, ips,
purge_existing)
# If link existed before, flap the link
@@ -198,7 +228,7 @@ class addressvirtual(moduleBase):
lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.name, refresh=True)
update_mtu = False
if lower_iface_mtu and lower_iface_mtu != self.ipcmd.link_get_mtu(macvlan_ifacename):
if lower_iface_mtu and lower_iface_mtu != self.ipcmd.link_get_mtu(macvlan_ifacename, refresh=True):
try:
self.ipcmd.link_set_mtu(macvlan_ifacename,
lower_iface_mtu)
@@ -211,10 +241,11 @@ class addressvirtual(moduleBase):
# to bring them up here in the case they were brought down
# by some other entity in the system.
netlink.link_set_updown(macvlan_ifacename, "up")
# handle vrf slaves
if (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE):
self._handle_vrf_slaves(macvlan_ifacename, ifaceobj)
else:
try:
self.ipcmd.fix_ipv6_route_metric(ifaceobj, macvlan_ifacename, ips)
except Exception as e:
self.logger.debug('fix_vrf_slave_ipv6_route_metric: failed: %s' % e)
# Disable IPv6 duplicate address detection on VRR interfaces
for key, sysval in { 'accept_dad' : '0', 'dad_transmits' : '0' }.iteritems():
@@ -285,7 +316,7 @@ class addressvirtual(moduleBase):
def check_mac_address(self, ifaceobj, mac):
if mac == 'None':
return True
return True
mac = mac.lower()
try:
if int(mac.split(":")[0], 16) & 1 :
@@ -332,7 +363,8 @@ class addressvirtual(moduleBase):
# upper device list
if u == ifaceobj.name:
continue
netlink.link_set_master(u, ifaceobj.name, state='up')
self.ipcmd.link_set(u, 'master', ifaceobj.name,
state='up')
elif ((ifaceobj.link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE) and
(ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) and
self.ipcmd.link_exists(ifaceobj.name)):
@@ -352,7 +384,8 @@ class addressvirtual(moduleBase):
if u == vrfname:
continue
if u.startswith(macvlan_prefix):
netlink.link_set_master(u, vrfname, state='up')
self.ipcmd.link_set(u, 'master', vrfname,
state='up')
def _up(self, ifaceobj, ifaceobj_getfunc=None):
if not ifupdownflags.flags.ALL:
@@ -406,12 +439,15 @@ class addressvirtual(moduleBase):
continue
# Check mac and ip address
rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
raddrs = self.ipcmd.addr_get(macvlan_ifacename)
raddrs = self.ipcmd.get_running_addrs(
ifname=macvlan_ifacename,
details=False,
addr_virtual_ifaceobj=ifaceobj
)
if not raddrs or not rhwaddress:
ifaceobjcurr.update_config_with_status('address-virtual', '', 1)
av_idx += 1
continue
raddrs = raddrs.keys()
try:
av_attrs[0] = ':'.join([i if len(i) == 2 else '0%s' % i
for i in av_attrs[0].split(':')])
@@ -421,16 +457,9 @@ class addressvirtual(moduleBase):
macvlan_ifacename,
' '.join(av_attrs)))
try:
cmp_av_addr = av_attrs[1:][0]
cmp_raddr = raddrs[0]
if '/' in cmp_raddr and '/' not in cmp_av_addr:
cmp_av_addr = str(IPNetwork(cmp_av_addr))
elif '/' in cmp_av_addr and '/' not in cmp_raddr:
cmp_raddr = str(IPNetwork(cmp_raddr))
if (rhwaddress == av_attrs[0] and cmp_raddr == cmp_av_addr and
self._check_addresses_in_bridge(ifaceobj, av_attrs[0])):
if (rhwaddress == av_attrs[0].lower() and
self.ipcmd.compare_user_config_vs_running_state(raddrs, av_attrs[1:]) and
self._check_addresses_in_bridge(ifaceobj, av_attrs[0].lower())):
ifaceobjcurr.update_config_with_status('address-virtual',
address_virtual, 0)
else:
@@ -450,7 +479,7 @@ class addressvirtual(moduleBase):
for av in address_virtuals:
macvlan_ifacename = os.path.basename(av)
rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
raddress = self.ipcmd.addr_get(macvlan_ifacename)
raddress = self.ipcmd.get_running_addrs(None, macvlan_ifacename)
if not raddress:
self.logger.warn('%s: no running addresses'
%ifaceobjrunning.name)
@@ -470,7 +499,7 @@ class addressvirtual(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None, **extra_args):

773
ifupdown2/addons/bond.py Normal file
View File

@@ -0,0 +1,773 @@
#!/usr/bin/python
#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# Julien Fortin, julien@cumulusnetworks.com
#
import os
from sets import Set
try:
from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdown.statemanager import statemanager_api as statemanager
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
from nlmanager.nlmanager import Link
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.netlink import netlink
from ifupdown.statemanager import statemanager_api as statemanager
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
class bond(moduleBase):
""" ifupdown2 addon module to configure bond interfaces """
overrides_ifupdown_scripts = ['ifenslave', ]
_modinfo = { 'mhelp' : 'bond configuration module',
'attrs' : {
'bond-use-carrier':
{'help' : 'bond use carrier',
'validvals' : ['yes', 'no', '0', '1'],
'default' : 'yes',
'example': ['bond-use-carrier yes']},
'bond-num-grat-arp':
{'help' : 'bond use carrier',
'validrange' : ['0', '255'],
'default' : '1',
'example' : ['bond-num-grat-arp 1']},
'bond-num-unsol-na' :
{'help' : 'bond slave devices',
'validrange' : ['0', '255'],
'default' : '1',
'example' : ['bond-num-unsol-na 1']},
'bond-xmit-hash-policy' :
{'help' : 'bond slave devices',
'validvals' : ['0', 'layer2',
'1', 'layer3+4',
'2', 'layer2+3',
'3', 'encap2+3',
'4', 'encap3+4'],
'default' : 'layer2',
'example' : ['bond-xmit-hash-policy layer2']},
'bond-miimon' :
{'help' : 'bond miimon',
'validrange' : ['0', '255'],
'default' : '0',
'example' : ['bond-miimon 0']},
'bond-mode' :
{'help': 'bond mode',
'validvals': ['0', 'balance-rr',
'1', 'active-backup',
'2', 'balance-xor',
'3', 'broadcast',
'4', '802.3ad',
'5', 'balance-tlb',
'6', 'balance-alb'],
'default': 'balance-rr',
'example': ['bond-mode 802.3ad']},
'bond-lacp-rate':
{'help' : 'bond lacp rate',
'validvals' : ['0', 'slow', '1', 'fast'],
'default' : '0',
'example' : ['bond-lacp-rate 0']},
'bond-min-links':
{'help' : 'bond min links',
'default' : '0',
'validrange' : ['0', '255'],
'example' : ['bond-min-links 0']},
'bond-ad-sys-priority':
{'help' : '802.3ad system priority',
'default' : '65535',
'validrange' : ['0', '65535'],
'example' : ['bond-ad-sys-priority 65535'],
'deprecated' : True,
'new-attribute' : 'bond-ad-actor-sys-prio'},
'bond-ad-actor-sys-prio':
{'help' : '802.3ad system priority',
'default' : '65535',
'validrange' : ['0', '65535'],
'example' : ['bond-ad-actor-sys-prio 65535']},
'bond-ad-sys-mac-addr':
{'help' : '802.3ad system mac address',
'validvals': ['<mac>', ],
'example' : ['bond-ad-sys-mac-addr 00:00:00:00:00:00'],
'deprecated' : True,
'new-attribute' : 'bond-ad-actor-system'},
'bond-ad-actor-system':
{'help' : '802.3ad system mac address',
'validvals': ['<mac>', ],
'example' : ['bond-ad-actor-system 00:00:00:00:00:00'],},
'bond-lacp-bypass-allow':
{'help' : 'allow lacp bypass',
'validvals' : ['yes', 'no', '0', '1'],
'default' : 'no',
'example' : ['bond-lacp-bypass-allow no']},
'bond-slaves' :
{'help' : 'bond slaves',
'required' : True,
'multivalue' : True,
'validvals': ['<interface-list>'],
'example' : ['bond-slaves swp1 swp2',
'bond-slaves glob swp1-2',
'bond-slaves regex (swp[1|2)'],
'aliases': ['bond-ports']},
'bond-updelay' :
{'help' : 'bond updelay',
'default' : '0',
'validrange' : ['0', '65535'],
'example' : ['bond-updelay 100']},
'bond-downdelay':
{'help' : 'bond downdelay',
'default' : '0',
'validrange' : ['0', '65535'],
'example' : ['bond-downdelay 100']}
}}
_bond_attr_netlink_map = {
'bond-mode': Link.IFLA_BOND_MODE,
'bond-miimon': Link.IFLA_BOND_MIIMON,
'bond-use-carrier': Link.IFLA_BOND_USE_CARRIER,
'bond-lacp-rate': Link.IFLA_BOND_AD_LACP_RATE,
'bond-xmit-hash-policy': Link.IFLA_BOND_XMIT_HASH_POLICY,
'bond-min-links': Link.IFLA_BOND_MIN_LINKS,
'bond-num-grat-arp': Link.IFLA_BOND_NUM_PEER_NOTIF,
'bond-num-unsol-na': Link.IFLA_BOND_NUM_PEER_NOTIF,
'bond-ad-sys-mac-addr': Link.IFLA_BOND_AD_ACTOR_SYSTEM,
'bond-ad-actor-system': Link.IFLA_BOND_AD_ACTOR_SYSTEM,
'bond-ad-sys-priority': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
'bond-ad-actor-sys-prio': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
'bond-lacp-bypass-allow': Link.IFLA_BOND_AD_LACP_BYPASS,
'bond-updelay': Link.IFLA_BOND_UPDELAY,
'bond-downdelay': Link.IFLA_BOND_DOWNDELAY
}
# ifquery-check attr dictionary with callable object to translate user data to netlink format
_bond_attr_ifquery_check_translate_func = {
Link.IFLA_BOND_MODE: lambda x: Link.ifla_bond_mode_tbl[x],
Link.IFLA_BOND_MIIMON: int,
Link.IFLA_BOND_USE_CARRIER: utils.get_boolean_from_string,
Link.IFLA_BOND_AD_LACP_RATE: lambda x: int(utils.get_boolean_from_string(x)),
Link.IFLA_BOND_XMIT_HASH_POLICY: lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x],
Link.IFLA_BOND_MIN_LINKS: int,
Link.IFLA_BOND_NUM_PEER_NOTIF: int,
Link.IFLA_BOND_AD_ACTOR_SYSTEM: str,
Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: int,
Link.IFLA_BOND_AD_LACP_BYPASS: lambda x: int(utils.get_boolean_from_string(x)),
Link.IFLA_BOND_UPDELAY: int,
Link.IFLA_BOND_DOWNDELAY: int
}
# ifup attr list with callable object to translate user data to netlink format
# in the future this can be moved to a dictionary, whenever we detect that some
# netlink capabilities are missing we can dynamically remove them from the dict.
_bond_attr_set_list = (
('bond-mode', Link.IFLA_BOND_MODE, lambda x: Link.ifla_bond_mode_tbl[x]),
('bond-xmit-hash-policy', Link.IFLA_BOND_XMIT_HASH_POLICY, lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x]),
('bond-miimon', Link.IFLA_BOND_MIIMON, int),
('bond-min-links', Link.IFLA_BOND_MIN_LINKS, int),
('bond-num-grat-arp', Link.IFLA_BOND_NUM_PEER_NOTIF, int),
('bond-num-unsol-na', Link.IFLA_BOND_NUM_PEER_NOTIF, int),
('bond-ad-sys-priority', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int),
('bond-ad-actor-sys-prio', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int),
('bond-updelay', Link.IFLA_BOND_UPDELAY, int),
('bond-downdelay', Link.IFLA_BOND_DOWNDELAY, int),
('bond-use-carrier', Link.IFLA_BOND_USE_CARRIER, lambda x: int(utils.get_boolean_from_string(x))),
('bond-lacp-rate', Link.IFLA_BOND_AD_LACP_RATE, lambda x: int(utils.get_boolean_from_string(x))),
('bond-lacp-bypass-allow', Link.IFLA_BOND_AD_LACP_BYPASS, lambda x: int(utils.get_boolean_from_string(x))),
('bond-ad-sys-mac-addr', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
('bond-ad-actor-system', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
)
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self.bondcmd = None
if not os.path.exists('/sys/class/net/bonding_masters'):
utils.exec_command('modprobe -q bonding')
@staticmethod
def get_bond_slaves(ifaceobj):
slaves = ifaceobj.get_attr_value_first('bond-slaves')
if not slaves:
slaves = ifaceobj.get_attr_value_first('bond-ports')
return slaves
def _is_bond(self, ifaceobj):
# at first link_kind is not set but once ifupdownmain
# calls get_dependent_ifacenames link_kind is set to BOND
if ifaceobj.link_kind & ifaceLinkKind.BOND or self.get_bond_slaves(ifaceobj):
return True
return False
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
""" Returns list of interfaces dependent on ifaceobj """
if not self._is_bond(ifaceobj):
return None
slave_list = self.parse_port_list(ifaceobj.name,
self.get_bond_slaves(ifaceobj),
ifacenames_all)
ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
# Also save a copy for future use
ifaceobj.priv_data = list(slave_list)
if ifaceobj.link_type != ifaceLinkType.LINK_NA:
ifaceobj.link_type = ifaceLinkType.LINK_MASTER
ifaceobj.link_kind |= ifaceLinkKind.BOND
ifaceobj.role |= ifaceRole.MASTER
return slave_list
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
return self.syntax_check_updown_delay(ifaceobj)
def get_dependent_ifacenames_running(self, ifaceobj):
self._init_command_handlers()
return self.bondcmd.bond_get_slaves(ifaceobj.name)
def _get_slave_list(self, ifaceobj):
""" Returns slave list present in ifaceobj config """
# If priv data already has slave list use that first.
if ifaceobj.priv_data:
return ifaceobj.priv_data
slaves = self.get_bond_slaves(ifaceobj)
if slaves:
return self.parse_port_list(ifaceobj.name, slaves)
else:
return None
def _is_clag_bond(self, ifaceobj):
if self.get_bond_slaves(ifaceobj):
attrval = ifaceobj.get_attr_value_first('clag-id')
if attrval and attrval != '0':
return True
return False
def _add_slaves(self, ifaceobj, ifaceobj_getfunc=None):
runningslaves = []
slaves = self._get_slave_list(ifaceobj)
if not slaves:
self.logger.debug('%s: no slaves found' %ifaceobj.name)
return
if not ifupdownflags.flags.PERFMODE:
runningslaves = self.bondcmd.bond_get_slaves(ifaceobj.name)
clag_bond = self._is_clag_bond(ifaceobj)
for slave in Set(slaves).difference(Set(runningslaves)):
if (not ifupdownflags.flags.PERFMODE and
not self.ipcmd.link_exists(slave)):
self.log_error('%s: skipping slave %s, does not exist'
%(ifaceobj.name, slave), ifaceobj,
raise_error=False)
continue
link_up = False
if self.ipcmd.is_link_up(slave):
netlink.link_set_updown(slave, "down")
link_up = True
# If clag bond place the slave in a protodown state; clagd
# will protoup it when it is ready
if clag_bond:
try:
netlink.link_set_protodown(slave, "on")
except Exception, e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
netlink.link_set_master(slave, ifaceobj.name)
if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
try:
if (ifaceobj_getfunc(slave)[0].link_privflags &
ifaceLinkPrivFlags.KEEP_LINK_DOWN):
netlink.link_set_updown(slave, "down")
else:
netlink.link_set_updown(slave, "up")
except Exception, e:
self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
pass
if runningslaves:
for s in runningslaves:
if s not in slaves:
self.bondcmd.bond_remove_slave(ifaceobj.name, s)
if clag_bond:
try:
netlink.link_set_protodown(s, "off")
except Exception, e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
else:
# apply link-down config changes on running slaves
try:
link_up = self.ipcmd.is_link_up(s)
config_link_down = (ifaceobj_getfunc(s)[0].link_privflags &
ifaceLinkPrivFlags.KEEP_LINK_DOWN)
if (config_link_down and link_up):
netlink.link_set_updown(s, "down")
elif (not config_link_down and not link_up):
netlink.link_set_updown(s, "up")
except Exception, e:
self.logger.warn('%s: %s' % (ifaceobj.name, str(e)))
def _check_updown_delay_log(self, ifaceobj, attr_name, value):
ifaceobj.status = ifaceStatus.ERROR
self.logger.error('%s: unable to set %s %s as MII link monitoring is '
'disabled' % (ifaceobj.name, attr_name, value))
# return False to notify syntax_check that an error has been logged
return False
def syntax_check_updown_delay(self, ifaceobj):
result = True
updelay = ifaceobj.get_attr_value_first('bond-updelay')
downdelay = ifaceobj.get_attr_value_first('bond-downdelay')
if not updelay and not downdelay:
return True
try:
miimon = int(ifaceobj.get_attr_value_first('bond-miimon'))
except:
try:
miimon = int(policymanager.policymanager_api.get_iface_default(
module_name=self.__class__.__name__,
ifname=ifaceobj.name,
attr='bond-miimon'))
except:
miimon = 0
if not miimon:
# self._check_updown_delay_log returns False no matter what
if updelay and int(updelay):
result = self._check_updown_delay_log(ifaceobj, 'bond-updelay', updelay)
if downdelay and int(downdelay):
result = self._check_updown_delay_log(ifaceobj, 'bond-downdelay', downdelay)
return result
_bond_updown_delay_nl_list = (
(Link.IFLA_BOND_UPDELAY, 'bond-updelay'),
(Link.IFLA_BOND_DOWNDELAY, 'bond-downdelay')
)
def check_updown_delay_nl(self, link_exists, ifaceobj, ifla_info_data):
"""
IFLA_BOND_MIIMON
Specifies the time, in milliseconds, to wait before enabling a slave
after a link recovery has been detected. This option is only valid
for the miimon link monitor. The updelay value should be a multiple
of the miimon value; if not, it will be rounded down to the nearest
multiple. The default value is 0.
This ifla_bond_miimon code should be move to get_ifla_bond_attr_from_user_config
but we need to know if the operation was successful to update the cache accordingly
"""
ifla_bond_miimon = ifla_info_data.get(Link.IFLA_BOND_MIIMON)
if link_exists and ifla_bond_miimon is None:
ifla_bond_miimon = self.bondcmd.link_cache_get([ifaceobj.name, 'linkinfo', Link.IFLA_BOND_MIIMON])
if ifla_bond_miimon == 0:
for nl_attr, attr_name in self._bond_updown_delay_nl_list:
delay = ifla_info_data.get(nl_attr)
# if up-down-delay exists we need to remove it, if non zero log error
if delay is not None:
if delay > 0:
self._check_updown_delay_log(ifaceobj, attr_name, delay)
del ifla_info_data[nl_attr]
return True
return False
_bond_lacp_attrs = (
(Link.IFLA_BOND_AD_LACP_RATE, 'bond-lacp-rate'),
(Link.IFLA_BOND_AD_LACP_BYPASS, 'bond-lacp-bypass')
)
def _check_bond_mode_user_config(self, ifname, link_exists, ifla_info_data):
ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE)
if ifla_bond_mode is None and link_exists:
ifla_bond_mode = self.bondcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BOND_MODE])
# in this case the link already exists (we have a cached value):
# if IFLA_BOND_MODE is not present in ifla_info_data it means:
# - that bond-mode was present in the user config and didn't change
# - never was in the user config so bond mode should be the system default value
# - was removed from the stanza so we might have to reset it to default value
# nevertheless we need to add it back to the ifla_info_data dict to check
# if we need to reset the mode to system default
ifla_info_data[Link.IFLA_BOND_MODE] = ifla_bond_mode
if ifla_bond_mode == 4: # 802.3ad
min_links = ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS)
if min_links is None:
min_links = self.bondcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
# get_min_links_nl may return None so we need to strictly check 0
if min_links == 0:
self.logger.warn('%s: attribute bond-min-links is set to \'0\'' % ifname)
else:
# IFLA_BOND_AD_LACP_RATE and IFLA_BOND_AD_LACP_BYPASS only for 802.3ad mode (4)
for nl_attr, attr_name in self._bond_lacp_attrs:
if nl_attr in ifla_info_data:
self.logger.info('%s: ignoring %s: only available for 802.3ad mode (4)' % (ifname, attr_name))
del ifla_info_data[nl_attr]
@staticmethod
def get_saved_ifaceobj(link_exists, ifname):
if link_exists:
old_config = statemanager.get_ifaceobjs(ifname)
if old_config:
return old_config[0]
return None
def get_ifla_bond_attr_from_user_config(self, ifaceobj, link_exists):
"""
Potential issue: if a user load the bond driver with custom
default values (say bond-mode 3), ifupdown2 has no knowledge
of these default values.
At bond creation everything should work, bonds will be created
with mode 3 (even if not specified under the stanza).
But, for example: if the user specifies a value under bond-mode
and later on the user removes the bond-mode line from the stanza
we will detect it and reset to MODINFO: BOND-MODE: DEFAULT aka 0
which is not the real default value that the user may expect.
"""
ifname = ifaceobj.name
ifla_info_data = OrderedDict()
old_config = self.get_saved_ifaceobj(link_exists, ifname)
# for each bond attribute we fetch the user configuration
# if no configuration is provided we look for a config in policy files
for attr_name, netlink_attr, func_ptr in self._bond_attr_set_list:
cached_value = None
user_config = ifaceobj.get_attr_value_first(attr_name)
if not user_config:
user_config = policymanager.policymanager_api.get_iface_default(
module_name=self.__class__.__name__,
ifname=ifname,
attr=attr_name)
if user_config:
self.logger.debug('%s: %s %s: extracted from policy files'
% (ifname, attr_name, user_config))
# no policy override, do we need to reset an attr to default value?
if not user_config and old_config and old_config.get_attr_value_first(attr_name):
# if the link already exists but the value is set
# (potentially removed from the stanza, we need to reset it to default)
# might not work for specific cases, see explanation at the top of this function :)
user_config = self.get_attr_default_value(attr_name)
if user_config:
self.logger.debug('%s: %s: removed from stanza, resetting to default value: %s'
% (ifname, attr_name, user_config))
if user_config:
try:
nl_value = func_ptr(user_config.lower())
if link_exists:
cached_value = self.bondcmd.link_cache_get([ifname, 'linkinfo', netlink_attr])
if link_exists and cached_value is None:
# the link already exists but we don't have any value
# cached for this attr, it probably means that the
# capability is not available on this system (i.e old kernel)
self.logger.debug('%s: ignoring %s %s: capability '
'probably not supported on this system'
% (ifname, attr_name, user_config))
continue
elif link_exists:
# there should be a cached value if the link already exists
if cached_value == nl_value:
# if the user value is already cached: continue
continue
# else: the link doesn't exist so we create the bond with
# all the user/policy defined values without extra checks
ifla_info_data[netlink_attr] = nl_value
if cached_value is not None:
self.logger.info('%s: set %s %s (cache %s)' % (ifname, attr_name, user_config, cached_value))
else:
self.logger.info('%s: set %s %s' % (ifname, attr_name, user_config))
except KeyError:
self.logger.warning('%s: invalid %s value %s' % (ifname, attr_name, user_config))
self._check_bond_mode_user_config(ifname, link_exists, ifla_info_data)
return ifla_info_data
_bond_down_nl_attributes_list = (
Link.IFLA_BOND_MODE,
Link.IFLA_BOND_XMIT_HASH_POLICY,
Link.IFLA_BOND_AD_LACP_RATE,
Link.IFLA_BOND_MIN_LINKS
)
def _should_down_bond(self, ifla_info_data):
for nl_attr in self._bond_down_nl_attributes_list:
if nl_attr in ifla_info_data:
return True
return False
def should_update_bond_mode(self, ifaceobj, ifname, is_link_up, ifla_info_data):
# if bond-mode was changed the bond needs to be brought
# down and slaves un-slaved before bond mode is changed.
cached_bond_mode = self.bondcmd.link_cache_get([ifname, 'linkinfo', Link.IFLA_BOND_MODE])
ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE)
# bond-mode was changed or is not specified
if ifla_bond_mode is not None:
if ifla_bond_mode != cached_bond_mode:
self.logger.info('%s: bond mode changed to %s: running ops on bond and slaves'
% (ifname, ifla_bond_mode))
if is_link_up:
netlink.link_set_updown(ifname, 'down')
is_link_up = False
for lower_dev in ifaceobj.lowerifaces:
netlink.link_set_nomaster(lower_dev)
self.bondcmd.cache_delete([ifname, 'linkinfo', 'slaves'])
else:
# bond-mode user config value is the current running(cached) value
# no need to reset it again we can ignore this attribute
del ifla_info_data[Link.IFLA_BOND_MODE]
return is_link_up
def create_or_set_bond_config(self, ifaceobj):
ifname = ifaceobj.name
link_exists = self.ipcmd.link_exists(ifname)
is_link_up = self.ipcmd.is_link_up(ifname) if link_exists else False
ifla_info_data = self.get_ifla_bond_attr_from_user_config(ifaceobj, link_exists)
remove_delay_from_cache = self.check_updown_delay_nl(link_exists, ifaceobj, ifla_info_data)
# if link exists: down link if specific attributes are specified
if link_exists:
# did bond-mode changed?
is_link_up = self.should_update_bond_mode(ifaceobj, ifname, is_link_up, ifla_info_data)
# if specific attributes need to be set we need to down the bond first
if ifla_info_data and is_link_up:
if self._should_down_bond(ifla_info_data):
netlink.link_set_updown(ifname, 'down')
is_link_up = False
if link_exists and not ifla_info_data:
# if the bond already exists and no attrs need to be set
# ignore the netlink call
self.logger.info('%s: already exists, no change detected' % ifname)
else:
try:
netlink.link_add_set(kind='bond', ifname=ifname, ifla_info_data=ifla_info_data)
except Exception as e:
# defensive code
# if anything happens, we try to set up the bond with the sysfs api
self.logger.debug('%s: bond setup: %s' % (ifname, str(e)))
self.create_or_set_bond_config_sysfs(ifaceobj, ifla_info_data)
if remove_delay_from_cache:
# making sure up/down delay attributes are set to 0 before caching
# this can be removed when moving to a nllistener/live cache
ifla_info_data[Link.IFLA_BOND_UPDELAY] = 0
ifla_info_data[Link.IFLA_BOND_DOWNDELAY] = 0
# if link_add doesn't raise we can update the cache, the future
# netlink listener will update the cache based on the kernel response
for key, value in ifla_info_data.items():
self.bondcmd.cache_update([ifname, 'linkinfo', key], value)
if link_exists and ifla_info_data and not is_link_up:
netlink.link_set_updown(ifname, 'up')
def create_or_set_bond_config_sysfs(self, ifaceobj, ifla_info_data):
if not self.ipcmd.link_exists(ifaceobj.name):
self.bondcmd.create_bond(ifaceobj.name)
self.bondcmd.bond_set_attrs_nl(ifaceobj.name, ifla_info_data)
def _up(self, ifaceobj, ifaceobj_getfunc=None):
try:
self.create_or_set_bond_config(ifaceobj)
self._add_slaves(ifaceobj, ifaceobj_getfunc)
except Exception, e:
self.log_error(str(e), ifaceobj)
def _down(self, ifaceobj, ifaceobj_getfunc=None):
try:
netlink.link_del(ifaceobj.name)
self.bondcmd.cache_delete([ifaceobj.name])
except Exception as e:
self.log_warn('%s: %s' % (ifaceobj.name, str(e)))
def _query_check_bond_slaves(self, ifaceobjcurr, attr, user_bond_slaves, running_bond_slaves):
query = 1
if user_bond_slaves and running_bond_slaves:
if not set(user_bond_slaves).symmetric_difference(running_bond_slaves):
query = 0
# we want to display the same bond-slaves list as provided
# in the interfaces file but if this list contains regexes or
# globs, for now, we won't try to change it.
if 'regex' in user_bond_slaves or 'glob' in user_bond_slaves:
user_bond_slaves = running_bond_slaves
else:
ordered = []
for slave in user_bond_slaves:
if slave in running_bond_slaves:
ordered.append(slave)
user_bond_slaves = ordered
ifaceobjcurr.update_config_with_status(attr, ' '.join(user_bond_slaves) if user_bond_slaves else 'None', query)
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
if not self.bondcmd.bond_exists(ifaceobj.name):
self.logger.debug('bond iface %s does not exist' % ifaceobj.name)
return
iface_attrs = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs())
if not iface_attrs:
return
# remove bond-slaves and bond-ports from the list,
# because there aren't any ifla_info_data netlink attr for slaves
# an exception is raised when index is not found, so query_slaves will stay False
query_slaves = False
user_bond_slaves = None
running_bond_slaves = None
try:
del iface_attrs[iface_attrs.index('bond-slaves')]
# if user specified bond-slaves we need to display it
query_slaves = True
if not user_bond_slaves:
user_bond_slaves = self._get_slave_list(ifaceobj)
running_bond_slaves = self.bondcmd.bond_get_slaves(ifaceobj.name)
self._query_check_bond_slaves(ifaceobjcurr, 'bond-slaves', user_bond_slaves, running_bond_slaves)
except:
pass
try:
del iface_attrs[iface_attrs.index('bond-ports')]
# if user specified bond-ports we need to display it
if not query_slaves and not user_bond_slaves: # if get_slave_list was already called for slaves
user_bond_slaves = self._get_slave_list(ifaceobj)
running_bond_slaves = self.bondcmd.bond_get_slaves(ifaceobj.name)
self._query_check_bond_slaves(ifaceobjcurr, 'bond-ports', user_bond_slaves, running_bond_slaves)
except:
pass
for attr in iface_attrs:
nl_attr = self._bond_attr_netlink_map[attr]
translate_func = self._bond_attr_ifquery_check_translate_func[nl_attr]
current_config = self.bondcmd.link_cache_get([ifaceobj.name, 'linkinfo', nl_attr])
user_config = ifaceobj.get_attr_value_first(attr)
if current_config == translate_func(user_config):
ifaceobjcurr.update_config_with_status(attr, user_config, 0)
else:
ifaceobjcurr.update_config_with_status(attr, str(current_config), 1)
@staticmethod
def translate_nl_value_yesno(value):
return 'yes' if value else 'no'
@staticmethod
def translate_nl_value_slowfast(value):
return 'fast' if value else 'slow'
def _query_running_attrs(self, bondname):
bond_attrs = {
'bond-mode': Link.ifla_bond_mode_pretty_tbl.get(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])),
'bond-miimon': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON]),
'bond-use-carrier': self.translate_nl_value_yesno(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])),
'bond-lacp-rate': self.translate_nl_value_slowfast(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])),
'bond-min-links': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS]),
'bond-ad-actor-system': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM]),
'bond-ad-actor-sys-prio': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO]),
'bond-xmit-hash-policy': Link.ifla_bond_xmit_hash_policy_pretty_tbl.get(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])),
'bond-lacp-bypass-allow': self.translate_nl_value_yesno(self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])),
'bond-num-unsol-na': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF]),
'bond-num-grat-arp': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF]),
'bond-updelay': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY]),
'bond-downdelay': self.bondcmd.link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
}
slaves = self.bondcmd.bond_get_slaves(bondname)
if slaves:
bond_attrs['bond-slaves'] = slaves
return bond_attrs
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
if not self.bondcmd.bond_exists(ifaceobjrunning.name):
return
bond_attrs = self._query_running_attrs(ifaceobjrunning.name)
if bond_attrs.get('bond-slaves'):
bond_attrs['bond-slaves'] = ' '.join(bond_attrs.get('bond-slaves'))
[ifaceobjrunning.update_config(k, str(v))
for k, v in bond_attrs.items()
if v is not None]
_run_ops = {
'pre-up': _up,
'post-down': _down,
'query-running': _query_running,
'query-checkcurr': _query_check
}
def get_ops(self):
""" returns list of ops supported by this module """
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = self.bondcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None):
""" run bond configuration on the interface object passed as argument
Args:
**ifaceobj** (object): iface object
**operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
'query-running'
Kwargs:
**query_ifaceobj** (object): query check ifaceobject. This is only
valid when op is 'query-checkcurr'. It is an object same as
ifaceobj, but contains running attribute values and its config
status. The modules can use it to return queried running state
of interfaces. status is success if the running state is same
as user required state in ifaceobj. error otherwise.
"""
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if operation != 'query-running' and not self._is_bond(ifaceobj):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
else:
op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)

3146
ifupdown2/addons/bridge.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,24 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdownaddons.bridgeutils import brctl
from ipaddr import IPv4Address
import ifupdown.ifupdownflags as ifupdownflags
import logging
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.iface import *
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.ifupdownflags as ifupdownflags
class bridgevlan(moduleBase):
""" ifupdown2 addon module to configure vlan attributes on a vlan
@@ -71,7 +79,7 @@ class bridgevlan(moduleBase):
running_mcqv4src = {}
if not ifupdownflags.flags.PERFMODE:
running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src(bridgename)
if running_mcqv4src:
r_mcqv4src = running_mcqv4src.get(vlan)
else:
@@ -79,14 +87,14 @@ class bridgevlan(moduleBase):
mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
if not mcqv4src:
if r_mcqv4src:
self.brctlcmd.del_mcqv4src(bridgename, vlanid)
self.brctlcmd.bridge_del_mcqv4src(bridgename, vlanid)
return
if r_mcqv4src and r_mcqv4src != mcqv4src:
self.brctlcmd.del_mcqv4src(bridgename, vlanid)
self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
self.brctlcmd.bridge_del_mcqv4src(bridgename, vlanid)
self.brctlcmd.bridge_set_mcqv4src(bridgename, vlanid, mcqv4src)
else:
self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
self.brctlcmd.bridge_set_mcqv4src(bridgename, vlanid, mcqv4src)
def _down(self, ifaceobj):
try:
@@ -103,11 +111,11 @@ class bridgevlan(moduleBase):
return
mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
if mcqv4src:
self.brctlcmd.del_mcqv4src(bridgename, vlanid)
self.brctlcmd.bridge_del_mcqv4src(bridgename, vlanid)
def _query_running_bridge_igmp_querier_src(self, ifaceobj):
(bridgename, vlanid) = ifaceobj.name.split('.')
running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
running_mcqv4src = self.brctlcmd.bridge_get_mcqv4src(bridgename)
if running_mcqv4src:
return running_mcqv4src.get(vlanid)
return None
@@ -129,6 +137,15 @@ class bridgevlan(moduleBase):
# XXX not supported
return
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
ret = True
bvlan_intf = self._is_bridge_vlan_device(ifaceobj)
if (ifaceobj.get_attr_value_first('bridge-igmp-querier-src') and
not bvlan_intf):
self.logger.error('%s: bridge-igmp-querier-src only allowed under vlan stanza' %ifaceobj.name)
ret = False
return ret
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check,
@@ -140,9 +157,7 @@ class bridgevlan(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
if not self.brctlcmd:
self.brctlcmd = brctl()
self.ipcmd = self.brctlcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument
@@ -165,6 +180,14 @@ class bridgevlan(moduleBase):
return
if (operation != 'query-running' and
not self._is_bridge_vlan_device(ifaceobj)):
# most common problem is people specify BRIDGE_VLAN
# attribute on a bridge or a vlan device, which
# is incorrect. So, catch them here and warn before
# giving up processing the interface
if ((ifaceobj.link_kind & ifaceLinkKind.BRIDGE or
ifaceobj.link_kind & ifaceLinkKind.VLAN) and
not self.syntax_check(ifaceobj, None)):
ifaceobj.status = ifaceStatus.ERROR
return
self._init_command_handlers()
if operation == 'query-checkcurr':

View File

@@ -1,24 +1,33 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import re
import time
try:
import re
from ipaddr import IPNetwork
from sets import Set
from ifupdown.iface import *
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.dhclient import dhclient
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
import ifupdown.policymanager as policymanager
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.dhclient import dhclient
from ifupdownaddons.iproute2 import iproute2
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.iface import *
from ifupdown.utils import utils
import time
from ifupdown.netlink import netlink
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
from ifupdownaddons.dhclient import dhclient
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
class dhcp(moduleBase):
""" ifupdown2 addon module to configure dhcp on interface """
@@ -95,8 +104,8 @@ class dhcp(moduleBase):
timeout = 10
while timeout:
timeout -= 2
addr_output = utils.exec_command('ip -6 addr show %s'
% ifaceobj.name)
addr_output = utils.exec_command('%s -6 addr show %s'
%(utils.ip_cmd, ifaceobj.name))
r = re.search('inet6 .* scope link', addr_output)
if r:
self.dhclientcmd.start6(ifaceobj.name,
@@ -179,7 +188,7 @@ class dhcp(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run dhcp configuration on the interface object passed as argument
@@ -203,7 +212,7 @@ class dhcp(moduleBase):
return
try:
if (operation != 'query-running' and
(ifaceobj.addr_method != 'dhcp' and
(ifaceobj.addr_method != 'dhcp' and
ifaceobj.addr_method != 'dhcp6')):
return
except:

View File

@@ -1,24 +1,34 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import json
import ifupdown.policymanager as policymanager
import os
try:
import os
from ipaddr import IPNetwork
from sets import Set
from ifupdown.iface import *
from ifupdown.exceptions import moduleNotSupported
from ifupdown.utils import utils
from ifupdownaddons.utilsbase import *
from ifupdownaddons.modulebase import moduleBase, NotSupported
from ifupdownaddons.iproute2 import iproute2
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.policymanager as policymanager
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.exceptions import moduleNotSupported
from ifupdown2.ifupdownaddons.utilsbase import *
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
import ifupdown.ifupdownflags as ifupdownflags
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
import ifupdown.policymanager as policymanager
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.exceptions import moduleNotSupported
from ifupdownaddons.utilsbase import *
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
class ethtool(moduleBase,utilsBase):
""" ifupdown2 addon module to configure ethtool attributes """
@@ -49,128 +59,162 @@ class ethtool(moduleBase,utilsBase):
'link-fec' :
{'help': 'set forward error correction mode',
'example' : ['link-fec rs'],
'validvals' : ['rs', 'baser', 'on', 'off'],
'validvals' : ['rs', 'baser', 'auto', 'off'],
'default' : 'varies by platform and port'}}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
if not os.path.exists('/sbin/ethtool'):
raise moduleNotSupported('module init failed: no /sbin/ethtool found')
if not os.path.exists(utils.ethtool_cmd):
raise moduleNotSupported('module init failed: %s: not found' % utils.ethtool_cmd)
self.ipcmd = None
# keep a list of iface objects who have modified link attributes
self.ifaceobjs_modified_configs = []
def _post_up(self, ifaceobj, operation='post_up'):
"""
_post_up and _pre_down will reset the layer 2 attributes to default policy
settings.
"""
if not self.ipcmd.link_exists(ifaceobj.name):
return
cmd = ''
def do_fec_settings(self, ifaceobj):
feccmd = ''
for attr in ['speed', 'duplex', 'autoneg', 'fec']:
# attribute existed before but we must reset to default
config_val = ifaceobj.get_attr_value_first('link-%s'%attr)
default_val = policymanager.policymanager_api.get_iface_default(
module_name='ethtool',
ifname=ifaceobj.name,
attr='link-%s'%attr)
if not default_val and not config_val:
# there is no point in checking the running config
# if we have no default and the user did not have settings
continue
# check running values
running_val = self.get_running_attr(attr, ifaceobj)
# attribute existed before but we must reset to default
config_val = ifaceobj.get_attr_value_first('link-fec')
default_val = policymanager.policymanager_api.get_iface_default(
module_name='ethtool',
ifname=ifaceobj.name,
attr='link-fec')
if attr == 'autoneg':
config_val = utils.get_onoff_bool(config_val)
if not default_val and not config_val:
# there is no point in checking the running config
# if we have no default and the user did not have settings
return
# we need to track if an interface has a configured value
# this will be used if there are duplicate iface stanza and
# the configured interface will always take precedence.
# so even if we do not change the settings because they match
# what is configured, we need to append it here so that later duplicate
# ifaces will see that we had a configured iface and not change things.
if config_val and config_val == running_val:
# running value is what is configured, do nothing
# this prevents unconfigured ifaces from resetting to default
self.ifaceobjs_modified_configs.append(ifaceobj.name)
continue
# check running values
running_val = self.get_running_attr('fec', ifaceobj)
if config_val and config_val == running_val:
return
if not config_val and default_val and default_val == running_val:
# nothing configured but the default is running
continue
# if we are the oldest sibling, we have to reset to defaults
# unless a previous sibling had link attr configured and made changes
if ((ifaceobj.flags & iface.HAS_SIBLINGS) and
(ifaceobj.flags & iface.OLDEST_SIBLING) and
(ifaceobj.name in self.ifaceobjs_modified_configs)):
continue
if not config_val and default_val and default_val == running_val:
# nothing configured but the default is running
return
# If we have siblings AND are not the oldest AND we have no configs,
# do not change anything. The only way a non-oldest sibling would
# change values is if it had configured settings. iface stanzas may
# not be squashed if addr_config_squash is not set so we still need this.
if ((ifaceobj.flags & iface.HAS_SIBLINGS) and
not (ifaceobj.flags & iface.OLDEST_SIBLING) and
not config_val):
continue
if attr == 'fec':
# if we got this far, we need to change it
if config_val and (config_val != running_val):
# if the configured value is not set, set it
feccmd = ' %s %s' % ("encoding", config_val)
elif default_val and (default_val != running_val):
# or if it has a default not equal to running value, set it
feccmd = ' %s %s' % ("encoding", default_val)
else:
# no value set nor default, leave it alone
pass
else:
# if we got this far, we need to change it
if config_val and (config_val != running_val):
# if the configured value is not set, set it
cmd += ' %s %s' % (attr, config_val)
elif default_val and (default_val != running_val):
# or if it has a default not equal to running value, set it
cmd += ' %s %s' % (attr, default_val)
else:
# no value set nor default, leave it alone
pass
if cmd:
try:
# we should only be calling ethtool if there
# is a speed set or we can find a default speed
# because we should only be calling ethtool on swp ports
# we also need to set this here in case we changed
# something. this prevents unconfigured ifaces from resetting to default
self.ifaceobjs_modified_configs.append(ifaceobj.name)
cmd = 'ethtool -s %s %s' %(ifaceobj.name, cmd)
utils.exec_command(cmd)
except Exception, e:
self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
else:
pass
# if we got this far, we need to change it
if config_val and (config_val != running_val):
# if the configured value is not set, set it
feccmd = ' %s %s' % ("encoding", config_val)
elif default_val and (default_val != running_val):
# or if it has a default not equal to running value, set it
feccmd = ' %s %s' % ("encoding", default_val)
if feccmd:
try:
# we should only be calling ethtool if there
# is a speed set or we can find a default speed
# because we should only be calling ethtool on swp ports
# we also need to set this here in case we changed
# something. this prevents unconfigured ifaces from resetting to default
self.ifaceobjs_modified_configs.append(ifaceobj.name)
feccmd = 'ethtool --set-fec %s %s' %(ifaceobj.name, feccmd)
feccmd = ('%s --set-fec %s %s' %
(utils.ethtool_cmd, ifaceobj.name, feccmd))
utils.exec_command(feccmd)
except Exception, e:
self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
else:
pass
def do_speed_settings(self, ifaceobj, operation='post_up'):
cmd = ''
autoneg_to_configure = None
speed_to_configure = None
duplex_to_configure = None
config_speed = ifaceobj.get_attr_value_first('link-speed')
config_duplex = ifaceobj.get_attr_value_first('link-duplex')
config_autoneg = ifaceobj.get_attr_value_first('link-autoneg')
default_speed = policymanager.policymanager_api.get_iface_default(
module_name='ethtool',
ifname=ifaceobj.name,
attr='link-speed'
)
default_duplex = policymanager.policymanager_api.get_iface_default(
module_name='ethtool',
ifname=ifaceobj.name,
attr='link-duplex'
)
default_autoneg = policymanager.policymanager_api.get_iface_default(
module_name='ethtool',
ifname=ifaceobj.name,
attr='link-autoneg'
)
# autoneg wins if provided by user and is on
if config_autoneg and utils.get_boolean_from_string(config_autoneg):
autoneg_to_configure = config_autoneg
speed_to_configure = None
duplex_to_configure = None
elif config_speed:
# Any speed settings configured by the user wins
autoneg_to_configure = None
speed_to_configure = config_speed
duplex_to_configure = config_duplex
if not config_duplex:
duplex_to_configure = default_duplex
else:
# if user given autoneg config is off, we must respect that and
# override any default autoneg config
if config_autoneg and not utils.get_boolean_from_string(config_autoneg):
default_autoneg = 'off'
if default_autoneg and utils.get_boolean_from_string(default_autoneg):
autoneg_to_configure = utils.get_onoff_bool(default_autoneg)
speed_to_configure = None
duplex_to_configure = None
else:
autoneg_to_configure = None
speed_to_configure = default_speed
duplex_to_configure = default_duplex
if autoneg_to_configure:
autoneg_to_configure = utils.get_onoff_bool(autoneg_to_configure)
# check running values
running_val = self.get_running_attr('autoneg', ifaceobj)
if autoneg_to_configure != running_val:
# if the configured value is not set, set it
cmd += ' autoneg %s' % autoneg_to_configure
else:
force_set = False
if speed_to_configure:
# check running values
if utils.get_boolean_from_string(self.get_running_attr('autoneg', ifaceobj) or 'off'):
cmd = 'autoneg off'
# if we are transitioning from autoneg 'on' to 'off'
# don't check running speed
force_set = True
running_val = self.get_running_attr('speed', ifaceobj)
if force_set or (speed_to_configure != running_val):
# if the configured value is not set, set it
cmd += ' speed %s' % speed_to_configure
if duplex_to_configure:
# check running values
running_val = self.get_running_attr('duplex', ifaceobj)
if force_set or (duplex_to_configure != running_val):
# if the configured value is not set, set it
cmd += ' duplex %s' % duplex_to_configure
if cmd:
try:
cmd = ('%s -s %s %s' % (utils.ethtool_cmd, ifaceobj.name, cmd))
utils.exec_command(cmd)
except Exception, e:
self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj, raise_error=False)
def _pre_up(self, ifaceobj, operation='post_up'):
"""
_pre_up and _pre_down will reset the layer 2 attributes to default policy
settings.
"""
if not self.ipcmd.link_exists(ifaceobj.name):
return
self.do_speed_settings(ifaceobj)
self.do_fec_settings(ifaceobj)
def _pre_down(self, ifaceobj):
pass #self._post_up(ifaceobj,operation="_pre_down")
@@ -252,7 +296,7 @@ class ethtool(moduleBase,utilsBase):
for attr in ethtool_output.splitlines():
if attr.startswith('FEC encodings'):
fec_attrs = attr.split()
return(fec_attrs[fec_attrs.index(':')+1])
return(fec_attrs[fec_attrs.index(':')+1])
except Exception as e:
self.logger.debug('ethtool: problems in ethtool set-fec output'
' %s: %s' %(ethtool_output.splitlines(), str(e)))
@@ -265,10 +309,11 @@ class ethtool(moduleBase,utilsBase):
running_attr = None
try:
if attr == 'autoneg':
output = utils.exec_commandl(['ethtool', ifaceobj.name])
output = utils.exec_commandl([utils.ethtool_cmd, ifaceobj.name])
running_attr = self.get_autoneg(ethtool_output=output)
elif attr == 'fec':
output = utils.exec_command('ethtool --show-fec %s'%(ifaceobj.name))
output = utils.exec_command('%s --show-fec %s'%
(utils.ethtool_cmd, ifaceobj.name))
running_attr = self.get_fec_encoding(ethtool_output=output)
else:
running_attr = self.read_file_oneline('/sys/class/net/%s/%s' % \
@@ -330,7 +375,7 @@ class ethtool(moduleBase,utilsBase):
ifaceobj.update_config('link-%s' %attr, default)
_run_ops = {'pre-down' : _pre_down,
'post-up' : _post_up,
'pre-up' : _pre_up,
'query-checkcurr' : _query_check,
'query-running' : _query_running,
'query' : _query}
@@ -341,7 +386,7 @@ class ethtool(moduleBase,utilsBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run ethtool configuration on the interface object passed as

142
ifupdown2/addons/link.py Normal file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/python
#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# This should be pretty simple and might not really even need to exist.
# The key is that we need to call link_create with a type of "dummy"
# since that will translate to 'ip link add loopbackX type dummy'
# The config file should probably just indicate that the type is
# loopback or dummy.
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.policymanager as policymanager
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.policymanager as policymanager
class link(moduleBase):
_modinfo = {'mhelp' : 'create/configure link types. similar to ip-link',
'attrs' : {
'link-type' :
{'help' : 'type of link as in \'ip link\' command.',
'validvals' : ['dummy', 'veth'],
'example' : ['link-type <dummy|veth>']},
'link-down' :
{'help': 'keep link down',
'example' : ['link-down yes/no'],
'default' : 'no',
'validvals' : ['yes', 'no']}}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self.check_physical_port_existance = utils.get_boolean_from_string(policymanager.policymanager_api.get_module_globals(
self.__class__.__name__,
'warn_on_physdev_not_present'
))
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if self.check_physical_port_existance:
if not ifaceobj.link_kind and not LinkUtils.link_exists(ifaceobj.name):
self.logger.warning('%s: interface does not exist' % ifaceobj.name)
return False
return True
def _is_my_interface(self, ifaceobj):
if (ifaceobj.get_attr_value_first('link-type')
or ifaceobj.get_attr_value_first('link-down')):
return True
return False
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if ifaceobj.get_attr_value_first('link-down') == 'yes':
ifaceobj.link_privflags |= ifaceLinkPrivFlags.KEEP_LINK_DOWN
if ifaceobj.get_attr_value_first('link-type'):
ifaceobj.link_kind = ifaceLinkKind.OTHER
def _up(self, ifaceobj):
link_type = ifaceobj.get_attr_value_first('link-type')
if link_type:
self.ipcmd.link_create(ifaceobj.name,
ifaceobj.get_attr_value_first('link-type'))
def _down(self, ifaceobj):
if not ifaceobj.get_attr_value_first('link-type'):
return
if (not ifupdownflags.flags.PERFMODE and
not self.ipcmd.link_exists(ifaceobj.name)):
return
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr):
if ifaceobj.get_attr_value('link-type'):
if not self.ipcmd.link_exists(ifaceobj.name):
ifaceobjcurr.update_config_with_status('link-type', 'None', 1)
else:
link_type = ifaceobj.get_attr_value_first('link-type')
if self.ipcmd.link_get_kind(ifaceobj.name) == link_type:
ifaceobjcurr.update_config_with_status('link-type',
link_type, 0)
else:
ifaceobjcurr.update_config_with_status('link-type',
link_type, 1)
link_down = ifaceobj.get_attr_value_first('link-down')
if link_down:
link_up = self.ipcmd.is_link_up(ifaceobj.name)
link_should_be_down = utils.get_boolean_from_string(link_down)
if link_should_be_down and link_up:
status = 1
link_down = 'no'
elif link_should_be_down and not link_up:
status = 0
elif not link_should_be_down and link_up:
status = 0
else:
status = 1
ifaceobjcurr.update_config_with_status('link-down', link_down, status)
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check}
def get_ops(self):
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if (operation != 'query-running' and
not self._is_my_interface(ifaceobj)):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

View File

@@ -1,21 +1,38 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
from sets import Set
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.bridgeutils import brctl
from ifupdownaddons.iproute2 import iproute2
from ifupdown.netlink import netlink
from ifupdownaddons.mstpctlutil import mstpctlutil
from ifupdownaddons.systemutils import systemUtils
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.policymanager as policymanager
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.netlink import netlink
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.policymanager as policymanager
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
from ifupdown2.ifupdownaddons.mstpctlutil import mstpctlutil
from ifupdown2.ifupdownaddons.systemutils import systemUtils
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.policymanager as policymanager
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.mstpctlutil import mstpctlutil
from ifupdownaddons.systemutils import systemUtils
class mstpctlFlags:
PORT_PROCESSED = 0x1
@@ -57,20 +74,20 @@ class mstpctl(moduleBase):
{ 'help' : 'max message age',
'validrange' : ['0', '255'],
'default' : '20',
'jsonAttr': 'maxAge',
'jsonAttr': 'bridgeMaxAge',
'required' : False,
'example' : ['mstpctl-maxage 20']},
'mstpctl-fdelay' :
{ 'help' : 'set forwarding delay',
'validrange' : ['0', '255'],
'default' : '15',
'jsonAttr': 'fwdDelay',
'jsonAttr': 'bridgeFwdDelay',
'required' : False,
'example' : ['mstpctl-fdelay 15']},
'mstpctl-maxhops' :
{ 'help' : 'bridge max hops',
'validrange' : ['0', '255'],
'default' : '15',
'default' : '20',
'jsonAttr': 'maxHops',
'required' : False,
'example' : ['mstpctl-maxhops 15']},
@@ -132,11 +149,11 @@ class mstpctl(moduleBase):
'required' : False,
'example' : ['under the bridge: mstpctl-bpduguard swp1=yes swp2=no',
'under the port (recommended): mstpctl-bpduguard yes']},
'mstpctl-treeportprio' :
{ 'help' :
'port priority for MSTI instance',
'mstpctl-treeportprio' :
{ 'help': 'Sets the <port>\'s priority MSTI instance. '
'The priority value must be a number between 0 and 240 and a multiple of 16.',
'default' : '128',
'validvals': ['<interface-range-list>'],
'validvals': ['<interface-range-list-multiple-of-16>'],
'validrange' : ['0', '240'],
'jsonAttr': 'treeportprio',
'required' : False,
@@ -149,7 +166,7 @@ class mstpctl(moduleBase):
'required' : False,
'jsonAttr': 'helloTime',
'example' : ['mstpctl-hello 2']},
'mstpctl-portnetwork' :
'mstpctl-portnetwork' :
{ 'help' : 'enable/disable bridge assurance capability for a port',
'validvals' : ['<interface-yes-no-list>'],
'default' : 'no',
@@ -157,7 +174,7 @@ class mstpctl(moduleBase):
'required' : False,
'example' : ['under the bridge: mstpctl-portnetwork swp1=yes swp2=no',
'under the port (recommended): mstpctl-portnetwork yes']},
'mstpctl-portadminedge' :
'mstpctl-portadminedge' :
{ 'help' : 'enable/disable initial edge state of the port',
'validvals' : ['<interface-yes-no-list>'],
'default' : 'no',
@@ -165,7 +182,7 @@ class mstpctl(moduleBase):
'required' : False,
'example' : ['under the bridge: mstpctl-portadminedge swp1=yes swp2=no',
'under the port (recommended): mstpctl-portadminedge yes']},
'mstpctl-portautoedge' :
'mstpctl-portautoedge' :
{ 'help' : 'enable/disable auto transition to/from edge state of the port',
'validvals' : ['<interface-yes-no-list>'],
'default' : 'yes',
@@ -173,13 +190,13 @@ class mstpctl(moduleBase):
'required' : False,
'example' : ['under the bridge: mstpctl-portautoedge swp1=yes swp2=no',
'under the port (recommended): mstpctl-portautoedge yes']},
'mstpctl-treeportcost' :
'mstpctl-treeportcost' :
{ 'help' : 'port tree cost',
'validrange' : ['0', '255'],
'required' : False,
'jsonAttr': 'extPortCost',
},
'mstpctl-portbpdufilter' :
'mstpctl-portbpdufilter' :
{ 'help' : 'enable/disable bpdu filter on a port. ' +
'syntax varies when defined under a bridge ' +
'vs under a port',
@@ -224,11 +241,38 @@ class mstpctl(moduleBase):
self.mstpctlcmd = None
self.mstpd_running = (True if systemUtils.is_process_running('mstpd')
else False)
self.default_vxlan_ports_set_bpduparams = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='mstpctl-vxlan-always-set-bpdu-params')
if self.default_vxlan_ports_set_bpduparams == 'yes':
self.default_vxlan_ports_set_bpduparams = True
else:
self.default_vxlan_ports_set_bpduparams = False
# Background -
# The ask is to make "mstpctl-portadminedge yes" part of the default ifupdown2
# policy for all vxlan interfaces. In the absence of this, the mstp work flow
# is flawed in the event of vxlan flap.
# Details -
# As of today, for vxlan interfaces "oper edge port" is set to 'yes' and also
# "bpdufilter port" is also set to 'yes'. So, in a case where bridge has multiple
# vxlan interfaces, if one vxlan interface is flapped, this would trigger mstp
# re-evaluation of states on other vxlan interfaces, creating momentary traffic
# glitch on those vxlans. Setting "admin edge port" to yes (in addition to the
# defaults we already have) prevents this.
#
# We use to only support 'mstpctl-vxlan-always-set-bpdu-params' but introducing a
# separate policy attribute doesn't make sense, we should have one single
# attribute to handle the whole thing (and deprecate mstpctl-vxlan-always-set-bpdu-params)
# mstpctl-set-default-vxlan-bridge-attrs=yes will set
# mstpctl-portbpdufilter
# mstpctl-bpduguard
# mstpctl-portadminedge
#
self.set_default_mstp_vxlan_bridge_config = utils.get_boolean_from_string(
policymanager.policymanager_api.get_module_globals(
module_name=self.__class__.__name__,
attr='mstpctl-vxlan-always-set-bpdu-params'
)
) or utils.get_boolean_from_string(
policymanager.policymanager_api.get_module_globals(
module_name=self.__class__.__name__,
attr='mstpctl-set-default-vxlan-bridge-attrs'
)
)
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if self._is_bridge(ifaceobj):
@@ -303,7 +347,7 @@ class mstpctl(moduleBase):
if not ifupdownflags.flags.PERFMODE:
runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
if runningbridgeports:
[netlink.link_set_nomaster(bport)
[self.ipcmd.link_set(bport, 'nomaster')
for bport in runningbridgeports
if not bridgeports or bport not in bridgeports]
else:
@@ -319,7 +363,7 @@ class mstpctl(moduleBase):
%(ifaceobj.name, bridgeport))
err += 1
continue
netlink.link_set_master(bridgeport, ifaceobj.name)
self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
self.ipcmd.addr_flush(bridgeport)
except Exception, e:
self.log_error(str(e), ifaceobj)
@@ -327,7 +371,7 @@ class mstpctl(moduleBase):
if err:
self.log_error('error configuring bridge (missing ports)')
def _apply_bridge_settings(self, ifaceobj):
def _apply_bridge_settings(self, ifaceobj, ifaceobj_getfunc):
check = False if ifupdownflags.flags.PERFMODE else True
try:
# set bridge attributes
@@ -335,8 +379,8 @@ class mstpctl(moduleBase):
config_val = ifaceobj.get_attr_value_first(attrname)
default_val = policymanager.policymanager_api.get_iface_default(module_name=self.__class__.__name__, ifname=ifaceobj.name, attr=attrname)
if not default_val:
default_val = self.get_mod_subattr(attrname,'default')
jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
default_val = self.get_mod_subattr(attrname, 'default')
jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
try:
running_val = self.mstpctlcmd.get_bridge_attr(
ifaceobj.name, jsonAttr)
@@ -378,12 +422,18 @@ class mstpctl(moduleBase):
for port in bridgeports:
if not self.brctlcmd.is_bridge_port(port):
continue
bport_ifaceobj = ifaceobj_getfunc(port)
if bport_ifaceobj:
default_val = self._get_default_val(attrname, bport_ifaceobj[0], ifaceobj)
self.mstpctlcmd.set_bridge_port_attr(ifaceobj.name,
port,
dstattrname,
default_val,
json_attr=jsonAttr)
except:
except Exception as e:
self.logger.debug('%s' % str(e))
self.logger.info('%s: not resetting %s config'
%(ifaceobj.name, attrname))
# leave the loop for this attribute
@@ -417,10 +467,14 @@ class mstpctl(moduleBase):
pass
def _get_default_val(self, attr, ifaceobj, bridgeifaceobj):
if ((attr == 'mstpctl-portbpdufilter' or
attr == 'mstpctl-bpduguard') and
self.default_vxlan_ports_set_bpduparams and
(ifaceobj.link_kind & ifaceLinkKind.VXLAN)):
if (self.set_default_mstp_vxlan_bridge_config
and ifaceobj.link_kind & ifaceLinkKind.VXLAN
and attr in (
'mstpctl-portbpdufilter',
'mstpctl-bpduguard',
'mstpctl-portadminedge',
)
):
try:
config_val = bridgeifaceobj.get_attr_value_first(attr)
except Exception, e:
@@ -459,10 +513,13 @@ class mstpctl(moduleBase):
not os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name) or
not bvlan_aware):
if (not bvlan_aware and
self.default_vxlan_ports_set_bpduparams and
self.set_default_mstp_vxlan_bridge_config and
(ifaceobj.link_kind & ifaceLinkKind.VXLAN)):
for attr in ['mstpctl-portbpdufilter',
'mstpctl-bpduguard']:
for attr in (
'mstpctl-portbpdufilter',
'mstpctl-bpduguard',
'mstpctl-portadminedge'
):
json_attr = self.get_mod_subattr(attr, 'jsonAttr')
config_val = self._get_default_val(attr, ifaceobj,
bridgeifaceobj)
@@ -475,10 +532,32 @@ class mstpctl(moduleBase):
except Exception, e:
self.log_warn('%s: error setting %s (%s)'
% (ifaceobj.name, attr, str(e)))
if not bvlan_aware:
# for "traditional" bridges we also want to let the user configure
# some attributes (possibly all of them in the future)
applied = self._apply_bridge_port_settings_attributes_list(
(
('mstpctl-portrestrrole', 'portrestrrole'),
('mstpctl-portautoedge', 'portautoedge')
),
ifaceobj,
bridgeifaceobj,
bridgename,
applied
)
return applied
# set bridge port attributes
for attrname, dstattrname in self._port_attrs_map.items():
attrval = ifaceobj.get_attr_value_first(attrname)
return self._apply_bridge_port_settings_attributes_list(
self._port_attrs_map.items(),
ifaceobj,
bridgeifaceobj,
bridgename,
applied
)
def _apply_bridge_port_settings_attributes_list(self, attributes_list, ifaceobj, bridgeifaceobj, bridgename, applied):
for attrname, dstattrname in attributes_list:
config_val = ifaceobj.get_attr_value_first(attrname)
default_val = self._get_default_val(attrname, ifaceobj, bridgeifaceobj)
jsonAttr = self.get_mod_subattr(attrname, 'jsonAttr')
@@ -595,12 +674,12 @@ class mstpctl(moduleBase):
stp = ifaceobj.get_attr_value_first('mstpctl-stp')
if stp:
self.set_iface_attr(ifaceobj, 'mstpctl-stp',
self.brctlcmd.set_stp)
self.brctlcmd.bridge_set_stp)
else:
stp = self.brctlcmd.get_stp(ifaceobj.name)
stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
if (self.mstpd_running and
(stp == 'yes' or stp == 'on')):
self._apply_bridge_settings(ifaceobj)
self._apply_bridge_settings(ifaceobj, ifaceobj_getfunc)
self._apply_bridge_port_settings_all(ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
except Exception, e:
@@ -691,7 +770,7 @@ class mstpctl(moduleBase):
return utils.get_boolean_from_string(stp)
def _get_running_stp(self, ifaceobj):
stp = self.brctlcmd.get_stp(ifaceobj.name)
stp = self.brctlcmd.bridge_get_stp(ifaceobj.name)
return utils.get_boolean_from_string(stp)
def _query_check_bridge(self, ifaceobj, ifaceobjcurr,
@@ -704,8 +783,8 @@ class mstpctl(moduleBase):
return
ifaceattrs = self.dict_key_subset(ifaceobj.config,
self.get_mod_attrs())
if self.default_vxlan_ports_set_bpduparams:
for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']:
if self.set_default_mstp_vxlan_bridge_config:
for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
if attr not in ifaceattrs:
ifaceattrs.append(attr)
if not ifaceattrs:
@@ -721,8 +800,7 @@ class mstpctl(moduleBase):
# for all mstpctl options
if k in blacklistedattrs:
continue
if ((k == 'mstpctl-portbpdufilter' or
k == 'mstpctl-bpduguard')):
if k in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
#special case, 'ifquery --check --with-defaults' on a VLAN
#unaware bridge
if not running_port_list:
@@ -788,7 +866,7 @@ class mstpctl(moduleBase):
# contain more than one valid values
stp_on_vals = ['on', 'yes']
stp_off_vals = ['off']
rv = self.brctlcmd.get_stp(ifaceobj.name)
rv = self.brctlcmd.bridge_get_stp(ifaceobj.name)
if ((v in stp_on_vals and rv in stp_on_vals) or
(v in stp_off_vals and rv in stp_off_vals)):
ifaceobjcurr.update_config_with_status('mstpctl-stp', v, 0)
@@ -855,14 +933,17 @@ class mstpctl(moduleBase):
bifaceobjlist = ifaceobj_getfunc(bridge)
for bifaceobj in bifaceobjlist:
if (self._is_bridge(bifaceobj) and
self.default_vxlan_ports_set_bpduparams and
self.set_default_mstp_vxlan_bridge_config and
(bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
config_stp = self._get_config_stp(bifaceobj)
running_stp = self._get_running_stp(bifaceobj)
if (not config_stp or not running_stp):
continue
for attr in ['mstpctl-portbpdufilter',
'mstpctl-bpduguard']:
for attr in (
'mstpctl-portbpdufilter',
'mstpctl-bpduguard',
'mstpctl-portadminedge'
):
jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
config_val = bifaceobj.get_attr_value_first(attr)
if config_val:
@@ -954,7 +1035,7 @@ class mstpctl(moduleBase):
self.logger.warn('%s: unable to determine bridgename'
%ifaceobjrunning.name)
return
if self.brctlcmd.get_stp(bridgename) == 'no':
if self.brctlcmd.bridge_get_stp(bridgename) == 'no':
# This bridge does not run stp, return
return
# if userspace stp not set, return
@@ -1013,7 +1094,7 @@ class mstpctl(moduleBase):
# portconfig['mstpctl-treeportcost'] += ' %s=%s' %(p, v)
def _query_running_bridge(self, ifaceobjrunning):
if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
if self.brctlcmd.bridge_get_stp(ifaceobjrunning.name) == 'no':
# This bridge does not run stp, return
return
# if userspace stp not set, return
@@ -1072,10 +1153,11 @@ class mstpctl(moduleBase):
for bridge in masters:
bifaceobj = ifaceobj_getfunc(bridge)[0]
if (self._is_bridge(bifaceobj) and
self.default_vxlan_ports_set_bpduparams and
self.set_default_mstp_vxlan_bridge_config and
(bifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE)):
for attr in ['mstpctl-portbpdufilter',
'mstpctl-bpduguard']:
for attr in ('mstpctl-portbpdufilter',
'mstpctl-bpduguard',
'mstpctl-portadminedge'):
jsonAttr = self.get_mod_subattr(attr, 'jsonAttr')
config_val = ifaceobj.get_attr_value_first(attr)
if config_val or not ifupdownflags.flags.WITHDEFAULTS:
@@ -1102,7 +1184,7 @@ class mstpctl(moduleBase):
if not lowerinfs:
return
if ifaceobj.get_attr_value_first('bridge-vlan-aware') != 'yes':
for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']:
for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
state = ''
config = ifaceobj.get_attr_value_first(attr)
for port in lowerinfs:
@@ -1116,7 +1198,7 @@ class mstpctl(moduleBase):
state += '%s=yes ' %port
ifaceobj.replace_config(attr, config if config else state)
else:
for attr in ['mstpctl-portbpdufilter', 'mstpctl-bpduguard']:
for attr in ('mstpctl-portbpdufilter', 'mstpctl-bpduguard', 'mstpctl-portadminedge'):
state = ''
config = ifaceobj.get_attr_value_first(attr)
for port in lowerinfs:
@@ -1158,9 +1240,7 @@ class mstpctl(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
if not self.brctlcmd:
self.brctlcmd = brctl()
self.ipcmd = self.brctlcmd = LinkUtils()
if not self.mstpctlcmd:
self.mstpctlcmd = mstpctlutil()

View File

@@ -1,16 +1,22 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
import ifupdownaddons
from ifupdown.utils import utils
import ifupdown.ifupdownflags as ifupdownflags
try:
from ifupdown2.ifupdown.utils import utils
class usercmds(ifupdownaddons.modulebase.moduleBase):
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
class usercmds(moduleBase):
""" ifupdown2 addon module to configure user specified commands """
_modinfo = {'mhelp' : 'user commands for interfaces',

View File

@@ -1,18 +1,27 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
import ifupdown.ifupdownconfig as ifupdownConfig
try:
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.iface import *
from ifupdown.netlink import netlink
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
import logging
import re
class vlan(moduleBase):
""" ifupdown2 addon module to configure vlans """
@@ -28,16 +37,18 @@ class vlan(moduleBase):
'validvals': ['<interface>']},
'vlan-id' :
{'help' : 'vlan id',
'validrange' : ['0', '4096']}}}
'validrange' : ['0', '4096']},
'vlan-protocol' :
{'help' : 'vlan protocol',
'default' : '802.1q',
'validvals': ['802.1q', '802.1ad'],
'example' : ['vlan-protocol 802.1q']},
}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self._bridge_vids_query_cache = {}
self._resv_vlan_range = self._get_reserved_vlan_range()
self.logger.debug('%s: using reserved vlan range %s'
%(self.__class__.__name__, str(self._resv_vlan_range)))
def _is_vlan_device(self, ifaceobj):
vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
@@ -47,34 +58,6 @@ class vlan(moduleBase):
return True
return False
def _get_vlan_id(self, ifaceobj):
""" Derives vlanid from iface name
Example:
Returns 1 for ifname vlan0001 returns 1
Returns 1 for ifname vlan1
Returns 1 for ifname eth0.1
Returns -1 if vlan id cannot be determined
"""
vid_str = ifaceobj.get_attr_value_first('vlan-id')
try:
if vid_str: return int(vid_str)
except:
return -1
if '.' in ifaceobj.name:
vid_str = ifaceobj.name.split('.', 1)[1]
elif ifaceobj.name.startswith('vlan'):
vid_str = ifaceobj.name[4:]
else:
return -1
try:
vid = int(vid_str)
except:
return -1
return vid
def _is_vlan_by_name(self, ifacename):
return '.' in ifacename
@@ -82,13 +65,15 @@ class vlan(moduleBase):
""" Returns vlan raw device from ifname
Example:
Returns eth0 for ifname eth0.100
Returns eth0.100 for ifname eth0.100.200
Returns None if vlan raw device name cannot
be determined
"""
vlist = ifacename.split('.', 1)
vlist = ifacename.split('.', 2)
if len(vlist) == 2:
return vlist[0]
elif len(vlist) == 3:
return vlist[0] + "." + vlist[1]
return None
def _get_vlan_raw_device(self, ifaceobj):
@@ -118,10 +103,7 @@ class vlan(moduleBase):
is configured on the bridge """
if not self.ipcmd.bridge_is_vlan_aware(bridgename):
return
vids = self._bridge_vids_query_cache.get(bridgename)
if vids == None:
vids = self.ipcmd.bridge_port_vids_get(bridgename)
self._bridge_vids_query_cache[bridgename] = vids
vids = self.ipcmd.bridge_vlan_get_vids(bridgename)
if not vids or vlanid not in vids:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = 'bridge vid error'
@@ -133,13 +115,27 @@ class vlan(moduleBase):
vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
if not vlanrawdevice:
raise Exception('could not determine vlan raw device')
vlan_protocol = ifaceobj.get_attr_value_first('vlan-protocol')
cached_vlan_protocol = self.ipcmd.get_vlan_protocol(ifaceobj.name)
if not vlan_protocol:
vlan_protocol = self.get_attr_default_value('vlan-protocol')
if cached_vlan_protocol and vlan_protocol.lower() != cached_vlan_protocol.lower():
raise Exception('%s: cannot change vlan-protocol to %s: operation not supported. '
'Please delete the device with \'ifdown %s\' and recreate it to '
'apply the change.'
% (ifaceobj.name, vlan_protocol, ifaceobj.name))
if not ifupdownflags.flags.PERFMODE:
if not self.ipcmd.link_exists(vlanrawdevice):
raise Exception('rawdevice %s not present' %vlanrawdevice)
if self.ipcmd.link_exists(ifaceobj.name):
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
return
netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid)
netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol)
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
def _down(self, ifaceobj):
@@ -163,7 +159,7 @@ class vlan(moduleBase):
return
if not '.' in ifaceobj.name:
# if vlan name is not in the dot format, check its running state
(vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
(vlanrawdev, vlanid, protocol) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
ifaceobjcurr.update_config_with_status('vlan-raw-device',
vlanrawdev, 1)
@@ -177,20 +173,29 @@ class vlan(moduleBase):
ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
else:
ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 0)
self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
protocol_config = ifaceobj.get_attr_value_first('vlan-protocol')
if protocol_config:
if protocol_config.upper() != protocol.upper():
ifaceobjcurr.update_config_with_status('vlan-protocol',
protocol, 1)
else:
ifaceobjcurr.update_config_with_status('vlan-protocol',
protocol, 0)
self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, int(vlanid))
def _query_running(self, ifaceobjrunning):
if not self.ipcmd.link_exists(ifaceobjrunning.name):
return
(vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
(vlanrawdev, vlanid, protocol) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
if not vlanid:
return
# If vlan name is not in the dot format, get the
# vlan dev and vlan id
if not '.' in ifaceobjrunning.name:
ifaceobjrunning.update_config_dict({(k, v) for k, v in
ifaceobjrunning.update_config_dict({k: [v] for k, v in
{'vlan-raw-device' : vlanrawdev,
'vlan-id' : vlanid}.items()
'vlan-id' : vlanid,
'vlan-protocol' : protocol}.items()
if v})
_run_ops = {'pre-up' : _up,
@@ -204,7 +209,7 @@ class vlan(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument

View File

@@ -1,27 +1,42 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import re
import os
import signal
import errno
import fcntl
import atexit
import re
import signal
from sets import Set
from ifupdown.iface import *
from ifupdown.utils import utils
import ifupdown.policymanager as policymanager
import ifupdownaddons
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.bondutil import bondutil
from ifupdownaddons.iproute2 import iproute2
from ifupdownaddons.dhclient import dhclient
from ifupdownaddons.utilsbase import *
try:
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.dhclient import dhclient
from ifupdown2.ifupdownaddons.utilsbase import *
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.netlink import netlink
from ifupdownaddons.dhclient import dhclient
from ifupdownaddons.utilsbase import *
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
class vrfPrivFlags:
PROCESSED = 0x1
@@ -49,17 +64,19 @@ class vrf(moduleBase):
VRF_TABLE_START = 1001
VRF_TABLE_END = 5000
system_reserved_rt_tables = {'255' : 'local', '254' : 'main',
system_reserved_rt_tables = {'255' : 'local', '254' : 'main',
'253' : 'default', '0' : 'unspec'}
def __init__(self, *args, **kargs):
ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs)
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self.bondcmd = None
self.dhclientcmd = None
self.name = self.__class__.__name__
self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname')
self.user_reserved_vrf_table = []
if (ifupdownflags.flags.PERFMODE and
not (self.vrf_mgmt_devname and os.path.exists('/sys/class/net/%s'
%self.vrf_mgmt_devname))):
@@ -79,14 +96,16 @@ class vrf(moduleBase):
self.logger.debug('vrf: removing file failed (%s)'
%str(e))
try:
ip_rules = utils.exec_command('/sbin/ip rule show').splitlines()
ip_rules = utils.exec_command('%s rule show'
%utils.ip_cmd).splitlines()
self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
except Exception, e:
self.ip_rule_cache = []
self.logger.warn('vrf: cache v4: %s' % str(e))
try:
ip_rules = utils.exec_command('/sbin/ip -6 rule show').splitlines()
ip_rules = utils.exec_command('%s -6 rule show'
%utils.ip_cmd).splitlines()
self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
except Exception, e:
self.ip6_rule_cache = []
@@ -118,6 +137,12 @@ class vrf(moduleBase):
self.vrf_table_id_end = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-table-id-end')
if not self.vrf_table_id_end:
self.vrf_table_id_end = self.VRF_TABLE_END
self._modinfo['attrs']['vrf-table']['validrange'] = [
str(self.vrf_table_id_start),
str(self.vrf_table_id_end)
]
self.vrf_max_count = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-max-count')
self.vrf_fix_local_table = True
@@ -126,6 +151,40 @@ class vrf(moduleBase):
self.vrf_close_socks_on_down = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-close-socks-on-down')
self.warn_on_vrf_map_write_err = True
def _check_vrf_table_id(self, ifaceobj):
vrf_table = ifaceobj.get_attr_value_first('vrf-table')
if not vrf_table:
return False
if (vrf_table != 'auto' and
(int(vrf_table) < self.vrf_table_id_start or
int(vrf_table) > self.vrf_table_id_end)):
self.logger.error('%s: vrf table id %s out of reserved range [%d,%d]'
%(ifaceobj.name,
vrf_table,
self.vrf_table_id_start,
self.vrf_table_id_end))
return False
return True
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if ifaceobj.link_kind & ifaceLinkKind.VRF:
try:
check_vrf_table_id = self._check_vrf_table_id(ifaceobj)
check_vrf_sys_names = self._check_vrf_system_reserved_names(ifaceobj)
return check_vrf_table_id and check_vrf_sys_names
except Exception as e:
self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
return False
return True
def _check_vrf_system_reserved_names(self, ifaceobj):
system_reserved_names = self.system_reserved_rt_tables.values()
if ifaceobj.name in system_reserved_names:
self.log_error('cannot use system reserved %s vrf names'
% (str(system_reserved_names)), ifaceobj)
return False
return True
def _iproute2_vrf_map_initialize(self, writetodisk=True):
if self._iproute2_vrf_map_initialized:
return
@@ -256,6 +315,14 @@ class vrf(moduleBase):
ifaceobj.link_type = ifaceLinkType.LINK_MASTER
ifaceobj.link_kind |= ifaceLinkKind.VRF
ifaceobj.role |= ifaceRole.MASTER
if vrf_table != 'auto':
# if the user didn't specify auto we need to store the desired
# vrf tables ids, in case the configuration has both auto and
# hardcoded vrf-table ids. We need to create them all without
# collisions.
self.user_reserved_vrf_table.append(int(vrf_table))
vrf_iface_name = ifaceobj.get_attr_value_first('vrf')
if not vrf_iface_name:
return None
@@ -278,9 +345,9 @@ class vrf(moduleBase):
table_id_start = self.vrf_table_id_start
else:
table_id_start = self.last_used_vrf_table + 1
for t in range(table_id_start,
self.vrf_table_id_end):
if not self.iproute2_vrf_map.get(t):
for t in range(table_id_start, self.vrf_table_id_end):
if (not self.iproute2_vrf_map.get(t)
and t not in self.user_reserved_vrf_table):
self.last_used_vrf_table = t
return str(t)
return None
@@ -330,13 +397,22 @@ class vrf(moduleBase):
return False
return True
def _up_vrf_slave_without_master(self, ifacename, vrfname, ifaceobj,
vrf_master_objs):
def _up_vrf_slave_without_master(self, ifacename, vrfname, ifaceobj, vrf_master_objs, ifaceobj_getfunc=None):
""" If we have a vrf slave that has dhcp configured, bring up the
vrf master now. This is needed because vrf has special handling
in dhclient hook which requires the vrf master to be present """
vrf_master = None
if len(ifaceobj.upperifaces) > 1 and ifaceobj_getfunc:
for upper_iface in ifaceobj.upperifaces:
upper_ifaceobjs = ifaceobj_getfunc(upper_iface)
vrf_master = ifaceobj.upperifaces[0]
if upper_ifaceobjs:
for upper_obj in upper_ifaceobjs:
if upper_obj.link_kind & ifaceLinkKind.VRF:
vrf_master = upper_obj.name
break
elif ifaceobj.upperifaces:
vrf_master = ifaceobj.upperifaces[0]
if not vrf_master:
self.logger.warn('%s: vrf master not found' %ifacename)
return
@@ -362,7 +438,7 @@ class vrf(moduleBase):
raise
break
self._handle_existing_connections(ifaceobj, vrfname)
netlink.link_set_master(ifacename, vrfname)
self.ipcmd.link_set(ifacename, 'master', vrfname)
return
def _down_dhcp_slave(self, ifaceobj, vrfname):
@@ -394,7 +470,7 @@ class vrf(moduleBase):
uppers = self.ipcmd.link_get_uppers(ifacename)
if not uppers or vrfname not in uppers:
self._handle_existing_connections(ifaceobj, vrfname)
netlink.link_set_master(ifacename, vrfname)
self.ipcmd.link_set(ifacename, 'master', vrfname)
elif ifaceobj:
vrf_master_objs = ifaceobj_getfunc(vrfname)
if not vrf_master_objs:
@@ -413,7 +489,8 @@ class vrf(moduleBase):
Set(ifaceobj.classes).intersection(vrf_master_objs[0].classes))):
self._up_vrf_slave_without_master(ifacename, vrfname,
ifaceobj,
vrf_master_objs)
vrf_master_objs,
ifaceobj_getfunc)
else:
master_exists = False
else:
@@ -429,29 +506,33 @@ class vrf(moduleBase):
def _del_vrf_rules(self, vrf_dev_name, vrf_table):
pref = 200
ip_rule_out_format = '%s: from all %s %s lookup %s'
ip_rule_cmd = 'ip %s rule del pref %s %s %s table %s'
ip_rule_cmd = '%s %s rule del pref %s %s %s table %s'
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
if rule in self.ip_rule_cache:
rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'', pref, 'oif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
if rule in self.ip_rule_cache:
rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'', pref, 'iif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
if rule in self.ip6_rule_cache:
rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'-6', pref, 'oif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
if rule in self.ip6_rule_cache:
rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'-6', pref, 'iif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
@@ -464,31 +545,37 @@ class vrf(moduleBase):
return False
def _rule_cache_fill(self):
ip_rules = utils.exec_command('/sbin/ip rule show').splitlines()
ip_rules = utils.exec_command('%s rule show'
%utils.ip_cmd).splitlines()
self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
self.l3mdev4_rule = self._l3mdev_rule(self.ip_rule_cache)
ip_rules = utils.exec_command('/sbin/ip -6 rule show').splitlines()
ip_rules = utils.exec_command('%s -6 rule show'
%utils.ip_cmd).splitlines()
self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
self.l3mdev6_rule = self._l3mdev_rule(self.ip6_rule_cache)
def _add_vrf_rules(self, vrf_dev_name, vrf_table):
pref = 200
ip_rule_out_format = '%s: from all %s %s lookup %s'
ip_rule_cmd = 'ip %s rule add pref %s %s %s table %s'
ip_rule_cmd = '%s %s rule add pref %s %s %s table %s'
if self.vrf_fix_local_table:
self.vrf_fix_local_table = False
rule = '0: from all lookup local'
if rule in self.ip_rule_cache:
try:
utils.exec_command('ip rule del pref 0')
utils.exec_command('ip rule add pref 32765 table local')
utils.exec_command('%s rule del pref 0'
%utils.ip_cmd)
utils.exec_command('%s rule add pref 32765 table local'
%utils.ip_cmd)
except Exception, e:
self.logger.info('%s: %s' % (vrf_dev_name, str(e)))
pass
if rule in self.ip6_rule_cache:
try:
utils.exec_command('ip -6 rule del pref 0')
utils.exec_command('ip -6 rule add pref 32765 table local')
utils.exec_command('%s -6 rule del pref 0'
%utils.ip_cmd)
utils.exec_command('%s -6 rule add pref 32765 table local'
%utils.ip_cmd)
except Exception, e:
self.logger.info('%s: %s' % (vrf_dev_name, str(e)))
pass
@@ -502,25 +589,29 @@ class vrf(moduleBase):
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
if not self.l3mdev4_rule and rule not in self.ip_rule_cache:
rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'', pref, 'oif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
if not self.l3mdev4_rule and rule not in self.ip_rule_cache:
rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'', pref, 'iif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name)
if not self.l3mdev6_rule and rule not in self.ip6_rule_cache:
rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'-6', pref, 'oif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name)
if not self.l3mdev6_rule and rule not in self.ip6_rule_cache:
rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
rule_cmd = ip_rule_cmd %(utils.ip_cmd,
'-6', pref, 'iif', vrf_dev_name,
vrf_dev_name)
utils.exec_command(rule_cmd)
@@ -533,7 +624,7 @@ class vrf(moduleBase):
# XXX: additional possible checks that can be done here
# are:
# - check if it is also a macvlan device of the
# format <vrf_slave>-v<int> created by the
# format <vrf_slave>-v<int> created by the
# address virtual module
vrfslave_lowers = self.ipcmd.link_get_lowers(vrfslave)
if vrfslave_lowers:
@@ -599,10 +690,8 @@ class vrf(moduleBase):
def _create_vrf_dev(self, ifaceobj, vrf_table):
if not self.ipcmd.link_exists(ifaceobj.name):
if ifaceobj.name in self.system_reserved_rt_tables.values():
self.log_error('cannot use system reserved %s vrf names'
%(str(self.system_reserved_rt_tables.values())),
ifaceobj)
self._check_vrf_system_reserved_names(ifaceobj)
if self.vrf_count == self.vrf_max_count:
self.log_error('max vrf count %d hit...not '
'creating vrf' % self.vrf_count, ifaceobj)
@@ -641,7 +730,7 @@ class vrf(moduleBase):
else:
if vrf_table == 'auto':
vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
if not vrf_table:
if not vrf_table and not ifupdownflags.flags.DRYRUN:
self.log_error('unable to get vrf table id', ifaceobj)
# if the device exists, check if table id is same
@@ -678,7 +767,7 @@ class vrf(moduleBase):
vrf_table = self._create_vrf_dev(ifaceobj, vrf_table)
except Exception, e:
self.log_error('%s: %s' %(ifaceobj.name, str(e)), ifaceobj)
try:
self._add_vrf_rules(ifaceobj.name, vrf_table)
self._up_vrf_helper(ifaceobj, vrf_table)
@@ -691,7 +780,7 @@ class vrf(moduleBase):
def _kill_ssh_connections(self, ifacename):
try:
runningaddrsdict = self.ipcmd.addr_get(ifacename)
runningaddrsdict = self.ipcmd.get_running_addrs(None, ifacename)
if not runningaddrsdict:
return
iplist = [i.split('/', 1)[0] for i in runningaddrsdict.keys()]
@@ -699,9 +788,9 @@ class vrf(moduleBase):
return
proc=[]
#Example output:
#ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
#ESTAB 0 0 10.0.1.84:ssh 10.0.1.228:45186
#users:(("sshd",pid=2528,fd=3))
cmdl = ['/bin/ss', '-t', '-p']
cmdl = [utils.ss_cmd, '-t', '-p']
for line in utils.exec_commandl(cmdl).splitlines():
citems = line.split()
addr = None
@@ -722,7 +811,8 @@ class vrf(moduleBase):
# 'systemd(1)---sshd(990)---sshd(16112)---sshd(16126)---bash(16127)---sudo(16756)---ifreload(16761)---pstree(16842)\n'
# get the above output to following format
# ['systemd(1)', 'sshd(990)', 'sshd(16112)', 'sshd(16126)', 'bash(16127)', 'sudo(16756)', 'ifreload(16761)', 'pstree(16850)']
pstree = list(reversed(utils.exec_command('/usr/bin/pstree -Aps %s' %os.getpid()).strip().split('---')))
pstree = list(reversed(utils.exec_command('%s -Aps %s' %
(utils.pstree_cmd, os.getpid())).strip().split('---')))
for index, process in enumerate(pstree):
# check the parent of SSH process to make sure
# we don't kill SSH server or systemd process
@@ -778,7 +868,7 @@ class vrf(moduleBase):
# This is a vrf slave
self._up_vrf_slave(ifaceobj.name, vrf, ifaceobj,
ifaceobj_getfunc)
else:
elif not ifupdownflags.flags.PERFMODE:
# check if we were a slave before
master = self.ipcmd.link_get_master(ifaceobj.name)
if master:
@@ -805,8 +895,8 @@ class vrf(moduleBase):
return
try:
utils.exec_command('/bin/ss -aK \"dev == %s\"'
%ifindex)
utils.exec_command('%s -aK \"dev == %s\"'
%(utils.ss_cmd, ifindex))
except Exception, e:
self.logger.info('%s: closing socks using ss'
' failed (%s)\n' %(ifaceobj.name, str(e)))
@@ -853,11 +943,12 @@ class vrf(moduleBase):
ifindex = self.ipcmd.link_get_ifindex(ifaceobj.name)
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
pass
if ifindex:
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
pass
self._close_sockets(ifaceobj, ifindex)
@@ -871,7 +962,7 @@ class vrf(moduleBase):
def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
try:
self._handle_existing_connections(ifaceobj, vrfname)
netlink.link_set_nomaster(ifacename)
self.ipcmd.link_set(ifacename, 'nomaster')
# Down this slave only if it is a slave ifupdown2 manages.
# we dont want to down slaves that maybe up'ed by
# somebody else. One such example is a macvlan device
@@ -1002,9 +1093,7 @@ class vrf(moduleBase):
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = iproute2()
if not self.bondcmd:
self.bondcmd = bondutil()
self.ipcmd = self.bondcmd = LinkUtils()
if not self.dhclientcmd:
self.dhclientcmd = dhclient()

View File

@@ -1,24 +1,29 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
import re
import glob
import signal
try:
from ipaddr import IPNetwork
from sets import Set
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdownaddons.modulebase import moduleBase
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
except ImportError:
import ifupdown.ifupdownflags as ifupdownflags
from ifupdownaddons.modulebase import moduleBase
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
import ifupdown.ifupdownflags as ifupdownflags
import os
import glob
import logging
import signal
import re
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class vrrpd(moduleBase):
""" ifupdown2 addon module to configure vrrpd attributes """
@@ -40,13 +45,12 @@ class vrrpd(moduleBase):
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
def _check_if_process_is_running(self, cmdname, cmdline):
targetpids = []
pidstr = ''
try:
cmdl = ['/bin/pidof', cmdname]
cmdl = [utils.pidof_cmd, cmdname]
pidstr = utils.exec_commandl(cmdl, stderr=None).strip('\n')
except:
pass
@@ -69,7 +73,7 @@ class vrrpd(moduleBase):
except:
pass
return targetpids
def _up(self, ifaceobj):
""" up vrrpd -n -D -i $IFACE -v 1 -p 20 10.0.1.254
up ifplugd -i $IFACE -b -f -u0 -d1 -I -p -q """
@@ -97,11 +101,13 @@ class vrrpd(moduleBase):
self.logger.warn('%s: incomplete vrrp arguments ' %ifaceobj.name,
'(virtual ip not found)')
return
cmd = '/usr/sbin/vrrpd -n -D -i %s %s' %(ifaceobj.name, cmd)
cmd = ('%s -n -D -i %s %s' %
(utils.vrrpd_cmd, ifaceobj.name, cmd))
utils.exec_command(cmd)
cmd = '/usr/sbin/ifplugd -i %s -b -f -u0 -d1 -I -p -q' %ifaceobj.name
if self._check_if_process_is_running('/usr/sbin/ifplugd', cmd):
cmd = ('%s -i %s -b -f -u0 -d1 -I -p -q' %
(utils.ifplugd_cmd, ifaceobj.name))
if self._check_if_process_is_running(utils.ifplugd_cmd, cmd):
self.logger.info('%s: ifplugd already running' %ifaceobj.name)
return
utils.exec_command(cmd)
@@ -119,7 +125,8 @@ class vrrpd(moduleBase):
if not attrval:
return
try:
utils.exec_command('/usr/sbin/ifplugd -k -i %s' % ifaceobj.name)
utils.exec_command('%s -k -i %s' %
(utils.ifplugd_cmd, ifaceobj.name))
except Exception, e:
self.logger.debug('%s: ifplugd down error (%s)'
%(ifaceobj.name, str(e)))

523
ifupdown2/addons/vxlan.py Normal file
View File

@@ -0,0 +1,523 @@
#!/usr/bin/python
#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from sets import Set
from ipaddr import IPNetwork, IPv4Address, IPv4Network, AddressValueError
try:
import ifupdown2.ifupdown.policymanager as policymanager
from ifupdown2.nlmanager.nlmanager import Link
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.netlink import netlink
from ifupdown2.ifupdownaddons.cache import *
from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
from ifupdown2.ifupdownaddons.modulebase import moduleBase
except ImportError:
import ifupdown.policymanager as policymanager
from nlmanager.nlmanager import Link
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.netlink import netlink
from ifupdownaddons.cache import *
from ifupdownaddons.LinkUtils import LinkUtils
from ifupdownaddons.modulebase import moduleBase
class vxlan(moduleBase):
_modinfo = {'mhelp' : 'vxlan module configures vxlan interfaces.',
'attrs' : {
'vxlan-id' :
{'help' : 'vxlan id',
'validrange' : ['1', '16777214'],
'required' : True,
'example': ['vxlan-id 100']},
'vxlan-local-tunnelip' :
{'help' : 'vxlan local tunnel ip',
'validvals' : ['<ipv4>'],
'example': ['vxlan-local-tunnelip 172.16.20.103']},
'vxlan-svcnodeip' :
{'help' : 'vxlan id',
'validvals' : ['<ipv4>'],
'example': ['vxlan-svcnodeip 172.16.22.125']},
'vxlan-remoteip' :
{'help' : 'vxlan remote ip',
'validvals' : ['<ipv4>'],
'example': ['vxlan-remoteip 172.16.22.127'],
'multiline': True},
'vxlan-learning' :
{'help' : 'vxlan learning yes/no',
'validvals' : ['yes', 'no', 'on', 'off'],
'example': ['vxlan-learning no'],
'default': 'yes'},
'vxlan-ageing' :
{'help' : 'vxlan aging timer',
'validrange' : ['0', '4096'],
'example': ['vxlan-ageing 300'],
'default': '300'},
'vxlan-purge-remotes' :
{'help' : 'vxlan purge existing remote entries',
'validvals' : ['yes', 'no'],
'example': ['vxlan-purge-remotes yes'],},
'vxlan-port': {
'help': 'vxlan UDP port (transmitted to vxlan driver)',
'validvals': ['<number>'],
'example': 'vxlan-port 4789',
'validrange': ['1', '65536'],
'default': '4789',
}
}}
_clagd_vxlan_anycast_ip = ""
_vxlan_local_tunnelip = None
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
purge_remotes = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vxlan-purge-remotes')
if purge_remotes:
self._purge_remotes = utils.get_boolean_from_string(purge_remotes)
else:
self._purge_remotes = False
def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if self._is_vxlan_device(ifaceobj):
if not ifaceobj.get_attr_value_first('vxlan-local-tunnelip') and not vxlan._vxlan_local_tunnelip:
self.logger.warning('%s: missing vxlan-local-tunnelip' % ifaceobj.name)
return False
return self.syntax_check_localip_anycastip_equal(
ifaceobj.name,
ifaceobj.get_attr_value_first('vxlan-local-tunnelip') or vxlan._vxlan_local_tunnelip,
vxlan._clagd_vxlan_anycast_ip
)
return True
def syntax_check_localip_anycastip_equal(self, ifname, local_ip, anycast_ip):
try:
if IPNetwork(local_ip) == IPNetwork(anycast_ip):
self.logger.warning('%s: vxlan-local-tunnelip and clagd-vxlan-anycast-ip are identical (%s)'
% (ifname, local_ip))
return False
except:
pass
return True
def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
if self._is_vxlan_device(ifaceobj):
ifaceobj.link_kind |= ifaceLinkKind.VXLAN
self._set_global_local_ip(ifaceobj)
elif ifaceobj.name == 'lo':
clagd_vxlan_list = ifaceobj.get_attr_value('clagd-vxlan-anycast-ip')
if clagd_vxlan_list:
if len(clagd_vxlan_list) != 1:
self.log_warn('%s: multiple clagd-vxlan-anycast-ip lines, using first one'
% (ifaceobj.name,))
vxlan._clagd_vxlan_anycast_ip = clagd_vxlan_list[0]
self._set_global_local_ip(ifaceobj)
return None
def _set_global_local_ip(self, ifaceobj):
vxlan_local_tunnel_ip = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
if vxlan_local_tunnel_ip and not vxlan._vxlan_local_tunnelip:
vxlan._vxlan_local_tunnelip = vxlan_local_tunnel_ip
def _is_vxlan_device(self, ifaceobj):
if ifaceobj.get_attr_value_first('vxlan-id'):
return True
return False
def _get_purge_remotes(self, ifaceobj):
if not ifaceobj:
return self._purge_remotes
purge_remotes = ifaceobj.get_attr_value_first('vxlan-purge-remotes')
if purge_remotes:
purge_remotes = utils.get_boolean_from_string(purge_remotes)
else:
purge_remotes = self._purge_remotes
return purge_remotes
def should_create_set_vxlan(self, link_exists, ifname, vxlan_id, local, learning, ageing, group):
"""
should we issue a netlink: ip link add dev %ifname type vxlan ...?
checking each attribute against the cache
"""
if not link_exists:
return True
try:
if ageing:
ageing = int(ageing)
except:
pass
for attr_list, value in (
((ifname, 'linkinfo', Link.IFLA_VXLAN_ID), vxlan_id),
((ifname, 'linkinfo', Link.IFLA_VXLAN_AGEING), ageing),
((ifname, 'linkinfo', Link.IFLA_VXLAN_LOCAL), local),
((ifname, 'linkinfo', Link.IFLA_VXLAN_LEARNING), learning),
((ifname, 'linkinfo', Link.IFLA_VXLAN_GROUP), group),
):
if value and not self.ipcmd.cache_check(attr_list, value):
return True
return False
def _vxlan_create(self, ifaceobj):
vxlanid = ifaceobj.get_attr_value_first('vxlan-id')
if vxlanid:
ifname = ifaceobj.name
anycastip = self._clagd_vxlan_anycast_ip
group = ifaceobj.get_attr_value_first('vxlan-svcnodeip')
local = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
if not local and vxlan._vxlan_local_tunnelip:
local = vxlan._vxlan_local_tunnelip
self.syntax_check_localip_anycastip_equal(ifname, local, anycastip)
# if both local-ip and anycast-ip are identical the function prints a warning
ageing = ifaceobj.get_attr_value_first('vxlan-ageing')
vxlan_port = ifaceobj.get_attr_value_first('vxlan-port')
purge_remotes = self._get_purge_remotes(ifaceobj)
link_exists = self.ipcmd.link_exists(ifname)
if (not link_exists or
not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
vxlan_learning = ifaceobj.get_attr_value_first('vxlan-learning')
if not vxlan_learning:
vxlan_learning = self.get_attr_default_value('vxlan-learning')
learning = utils.get_boolean_from_string(vxlan_learning)
else:
learning = utils.get_boolean_from_string(
self.ipcmd.get_vxlandev_learning(ifname))
if link_exists:
vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifname)
# on ifreload do not overwrite anycast_ip to individual ip
# if clagd has modified
if vxlanattrs:
running_localtunnelip = vxlanattrs.get('local')
if (anycastip and running_localtunnelip and
anycastip == running_localtunnelip):
local = running_localtunnelip
if vxlanattrs.get('vxlanid') != vxlanid:
self.log_error('%s: Cannot change running vxlan id: '
'Operation not supported' % ifname, ifaceobj)
try:
vxlanid = int(vxlanid)
except:
self.log_error('%s: invalid vxlan-id \'%s\'' % (ifname, vxlanid), ifaceobj)
if not group:
group = policymanager.policymanager_api.get_attr_default(
module_name=self.__class__.__name__,
attr='vxlan-svcnodeip'
)
if group:
try:
group = IPv4Address(group)
except AddressValueError:
try:
group_ip = IPv4Network(group).ip
self.logger.warning('%s: vxlan-svcnodeip %s: netmask ignored' % (ifname, group))
group = group_ip
except:
raise Exception('%s: invalid vxlan-svcnodeip %s: must be in ipv4 format' % (ifname, group))
if not local:
local = policymanager.policymanager_api.get_attr_default(
module_name=self.__class__.__name__,
attr='vxlan-local-tunnelip'
)
if local:
try:
local = IPv4Address(local)
except AddressValueError:
try:
local_ip = IPv4Network(local).ip
self.logger.warning('%s: vxlan-local-tunnelip %s: netmask ignored' % (ifname, local))
local = local_ip
except:
raise Exception('%s: invalid vxlan-local-tunnelip %s: must be in ipv4 format' % (ifname, local))
if not ageing:
ageing = policymanager.policymanager_api.get_attr_default(
module_name=self.__class__.__name__,
attr='vxlan-ageing'
)
if not ageing and link_exists:
# if link doesn't exist we let the kernel define ageing
ageing = self.get_attr_default_value('vxlan-ageing')
if not vxlan_port:
vxlan_port = policymanager.policymanager_api.get_attr_default(
module_name=self.__class__.__name__,
attr='vxlan-port'
)
try:
vxlan_port = int(vxlan_port)
except TypeError:
# TypeError means vxlan_port was None
# ie: not provided by the user or the policy
vxlan_port = netlink.VXLAN_UDP_PORT
except ValueError as e:
self.logger.warning('%s: vxlan-port: using default %s: invalid configured value %s' % (ifname, netlink.VXLAN_UDP_PORT, str(e)))
vxlan_port = netlink.VXLAN_UDP_PORT
if link_exists:
cache_port = vxlanattrs.get(Link.IFLA_VXLAN_PORT)
if vxlan_port != cache_port:
self.logger.warning('%s: vxlan-port (%s) cannot be changed - to apply the desired change please run: ifdown %s && ifup %s'
% (ifname, cache_port, ifname, ifname))
vxlan_port = cache_port
if self.should_create_set_vxlan(link_exists, ifname, vxlanid, local, learning, ageing, group):
try:
netlink.link_add_vxlan(ifname, vxlanid,
local=local,
learning=learning,
ageing=ageing,
group=group,
dstport=vxlan_port)
except Exception as e_netlink:
self.logger.debug('%s: vxlan netlink: %s' % (ifname, str(e_netlink)))
try:
self.ipcmd.link_create_vxlan(ifname, vxlanid,
localtunnelip=local,
svcnodeip=group,
remoteips=ifaceobj.get_attr_value('vxlan-remoteip'),
learning='on' if learning else 'off',
ageing=ageing)
except Exception as e_iproute2:
self.logger.warning('%s: vxlan add/set failed: %s' % (ifname, str(e_iproute2)))
return
try:
# manually adding an entry to the caching after creating/updating the vxlan
if not ifname in linkCache.links:
linkCache.links[ifname] = {'linkinfo': {}}
linkCache.links[ifname]['linkinfo'].update({
'learning': learning,
Link.IFLA_VXLAN_LEARNING: learning,
'vxlanid': str(vxlanid),
Link.IFLA_VXLAN_ID: vxlanid
})
if ageing:
linkCache.links[ifname]['linkinfo'].update({
'ageing': ageing,
Link.IFLA_VXLAN_AGEING: int(ageing)
})
except:
pass
else:
self.logger.info('%s: vxlan already exists' % ifname)
# if the vxlan already exists it's already cached
remoteips = ifaceobj.get_attr_value('vxlan-remoteip')
if remoteips:
try:
for remoteip in remoteips:
IPv4Address(remoteip)
except Exception as e:
self.log_error('%s: vxlan-remoteip: %s' %(ifaceobj.name, str(e)))
if purge_remotes or remoteips:
# figure out the diff for remotes and do the bridge fdb updates
# only if provisioned by user and not by an vxlan external
# controller.
peers = self.ipcmd.get_vxlan_peers(ifaceobj.name, group)
if local and remoteips and local in remoteips:
remoteips.remove(local)
cur_peers = set(peers)
if remoteips:
new_peers = set(remoteips)
del_list = cur_peers.difference(new_peers)
add_list = new_peers.difference(cur_peers)
else:
del_list = cur_peers
add_list = []
for addr in del_list:
try:
self.ipcmd.bridge_fdb_del(ifaceobj.name,
'00:00:00:00:00:00',
None, True, addr)
except:
pass
for addr in add_list:
try:
self.ipcmd.bridge_fdb_append(ifaceobj.name,
'00:00:00:00:00:00',
None, True, addr)
except:
pass
def _up(self, ifaceobj):
self._vxlan_create(ifaceobj)
def _down(self, ifaceobj):
try:
self.ipcmd.link_delete(ifaceobj.name)
except Exception, e:
self.log_warn(str(e))
def _query_check_n_update(self, ifaceobj, ifaceobjcurr, attrname, attrval,
running_attrval):
if not ifaceobj.get_attr_value_first(attrname):
return
if running_attrval and attrval == running_attrval:
ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
else:
ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
def _query_check_n_update_addresses(self, ifaceobjcurr, attrname,
addresses, running_addresses):
if addresses:
for a in addresses:
if a in running_addresses:
ifaceobjcurr.update_config_with_status(attrname, a, 0)
else:
ifaceobjcurr.update_config_with_status(attrname, a, 1)
running_addresses = Set(running_addresses).difference(
Set(addresses))
[ifaceobjcurr.update_config_with_status(attrname, a, 1)
for a in running_addresses]
def _query_check(self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists(ifaceobj.name):
return
# Update vxlan object
vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobj.name)
if not vxlanattrs:
ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj,
self.get_mod_attrs(), -1)
return
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-id',
ifaceobj.get_attr_value_first('vxlan-id'),
vxlanattrs.get('vxlanid'))
self._query_check_n_update(
ifaceobj,
ifaceobjcurr,
'vxlan-port',
ifaceobj.get_attr_value_first('vxlan-port'),
str(vxlanattrs.get(Link.IFLA_VXLAN_PORT))
)
running_attrval = vxlanattrs.get('local')
attrval = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
if not attrval:
attrval = vxlan._vxlan_local_tunnelip
ifaceobj.update_config('vxlan-local-tunnelip', attrval)
if running_attrval == self._clagd_vxlan_anycast_ip:
# if local ip is anycast_ip, then let query_check to go through
attrval = self._clagd_vxlan_anycast_ip
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip',
attrval, running_attrval)
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-svcnodeip',
ifaceobj.get_attr_value_first('vxlan-svcnodeip'),
vxlanattrs.get('svcnode'))
purge_remotes = self._get_purge_remotes(ifaceobj)
if purge_remotes or ifaceobj.get_attr_value('vxlan-remoteip'):
# If purge remotes or if vxlan-remoteip's are set
# in the config file, we are owners of the installed
# remote-ip's, lets check and report any remote ips we don't
# understand
self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip',
ifaceobj.get_attr_value('vxlan-remoteip'),
self.ipcmd.get_vxlan_peers(ifaceobj.name, vxlanattrs.get('svcnode')))
learning = ifaceobj.get_attr_value_first('vxlan-learning')
if learning:
running_learning = vxlanattrs.get('learning')
if learning == 'yes' and running_learning == 'on':
running_learning = 'yes'
elif learning == 'no' and running_learning == 'off':
running_learning = 'no'
if learning == running_learning:
ifaceobjcurr.update_config_with_status('vxlan-learning',
running_learning, 0)
else:
ifaceobjcurr.update_config_with_status('vxlan-learning',
running_learning, 1)
ageing = ifaceobj.get_attr_value_first('vxlan-ageing')
if not ageing:
ageing = self.get_mod_subattr('vxlan-ageing', 'default')
self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-ageing',
ageing, vxlanattrs.get('ageing'))
def _query_running(self, ifaceobjrunning):
vxlanattrs = self.ipcmd.get_vxlandev_attrs(ifaceobjrunning.name)
if not vxlanattrs:
return
attrval = vxlanattrs.get('vxlanid')
if attrval:
ifaceobjrunning.update_config('vxlan-id', vxlanattrs.get('vxlanid'))
else:
# if there is no vxlan id, this is not a vxlan port
return
ifaceobjrunning.update_config('vxlan-port', vxlanattrs.get(Link.IFLA_VXLAN_PORT))
attrval = vxlanattrs.get('local')
if attrval:
ifaceobjrunning.update_config('vxlan-local-tunnelip', attrval)
attrval = vxlanattrs.get('svcnode')
if attrval:
ifaceobjrunning.update_config('vxlan-svcnode', attrval)
purge_remotes = self._get_purge_remotes(None)
if purge_remotes:
# if purge_remotes is on, it means we own the
# remote ips. Query them and add it to the running config
attrval = self.ipcmd.get_vxlan_peers(ifaceobjrunning.name, vxlanattrs.get('svcnode'))
if attrval:
[ifaceobjrunning.update_config('vxlan-remoteip', a)
for a in attrval]
attrval = vxlanattrs.get('learning')
if attrval and attrval == 'on':
ifaceobjrunning.update_config('vxlan-learning', 'on')
attrval = vxlanattrs.get('ageing')
if attrval:
ifaceobjrunning.update_config('vxlan-ageing', vxlanattrs.get('ageing'))
_run_ops = {'pre-up' : _up,
'post-down' : _down,
'query-checkcurr' : _query_check,
'query-running' : _query_running}
def get_ops(self):
return self._run_ops.keys()
def _init_command_handlers(self):
if not self.ipcmd:
self.ipcmd = LinkUtils()
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if (operation != 'query-running' and
not self._is_vxlan_device(ifaceobj)):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

231
ifupdown2/ifupdown/argv.py Normal file
View File

@@ -0,0 +1,231 @@
#!/usr/bin/python
#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# Julien Fortin, julien@cumulusnetworks.com
#
import sys
import argparse
import argcomplete
try:
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.exceptions import ArgvParseError
except:
from ifupdown.utils import utils
from ifupdown.exceptions import ArgvParseError
class VersionAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
try:
dpkg = utils.exec_commandl([utils.dpkg_cmd, '-l', 'ifupdown2'])
if not dpkg:
raise Exception('dpkg -l ifupdown2 returns without output')
dpkg = dpkg.split('\n')
if not dpkg:
raise Exception('dpkg -l ifupdown2 returns without output')
for line in dpkg:
if 'ifupdown2' in line:
info = line.split()
sys.stdout.write('ifupdown2:%s\n' % (info[2]))
sys.exit(0)
raise Exception('ifupdown2 package not found using dpkg -l')
except Exception as e:
sys.stderr.write('error: cannot get current version using dpkg: %s\n' % str(e))
sys.exit(1)
class Parse:
valid_ops = {
'ifup': 'up',
'ifdown': 'down',
'ifreload': 'reload',
'ifquery': 'query'
}
def __init__(self, argv):
self.executable_name = argv[0]
self.op = self.get_op()
self.argv = argv[1:]
if self.op == 'query':
descr = 'query interfaces (all or interface list)'
elif self.op == 'reload':
descr = 'reload interface configuration.'
else:
descr = 'interface management'
argparser = argparse.ArgumentParser(description=descr)
if self.op == 'reload':
self.update_ifreload_argparser(argparser)
else:
self.update_argparser(argparser)
if self.op == 'up':
self.update_ifup_argparser(argparser)
elif self.op == 'down':
self.update_ifdown_argparser(argparser)
elif self.op == 'query':
self.update_ifquery_argparser(argparser)
self.update_common_argparser(argparser)
argcomplete.autocomplete(argparser)
self.args = argparser.parse_args(self.argv)
def validate(self):
if self.op == 'query' and (self.args.syntaxhelp or self.args.list):
return True
if self.op == 'reload':
if not self.args.all and not self.args.currentlyup and not self.args.CLASS:
raise ArgvParseError("'-a' or '-c' or '-allow' option is required")
elif not self.args.iflist and not self.args.all and not self.args.CLASS:
raise ArgvParseError("'-a' option or interface list are required")
if self.args.iflist and self.args.all:
raise ArgvParseError("'-a' option and interface list are mutually exclusive")
if self.op != 'reload' and self.args.CLASS and self.args.all:
raise ArgvParseError("'--allow' option is mutually exclusive with '-a'")
return True
def get_op(self):
try:
for key, value in self.valid_ops.iteritems():
if self.executable_name.endswith(key):
return value
except:
raise ArgvParseError("Unexpected executable. Should be 'ifup' or 'ifdown' or 'ifquery'")
def get_args(self):
return self.args
def update_argparser(self, argparser):
""" base parser, common to all commands """
argparser.add_argument('-a', '--all', action='store_true', required=False,
help='process all interfaces marked "auto"')
argparser.add_argument('iflist', metavar='IFACE', nargs='*',
help='interface list separated by spaces. '
'IFACE list is mutually exclusive with -a option.')
argparser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='verbose')
argparser.add_argument('-d', '--debug', dest='debug', action='store_true', help='output debug info')
argparser.add_argument('-q', '--quiet', dest='quiet', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('--allow', dest='CLASS', action='append', help='ignore non-"allow-CLASS" interfaces')
argparser.add_argument('-w', '--with-depends', dest='withdepends', action='store_true',
help="run with all dependent interfaces. "
"This option is redundant when '-a' is specified. "
"With '-a' interfaces are always executed in dependency order")
argparser.add_argument('--perfmode', dest='perfmode', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('--nocache', dest='nocache', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('-X', '--exclude', dest='excludepats', action='append',
help='Exclude interfaces from the list of interfaces to operate on. '
'Can be specified multiple times.')
argparser.add_argument('-i', '--interfaces', dest='interfacesfile', default=None,
help='Specify interfaces file instead of file defined in ifupdown2.conf file')
argparser.add_argument('-t', '--interfaces-format', dest='interfacesfileformat', default='native',
choices=['native', 'json'], help='interfaces file format')
argparser.add_argument('-T', '--type', dest='type', default=None, choices=['iface', 'vlan'],
help='type of interface entry (iface or vlan). '
'This option can be used in case of ambiguity between '
'a vlan interface and an iface interface of the same name')
def update_ifupdown_argparser(self, argparser):
""" common arg parser for ifup and ifdown """
argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations')
argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true', help=argparse.SUPPRESS)
group = argparser.add_mutually_exclusive_group(required=False)
group.add_argument('-n', '--no-act', dest='noact', action='store_true',
help="print out what would happen, but don't do it")
group.add_argument('-p', '--print-dependency', dest='printdependency',
choices=['list', 'dot'], help='print iface dependency')
group.add_argument('--no-scripts', '--admin-state', dest='noaddons', action='store_true',
help='dont run any addon modules/scripts. Only bring the interface administratively up/down')
def update_ifup_argparser(self, argparser):
argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck',
action='store_true', help='Only run the interfaces file parser')
argparser.add_argument('-k', '--skip-upperifaces', dest='skipupperifaces', action='store_true',
help='ifup by default tries to add newly created interfaces into its upper/parent '
'interfaces. Eg. if a bridge port is created as a result of ifup on the port, '
'ifup automatically adds the port to the bridge. This option can be used to '
'disable this default behaviour')
self.update_ifupdown_argparser(argparser)
def update_ifdown_argparser(self, argparser):
self.update_ifupdown_argparser(argparser)
argparser.add_argument('-u', '--use-current-config',
dest='usecurrentconfig', action='store_true',
help='By default ifdown looks at the saved state for interfaces to bring down. '
'This option allows ifdown to look at the current interfaces file. '
'Useful when your state file is corrupted or you want down to use '
'the latest from the interfaces file')
def update_ifquery_argparser(self, argparser):
""" arg parser for ifquery options """
# -l is same as '-a', only here for backward compatibility
argparser.add_argument('-l', '--list', action='store_true', dest='list',
help='list all matching known interfaces')
group = argparser.add_mutually_exclusive_group(required=False)
group.add_argument('-r', '--running', dest='running', action='store_true',
help='query running state of an interface')
group.add_argument('-c', '--check', dest='checkcurr', action='store_true',
help='check interface file contents against running state of an interface')
group.add_argument('-x', '--raw', action='store_true', dest='raw', help='print raw config file entries')
group.add_argument('--print-savedstate', action='store_true', dest='printsavedstate', help=argparse.SUPPRESS)
argparser.add_argument('-o', '--format', dest='format', default='native',
choices=['native', 'json'], help='interface display format')
argparser.add_argument('-p', '--print-dependency', dest='printdependency',
choices=['list', 'dot'], help='print interface dependency')
argparser.add_argument('-s', '--syntax-help', action='store_true', dest='syntaxhelp',
help='print supported interface config syntax')
argparser.add_argument('--with-defaults', action='store_true', dest='withdefaults',
help='check policy default file contents, for unconfigured attributes, '
'against running state of an interface')
def update_ifreload_argparser(self, argparser):
""" parser for ifreload """
group = argparser.add_mutually_exclusive_group(required=True)
group.add_argument('-a', '--all', action='store_true', help='process all interfaces marked "auto"')
group.add_argument('-c', '--currently-up', dest='currentlyup', action='store_true',
help='Reload the configuration for all interfaces which are '
'currently up regardless of whether an interface has '
'"auto <interface>" configuration within the /etc/network/interfaces file.')
group.add_argument('--allow', dest='CLASS', action='append', help='ignore non-"allow-CLASS" interfaces')
argparser.add_argument('iflist', metavar='IFACE', nargs='*', help=argparse.SUPPRESS)
argparser.add_argument('-n', '--no-act', dest='noact', action='store_true',
help='print out what would happen, but don\'t do it')
argparser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='verbose')
argparser.add_argument('-d', '--debug', dest='debug', action='store_true', help='output debug info')
argparser.add_argument('-w', '--with-depends', dest='withdepends', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('--perfmode', dest='perfmode', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('--nocache', dest='nocache', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('-X', '--exclude', dest='excludepats', action='append', help=argparse.SUPPRESS)
# argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
# default=-1, choices=range(1,12), help=argparse.SUPPRESS)
# argparser.add_argument('-i', '--interfaces', dest='interfacesfile',
# default='/etc/network/interfaces',
# help='use interfaces file instead of default ' +
# '/etc/network/interfaces')
argparser.add_argument('-u', '--use-current-config', dest='usecurrentconfig', action='store_true',
help='By default ifreload looks at saved state for interfaces to bring down. '
'With this option ifreload will only look at the current interfaces file. '
'Useful when your state file is corrupted or you want down to use the latest '
'from the interfaces file')
argparser.add_argument('-l', '--syslog', dest='syslog', action='store_true', help=argparse.SUPPRESS)
argparser.add_argument('-f', '--force', dest='force', action='store_true', help='force run all operations')
argparser.add_argument('-s', '--syntax-check', dest='syntaxcheck', action='store_true',
help='Only run the interfaces file parser')
def update_common_argparser(self, argparser):
''' general parsing rules '''
argparser.add_argument('-V', '--version', action=VersionAction, nargs=0)

View File

@@ -0,0 +1,57 @@
#!/usr/bin/python
#
# Copyright 2017 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Julien Fortin, julien@cumulusnetworks.com
#
# ifupdown2 --
# tool to configure network interfaces
#
import os
import resource
IFUPDOWN2_ADDON_DROPIN_FOLDER = '/usr/share/ifupdown2/addons'
# ifupdown2/core/config.py -> we need to use dirname twice.
_ = {
IFUPDOWN2_ADDON_DROPIN_FOLDER,
'%s/addons' % (os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
}
try:
addon_module_dir_list = list(_)
if addon_module_dir_list[0] is not IFUPDOWN2_ADDON_DROPIN_FOLDER:
addon_module_dir_list.remove(IFUPDOWN2_ADDON_DROPIN_FOLDER)
ADDON_MODULES_DIR = [IFUPDOWN2_ADDON_DROPIN_FOLDER] + addon_module_dir_list
else:
ADDON_MODULES_DIR = addon_module_dir_list
except:
ADDON_MODULES_DIR = [IFUPDOWN2_ADDON_DROPIN_FOLDER]
__version__ = ''
def get_configuration_file_real_path(path_to_file):
"""
When install via pypi or `pip install .` ifupdown2 is install in a virtualenv
config file that should be installed in /etc/network/ifupdown2 end-up being
installed in /usr/local/lib/python2.7/dist-packages/etc/network/ifupdown2/
"""
if not os.path.exists(path_to_file):
# we will try to resolve the location of our conf file
# otherwise default to the input argument
package_dir = os.path.dirname(os.path.realpath(__file__))
parent_dir = os.path.dirname(package_dir)
resolved_path = '%s%s' % (parent_dir, path_to_file)
if os.path.exists(resolved_path):
return resolved_path
return path_to_file
IFUPDOWN2_CONF_PATH = get_configuration_file_real_path('/etc/network/ifupdown2/ifupdown2.conf')
ADDONS_CONF_PATH = get_configuration_file_real_path('/etc/network/ifupdown2/addons.conf')
resource.setrlimit(resource.RLIMIT_CORE, (0, 0))

View File

@@ -0,0 +1,58 @@
#!/usr/bin/python
#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# Julien Fortin, julien@cumulusnetworks.com
#
# ifupdown --
# exceptions
#
try:
from ifupdown2.ifupdown.log import log
except:
from ifupdown.log import log
class Error(Exception):
"""Base class for exceptions in ifupdown"""
def log_error(self):
log.error(self.message)
def log_warning(self):
log.warning(self.message)
def log_info(self):
log.info(self.message)
def log_debug(self):
log.debug(self.message)
class ArgvParseError(Error):
"""
Exception coming from argv parsing
"""
pass
class ifaceNotFoundError(Error):
pass
class invalidValueError(Error):
pass
class errorReadingStateError(Error):
pass
class moduleNotSupported(Error):
pass
class ReservedVlanException(Error):
pass

View File

@@ -1,20 +1,23 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# graph --
# graph helper module for ifupdown
#
import logging
import copy
import logging
from collections import deque
try:
from gvgen import *
except ImportError, e:
pass
class graph():
""" graph functions to sort and print interface graph """
@@ -26,7 +29,7 @@ class graph():
Args:
**dependency_graphs** (dict): dependency graph with dependency
lists for interfaces
lists for interfaces
**indegrees_arg** (dict): indegrees array for all interfaces
"""
@@ -73,7 +76,7 @@ class graph():
Args:
**dependency_graphs** (dict): dependency graph with dependency
lists for interfaces
lists for interfaces
**indegrees_arg** (dict): indegrees array for all interfaces
"""

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# iface --
@@ -13,10 +13,11 @@ It is modeled based on the 'iface' section in /etc/network/interfaces
file. But can be extended to include any other network interface format
"""
from collections import OrderedDict
import logging
import json
from collections import OrderedDict
class ifaceStatusUserStrs():
""" This class declares strings user can see during an ifquery --check
for example. These strings can be overridden by user defined strings from
@@ -46,13 +47,28 @@ class ifaceLinkKind():
bond have an ifaceobj.role attribute of SLAVE and the bridge or
bond itself has ifaceobj.role of MASTER.
"""
UNKNOWN = 0x000000
BRIDGE = 0x000001
BOND = 0x000010
VLAN = 0x000100
VXLAN = 0x001000
VRF = 0x010000
BATMAN_ADV = 0x100000
UNKNOWN = 0x000000
BRIDGE = 0x000001
BOND = 0x000010
VLAN = 0x000100
VXLAN = 0x001000
VRF = 0x010000
# to indicate logical interface created by an external entity.
# the 'kind' of which ifupdown2 does not really understand
OTHER = 0x100000
@classmethod
def to_str(cls, kind):
if kind == cls.BRIDGE:
return "bridge"
elif kind == cls.BOND:
return "bond"
elif kind == cls.VLAN:
return "vlan"
elif kind == cls.VXLAN:
return "vxlan"
elif kind == cls.VRF:
return "vrf"
class ifaceLinkPrivFlags():
""" This corresponds to kernel netdev->priv_flags
@@ -103,6 +119,18 @@ class ifaceLinkType():
LINK_MASTER = 0x2
LINK_NA = 0x3
class VlanProtocols():
# Picked ID values from
# http://www.microhowto.info/howto/configure_an_ethernet_interface_as_a_qinq_vlan_trunk.html
ETHERTYPES_TO_ID = {
'802.1Q' : '0x8100',
'802.1AD' : '0x88a8',
}
ID_TO_ETHERTYPES = {
'0x8100' : '802.1Q',
'0x88a8' : '802.1AD',
}
class ifaceDependencyType():
""" Indicates type of dependency.
@@ -119,7 +147,7 @@ class ifaceDependencyType():
swp1.200 can both have 'link' swp1. swp1 is also a dependency
of swp1.100 and swp1.200. As you can see dependency
swp1 is shared between swp1.100 and swp1.200.
In a master/slave relationship like bridge and
its ports: eg: bridge br0 and its ports swp1 and swp2.
dependency swp1 and swp2 cannot be shared with any other
@@ -152,7 +180,7 @@ class ifaceStatus():
return 'error'
elif state == cls.NOTFOUND:
return 'notfound'
@classmethod
def from_str(cls, state_str):
if state_str == 'unknown':
@@ -228,7 +256,7 @@ class ifaceJsonEncoder(json.JSONEncoder):
def default(self, o):
retconfig = {}
retifacedict = OrderedDict([])
if o.config:
if o.config:
retconfig = dict((k, (v[0] if len(v) == 1 else v))
for k,v in o.config.items())
retifacedict['name'] = o.name
@@ -258,12 +286,12 @@ class ifaceJsonEncoderWithStatus(json.JSONEncoder):
vitem_status = []
for vitem in v:
s = o.get_config_attr_status(k, idx)
if s == -1:
status_str = ifaceStatusUserStrs.UNKNOWN
elif s == 1:
if s == 1:
status_str = ifaceStatusUserStrs.ERROR
elif s == 0:
status_str = ifaceStatusUserStrs.SUCCESS
else:
status_str = ifaceStatusUserStrs.UNKNOWN
vitem_status.append('%s' %status_str)
idx += 1
retconfig[k] = v[0] if len(v) == 1 else v
@@ -302,7 +330,7 @@ class ifaceJsonDecoder():
class iface():
""" ifupdown2 iface object class
Attributes:
**name** Name of the interface
**name** Name of the interface
**addr_family** Address family eg, inet, inet6. Can be None to
indicate both address families
@@ -331,7 +359,7 @@ class iface():
this interface depends on
**upperifaces** list of interface names upper to this interface or
the interfaces that depend on this interface
the interfaces that depend on this interface
**auto** True if interface belongs to the auto class
@@ -374,7 +402,7 @@ class iface():
"""iface priv flags. can be used by the external object manager """
self.refcnt = 0
"""iface refcnt (incremented for each dependent this interface has) """
self.lowerifaces = None
self.lowerifaces = None
"""lower iface list (in other words: slaves of this interface """
self.upperifaces = None
"""upper iface list (in other words: master of this interface """
@@ -471,7 +499,7 @@ class iface():
def get_attr_value(self, attr_name):
""" add to the list of upperifaces """
return self.config.get(attr_name)
def get_attr_value_first(self, attr_name):
""" get first value of the specified attr name """
attr_value_list = self.config.get(attr_name)
@@ -562,7 +590,7 @@ class iface():
def get_config_attr_status(self, attr_name, idx=0):
""" get status of a attribute config on this interface.
Looks at the iface _config_status dict"""
return self._config_status.get(attr_name, [])[idx]
@@ -653,7 +681,7 @@ class iface():
print (self.raw_config[0])
for i in range(1, len(self.raw_config)):
print(indent + self.raw_config[i])
def dump(self, logger):
indent = '\t'
logger.info(self.name + ' : {')

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
#
# Author: Scott Feldman, sfeldma@cumulusnetworks.com
#

View File

@@ -1,20 +1,26 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# ifupdownBase --
# base object for various ifupdown objects
#
import logging
import re
import os
import logging
import traceback
from ifupdown.netlink import netlink
from iface import *
import ifupdownflags as ifupdownflags
try:
from ifupdown2.ifupdown.netlink import netlink
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.netlink import netlink
import ifupdown.ifupdownflags as ifupdownflags
class ifupdownBase(object):
@@ -32,13 +38,13 @@ class ifupdownBase(object):
if self.ignore_error(str) == False:
if self.logger.getEffectiveLevel() == logging.DEBUG:
traceback.print_stack()
traceback.print_exc()
self.logger.warn(str)
pass
def log_error(self, str):
if self.ignore_error(str) == False:
raise
#raise Exception(str)
raise Exception(str)
else:
pass

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env python
#
# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
# Copyright 2015-2017 Cumulus Networks, Inc. All rights reserved.
#
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
#
class ifupdownConfig():
@@ -12,3 +11,7 @@ class ifupdownConfig():
self.conf = {}
config = ifupdownConfig()
def reset():
global config
config = ifupdownConfig()

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env python
#
# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
# Copyright 2015-2017 Cumulus Networks, Inc. All rights reserved.
#
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
#
class ifupdownFlags():
@@ -23,3 +22,8 @@ class ifupdownFlags():
self.CACHE_FLAGS = 0x0
flags = ifupdownFlags()
def reset():
global flags
flags = ifupdownFlags()

View File

@@ -1,34 +1,54 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# ifupdownMain --
# ifupdown main module
#
import os
import re
import imp
import pprint
import logging
import sys, traceback
import copy
import json
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownconfig as ifupdownConfig
import ifupdown.ifupdownflags as ifupdownflags
from networkinterfaces import *
from iface import *
from scheduler import *
from collections import deque
from collections import OrderedDict
from graph import *
from exceptions import *
from sets import Set
from ipaddr import IPNetwork, IPv4Network, IPv6Network, IPAddress, IPv4Address, IPv6Address
try:
import ifupdown2.ifupdownaddons.cache
import ifupdown2.ifupdownaddons.LinkUtils
import ifupdown2.ifupdownaddons.mstpctlutil
import ifupdown2.ifupdown.policymanager
import ifupdown2.ifupdown.ifupdownflags
import ifupdown2.ifupdown.statemanager as statemanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
import ifupdown2.ifupdown.ifupdownconfig as ifupdownConfig
from ifupdown2.ifupdown.graph import *
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.scheduler import *
from ifupdown2.ifupdown.exceptions import *
from ifupdown2.ifupdown.networkinterfaces import *
from ifupdown2.ifupdown.config import ADDON_MODULES_DIR, ADDONS_CONF_PATH, IFUPDOWN2_ADDON_DROPIN_FOLDER
except ImportError:
import ifupdownaddons.cache
import ifupdownaddons.LinkUtils
import ifupdownaddons.mstpctlutil
import ifupdown.ifupdownflags
import ifupdown.policymanager
import ifupdown.statemanager as statemanager
import ifupdown.ifupdownflags as ifupdownflags
import ifupdown.ifupdownconfig as ifupdownConfig
from ifupdown.graph import *
from ifupdown.iface import *
from ifupdown.scheduler import *
from ifupdown.exceptions import *
from ifupdown.networkinterfaces import *
from ifupdown.config import ADDON_MODULES_DIR, ADDONS_CONF_PATH, IFUPDOWN2_ADDON_DROPIN_FOLDER
"""
.. module:: ifupdownmain
:synopsis: main module for ifupdown package
@@ -59,52 +79,13 @@ class ifacePrivFlags():
def __init__(self, builtin=False, noconfig=False):
self.BUILTIN = builtin
self.NOCONFIG = noconfig
class ifupdownMain(ifupdownBase):
""" ifupdown2 main class """
scripts_dir='/etc/network'
addon_modules_dir='/usr/share/ifupdown2/addons'
addon_modules_configfile='/etc/network/ifupdown2/addons.conf'
# iface dictionary in the below format:
# { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
# eg:
# { 'swp1' : [<iface swp1>, <iface swp2> ..] }
#
# Each ifaceobject corresponds to a configuration block for
# that interface
# The value in the dictionary is a list because the network
# interface configuration file supports more than one iface section
# in the interfaces file
ifaceobjdict = OrderedDict()
# iface dictionary representing the curr running state of an iface
# in the below format:
# {'<ifacename>' : <ifaceobject>}
ifaceobjcurrdict = OrderedDict()
# Dictionary representing operation and modules
# for every operation
module_ops = OrderedDict([('pre-up', []),
('up' , []),
('post-up' , []),
('query-checkcurr', []),
('query-running', []),
('query-dependency', []),
('query', []),
('query-raw', []),
('pre-down', []),
('down' , []),
('post-down' , [])])
# For old style /etc/network/ bash scripts
script_ops = OrderedDict([('pre-up', []),
('up' , []),
('post-up' , []),
('pre-down', []),
('down' , []),
('post-down' , [])])
scripts_dir = '/etc/network'
addon_modules_dir = ADDON_MODULES_DIR
addon_modules_configfile = ADDONS_CONF_PATH
# Handlers for ops that ifupdown2 owns
def run_up(self, ifaceobj):
@@ -114,6 +95,7 @@ class ifupdownMain(ifupdownBase):
return
if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
(ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
self._keep_link_down(ifaceobj)
return
# if not a logical interface and addr method is manual,
# ignore link admin state changes
@@ -130,14 +112,19 @@ class ifupdownMain(ifupdownBase):
if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
return
if not self.link_exists(ifaceobj.name):
return
return
if self._keep_link_down(ifaceobj):
return
self.link_up(ifaceobj.name)
def _keep_link_down(self, ifaceobj):
if ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
# user has asked to explicitly keep the link down,
# so, force link down
self.logger.info('%s: keeping link down due to user config' %ifaceobj.name)
self.link_down(ifaceobj.name)
return
self.link_up(ifaceobj.name)
return True
return False
def run_down(self, ifaceobj):
if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
@@ -179,8 +166,21 @@ class ifupdownMain(ifupdownBase):
# ifupdown object interface scheduler pre and posthooks
sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
def reset_ifupdown2(self):
ifaceScheduler.reset()
ifupdown2.ifupdown.statemanager.reset()
ifupdown2.ifupdown.policymanager.reset()
ifupdown2.ifupdown.ifupdownflags.reset()
ifupdownConfig.reset()
ifupdown2.ifupdownaddons.mstpctlutil.mstpctlutil.reset()
ifupdown2.ifupdownaddons.LinkUtils.LinkUtils.reset()
ifupdown2.ifupdownaddons.cache.linkCache.reset()
ifupdown2.ifupdownaddons.cache.MSTPAttrsCache.invalidate()
def __init__(self, config={},
force=False, dryrun=False, nowait=False,
daemon=False, force=False, dryrun=False, nowait=False,
perfmode=False, withdepends=False, njobs=1,
cache=False, addons_enable=True, statemanager_enable=True,
interfacesfile='/etc/network/interfaces',
@@ -200,6 +200,49 @@ class ifupdownMain(ifupdownBase):
Raises:
AttributeError, KeyError """
if daemon:
self.reset_ifupdown2()
# iface dictionary in the below format:
# { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
# eg:
# { 'swp1' : [<iface swp1>, <iface swp2> ..] }
#
# Each ifaceobject corresponds to a configuration block for
# that interface
# The value in the dictionary is a list because the network
# interface configuration file supports more than one iface section
# in the interfaces file
self.ifaceobjdict = OrderedDict()
# iface dictionary representing the curr running state of an iface
# in the below format:
# {'<ifacename>' : <ifaceobject>}
self.ifaceobjcurrdict = OrderedDict()
# Dictionary representing operation and modules
# for every operation
self.module_ops = OrderedDict([('pre-up', []),
('up', []),
('post-up', []),
('query-checkcurr', []),
('query-running', []),
('query-dependency', []),
('query', []),
('query-raw', []),
('pre-down', []),
('down', []),
('post-down', [])])
# For old style /etc/network/ bash scripts
self.script_ops = OrderedDict([('pre-up', []),
('up', []),
('post-up', []),
('pre-down', []),
('down', []),
('post-down', [])])
self.logger = logging.getLogger('ifupdown')
ifupdownflags.flags.FORCE = force
ifupdownflags.flags.DRYRUN = dryrun
@@ -243,13 +286,13 @@ class ifupdownMain(ifupdownBase):
self._cache_no_repeats = {}
if self.flags.STATEMANAGER_ENABLE:
self.statemanager = statemanager.statemanager_api
try:
self.statemanager = statemanager.statemanager_api
self.statemanager.read_saved_state()
except Exception, e:
# XXX Maybe we should continue by ignoring old state
# if read_saved_state fails, state file might be corrupt.
# Ignore old state and continue
self.logger.warning('error reading state (%s)' %str(e))
raise
else:
self.flags.STATEMANAGER_UPDATE = False
self._delay_admin_state = True if self.config.get(
@@ -297,16 +340,21 @@ class ifupdownMain(ifupdownBase):
'<ipv6/prefixlen>': self._keyword_ipv6_prefixlen,
'<ip/prefixlen>': self._keyword_ip_prefixlen,
'<number-range-list>': self._keyword_number_range_list,
'<number-comma-range-list>': self._keyword_number_comma_range_list,
'<interface-range-list>': self._keyword_interface_range_list,
'<interface-range-list-multiple-of-16>': self._keyword_interface_range_list_multiple_of_16,
'<mac-ip/prefixlen-list>': self._keyword_mac_ip_prefixlen_list,
'<number-interface-list>': self._keyword_number_interface_list,
'<interface-yes-no-list>': self._keyword_interface_yes_no_list,
'<interface-on-off-list>': self._keyword_interface_on_off_list,
'<interface-yes-no-0-1-list>': self._keyword_interface_yes_no_0_1_list,
'<interface-disabled-automatic-enabled>': self._keyword_interface_disabled_automatic_enabled_list,
'<interface-yes-no-auto-list>': self._keyword_interface_yes_no_auto_list,
'<interface-l2protocol-tunnel-list>': self._keyword_interface_l2protocol_tunnel_list
}
def link_master_slave_ignore_error(self, errorstr):
# If link master slave flag is set,
# If link master slave flag is set,
# there may be cases where the lowerdev may not be
# up resulting in 'Network is down' error
# This can happen if the lowerdev is a LINK_SLAVE
@@ -372,7 +420,7 @@ class ifupdownMain(ifupdownBase):
def create_n_save_ifaceobjcurr(self, ifaceobj):
""" creates a copy of iface object and adds it to the iface
dict containing current iface objects
dict containing current iface objects
"""
ifaceobjcurr = iface()
ifaceobjcurr.name = ifaceobj.name
@@ -409,7 +457,7 @@ class ifupdownMain(ifupdownBase):
def is_iface_builtin_byname(self, ifacename):
""" Returns true if iface name is a builtin interface.
A builtin interface is an interface which ifupdown understands.
The following are currently considered builtin ifaces:
- vlan interfaces in the format <ifacename>.<vlanid>
@@ -418,7 +466,7 @@ class ifupdownMain(ifupdownBase):
def is_ifaceobj_builtin(self, ifaceobj):
""" Returns true if iface name is a builtin interface.
A builtin interface is an interface which ifupdown understands.
The following are currently considered builtin ifaces:
- vlan interfaces in the format <ifacename>.<vlanid>
@@ -429,7 +477,7 @@ class ifupdownMain(ifupdownBase):
def is_ifaceobj_noconfig(self, ifaceobj):
""" Returns true if iface object did not have a user defined config.
These interfaces appear only when they are dependents of interfaces
which have user defined config
"""
@@ -468,7 +516,7 @@ class ifupdownMain(ifupdownBase):
def _set_iface_role(self, ifaceobj, role, upperifaceobj):
if (self.flags.CHECK_SHARED_DEPENDENTS and
(ifaceobj.role & ifaceRole.SLAVE) and
(role == ifaceRole.SLAVE) and (upperifaceobj.role == ifaceRole.MASTER)):
(role == ifaceRole.SLAVE) and (upperifaceobj.role & ifaceRole.MASTER)):
self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
%(ifaceobj.name,
ifaceLinkPrivFlags.get_all_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
@@ -510,7 +558,7 @@ class ifupdownMain(ifupdownBase):
ifaceobj.link_type = ifaceLinkType.LINK_NA
def dump_iface_dependency_info(self):
""" debug funtion to print raw dependency
""" debug funtion to print raw dependency
info - lower and upper devices"""
for ifacename, ifaceobjs in self.ifaceobjdict.iteritems():
@@ -892,6 +940,13 @@ class ifupdownMain(ifupdownBase):
self.logger.debug('keyword: interface list with value: %s' % str(e))
return False
def _keyword_interface_on_off_list(self, value, validrange=None):
"""
<yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
ex: bridge-learning swp1=on swp2=off
"""
return self._keyword_interface_list_with_value(value, ['on', 'off'])
def _keyword_interface_yes_no_list(self, value, validrange=None):
"""
<yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
@@ -908,6 +963,30 @@ class ifupdownMain(ifupdownBase):
return self._keyword_interface_list_with_value(value,
['yes', 'no', 'auto'])
def _keyword_interface_l2protocol_tunnel_list(self, value, validrange=None):
"""
bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all
bridge-l2protocol-tunnel lacp stp,lldp,cdp
bridge-l2protocol-tunnel stp lacp cdp
bridge-l2protocol-tunnel lldp pvst
bridge-l2protocol-tunnel stp
bridge-l2protocol-tunnel all
"""
try:
if '=' in value:
for intf_arg in value.split():
intf_arg_split = intf_arg.split('=')
for arg in re.split(',|\s*', intf_arg_split[1]):
if arg not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
return False
else:
for arg in re.split(',|\s*', value):
if arg not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
return False
except:
return False
return True
def _keyword_interface_yes_no_0_1_list(self, value, validrange=None):
"""
<yes|no|0|1> |
@@ -915,16 +994,25 @@ class ifupdownMain(ifupdownBase):
ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
"""
return self._keyword_interface_list_with_value(value,
['yes', 'no', '1', '0'])
['yes', 'no', '1', '0', '2'])
def _keyword_interface_range_list(self, value, validrange):
def _keyword_interface_disabled_automatic_enabled_list(self, value, validrange=None):
return self._keyword_interface_list_with_value(value, [
'0', 'disabled', 'no',
'1', 'automatic', 'yes',
'2', 'enabled'])
def _keyword_interface_range_list_multiple_of_16(self, value, validrange):
return self._keyword_interface_range_list(value, validrange, multiple=16)
def _keyword_interface_range_list(self, value, validrange, multiple=None):
"""
<number> | ( <interface>=<number> [ <interface>=number> ...] )
ex: mstpctl-portpathcost swp1=0 swp2=1
"""
values = value.split()
try:
if len(values) == 1:
if len(values) == 1 and '=' not in values[0]:
try:
n = int(values[0])
if n < int(validrange[0]) or n > int(
@@ -933,6 +1021,11 @@ class ifupdownMain(ifupdownBase):
' valid attribute range: %s'
% (values[0],
'-'.join(validrange)))
if multiple is not None:
if not (n % multiple == 0):
raise invalidValueError('invalid value %s: must be a multiple of %s' % (n, multiple))
return True
except invalidValueError as e:
raise e
@@ -954,6 +1047,11 @@ class ifupdownMain(ifupdownBase):
% (iface_value[1],
iface_value[0],
'-'.join(validrange)))
if multiple is not None:
if not (number % multiple == 0):
raise invalidValueError('invalid value %s: must be a multiple of %s' % (number, multiple))
return True
except invalidValueError as e:
raise e
@@ -1059,6 +1157,8 @@ class ifupdownMain(ifupdownBase):
'message': 'invalid value "%s": valid attribute values: %s'
% (value, validvals)
}
elif validvals and value in validvals:
pass
elif validrange:
if len(validrange) != 2:
raise Exception('%s: invalid range in addon configuration'
@@ -1202,45 +1302,51 @@ class ifupdownMain(ifupdownBase):
self.logger.warn('error reading line \'%s\' %s:' %(l, str(e)))
continue
def load_addon_modules(self, modules_dir):
def load_addon_modules(self, modules_dir_list):
""" load python modules from modules_dir
Default modules_dir is /usr/share/ifupdownmodules
"""
self.logger.info('loading builtin modules from %s' %modules_dir)
failed_import = list()
self.logger.info('loading builtin modules from %s' % str(modules_dir_list))
self._load_addon_modules_config()
if not modules_dir in sys.path:
sys.path.append(modules_dir)
try:
for op, mlist in self.module_ops.items():
for mname in mlist:
if self.modules.get(mname):
continue
mpath = modules_dir + '/' + mname + '.py'
if os.path.exists(mpath):
try:
m = __import__(mname)
mclass = getattr(m, mname)
except:
raise
try:
minstance = mclass()
script_override = minstance.get_overrides_ifupdown_scripts()
self.overridden_ifupdown_scripts.extend(script_override)
except moduleNotSupported, e:
self.logger.info('module %s not loaded (%s)\n'
%(mname, str(e)))
for modules_dir in modules_dir_list:
if not modules_dir in sys.path:
sys.path.insert(1, modules_dir)
try:
for op, mlist in self.module_ops.items():
for mname in mlist:
if self.modules.get(mname):
continue
except:
raise
self.modules[mname] = minstance
try:
self.module_attrs[mname] = minstance.get_modinfo()
except:
pass
except:
raise
mpath = modules_dir + '/' + mname + '.py'
if os.path.exists(mpath) and mpath not in failed_import:
try:
m = __import__(mname)
mclass = getattr(m, mname)
except Exception as e:
self.logger.warning('cannot load "%s" module: %s' % (mname, str(e)))
failed_import.append(mpath)
continue
try:
minstance = mclass()
script_override = minstance.get_overrides_ifupdown_scripts()
self.overridden_ifupdown_scripts.extend(script_override)
except moduleNotSupported, e:
self.logger.info('module %s not loaded (%s)\n'
%(mname, str(e)))
continue
except:
raise
self.modules[mname] = minstance
try:
self.module_attrs[mname] = minstance.get_modinfo()
except:
pass
except:
raise
# Assign all modules to query operations
self.module_ops['query-checkcurr'] = self.modules.keys()
@@ -1249,52 +1355,65 @@ class ifupdownMain(ifupdownBase):
self.module_ops['query'] = self.modules.keys()
self.module_ops['query-raw'] = self.modules.keys()
def _keyword_number_comma_range_list(self, value, validrange=None):
return self._keyword_number_range_list(value.replace(',', ' '), validrange=validrange)
def _modules_help(self):
def _modules_help(self, fmt):
""" Prints addon modules supported syntax """
indent = ' '
for m, mdict in self.module_attrs.items():
if not mdict:
continue
print('%s: %s' %(m, mdict.get('mhelp')))
attrdict = mdict.get('attrs')
if not attrdict:
continue
try:
for attrname, attrvaldict in attrdict.items():
if attrvaldict.get('compat', False):
continue
print('%s%s' %(indent, attrname))
print('%shelp: %s' %(indent + ' ',
attrvaldict.get('help', '')))
print ('%srequired: %s' %(indent + ' ',
attrvaldict.get('required', False)))
default = attrvaldict.get('default')
if default:
print('%sdefault: %s' %(indent + ' ', default))
if fmt == 'json':
modinfos = {}
for key, value in self.modules.items():
if hasattr(value, '_modinfo'):
modinfos[key] = {
'mhelp': value._modinfo['mhelp'],
'attrs': value.merge_modinfo_with_policy_files()
}
print json.dumps(modinfos)
else:
indent = ' '
for m, mdict in self.module_attrs.items():
if not mdict:
continue
print('%s: %s' %(m, mdict.get('mhelp')))
attrdict = self.modules[m].merge_modinfo_with_policy_files()
if not attrdict:
continue
try:
for attrname, attrvaldict in attrdict.items():
if attrvaldict.get('compat', False):
continue
print('%s%s' %(indent, attrname))
print('%shelp: %s' %(indent + ' ',
attrvaldict.get('help', '')))
print ('%srequired: %s' %(indent + ' ',
attrvaldict.get('required', False)))
default = attrvaldict.get('default')
if default:
print('%sdefault: %s' %(indent + ' ', default))
validrange = attrvaldict.get('validrange')
if validrange:
print('%svalidrange: %s-%s'
%(indent + ' ', validrange[0], validrange[1]))
validrange = attrvaldict.get('validrange')
if validrange:
print('%svalidrange: %s-%s'
%(indent + ' ', validrange[0], validrange[1]))
validvals = attrvaldict.get('validvals')
if validvals:
print('%svalidvals: %s'
%(indent + ' ', ','.join(validvals)))
validvals = attrvaldict.get('validvals')
if validvals:
print('%svalidvals: %s'
%(indent + ' ', ','.join(validvals)))
examples = attrvaldict.get('example')
if not examples:
continue
examples = attrvaldict.get('example')
if not examples:
continue
print '%sexample:' %(indent + ' ')
for e in examples:
print '%s%s' %(indent + ' ', e)
except:
pass
print ''
print '%sexample:' %(indent + ' ')
for e in examples:
print '%s%s' %(indent + ' ', e)
except:
pass
print ''
def load_scripts(self, modules_dir):
""" loading user modules from /etc/network/.
@@ -1313,7 +1432,7 @@ class ifupdownMain(ifupdownBase):
if self.modules.get(module) or module in self.overridden_ifupdown_scripts:
continue
self.script_ops[op].append(msubdir + '/' + module)
except:
except:
# continue reading
pass
@@ -1324,13 +1443,13 @@ class ifupdownMain(ifupdownBase):
self._pretty_print_ordered_dict('dependency graph',
self.dependency_graph)
ifaceScheduler.sched_ifaces(self, ifacenames, ops,
dependency_graph=self.dependency_graph,
order=ifaceSchedulerFlags.INORDER
dependency_graph=self.dependency_graph,
order=ifaceSchedulerFlags.INORDER
if 'down' in ops[0]
else ifaceSchedulerFlags.POSTORDER,
followdependents=followdependents,
skipupperifaces=skipupperifaces,
sort=True if (sort or ifupdownflags.flags.CLASS) else False)
followdependents=followdependents,
skipupperifaces=skipupperifaces,
sort=True if (sort or ifupdownflags.flags.CLASS) else False)
return ifaceScheduler.get_sched_status()
def _render_ifacename(self, ifacename):
@@ -1346,7 +1465,7 @@ class ifupdownMain(ifupdownBase):
def _preprocess_ifacenames(self, ifacenames):
""" validates interface list for config existance.
returns -1 if one or more interface not found. else, returns 0
"""
@@ -1370,7 +1489,7 @@ class ifupdownMain(ifupdownBase):
new_ifacenames.append(i)
if err_iface:
raise Exception('cannot find interfaces:%s' %err_iface)
return new_ifacenames
return new_ifacenames
def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
""" Checks if interface is whitelisted depending on set of parameters.
@@ -1403,7 +1522,7 @@ class ifupdownMain(ifupdownBase):
ret = False
for i in ifaceobjs:
if i.classes:
common = Set([allow_classes]).intersection(
common = Set(allow_classes).intersection(
Set(i.classes))
if common:
ret = True
@@ -1500,7 +1619,7 @@ class ifupdownMain(ifupdownBase):
excludepats=None, printdependency=None, syntaxcheck=False,
type=None, skipupperifaces=False):
"""This brings the interface(s) up
Args:
ops (list): list of ops to perform on the interface(s).
Eg: ['pre-up', 'up', 'post-up'
@@ -1527,16 +1646,22 @@ class ifupdownMain(ifupdownBase):
except Exception:
raise
filtered_ifacenames = None
if ifacenames:
ifacenames = self._preprocess_ifacenames(ifacenames)
if allow_classes:
filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
# if iface list not given by user, assume all from config file
if not ifacenames: ifacenames = self.ifaceobjdict.keys()
# filter interfaces based on auto and allow classes
filtered_ifacenames = [i for i in ifacenames
if self._iface_whitelisted(auto, allow_classes,
if not filtered_ifacenames:
# filter interfaces based on auto and allow classes
filtered_ifacenames = [i for i in ifacenames
if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
if not filtered_ifacenames:
raise Exception('no ifaces found matching given allow lists')
@@ -1574,6 +1699,21 @@ class ifupdownMain(ifupdownBase):
if not iface_read_ret or not ret:
raise Exception()
def _get_filtered_ifacenames_with_classes(self, auto, allow_classes, excludepats, ifacenames):
# if user has specified ifacelist and allow_classes
# append the allow_classes interfaces to user
# ifacelist
filtered_ifacenames = [i for i in self.ifaceobjdict.keys()
if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
filtered_ifacenames += ifacenames
for intf in ifacenames:
for obj in self.get_ifaceobjs(intf) or []:
obj.blacklisted = False
return filtered_ifacenames
def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
excludepats=None, printdependency=None, usecurrentconfig=False,
type=None):
@@ -1597,27 +1737,35 @@ class ifupdownMain(ifupdownBase):
self.logger.debug('Looking at old state ..')
self.read_old_iface_config()
else:
# If no old state available
# If no old state available
try:
self.read_iface_config()
except Exception, e:
raise Exception('error reading iface config (%s)' %str(e))
filtered_ifacenames = None
if ifacenames:
# If iface list is given by the caller, always check if iface
# is present
try:
ifacenames = self._preprocess_ifacenames(ifacenames)
if allow_classes:
filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
except Exception, e:
raise Exception('%s' %str(e) +
' (interface was probably never up ?)')
# if iface list not given by user, assume all from config file
if not ifacenames: ifacenames = self.ifaceobjdict.keys()
# filter interfaces based on auto and allow classes
filtered_ifacenames = [i for i in ifacenames
if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
if not filtered_ifacenames:
# filter interfaces based on auto and allow classes
filtered_ifacenames = [i for i in ifacenames
if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
if not filtered_ifacenames:
raise Exception('no ifaces found matching given allow lists ' +
'(or interfaces were probably never up ?)')
@@ -1646,7 +1794,7 @@ class ifupdownMain(ifupdownBase):
self.set_type(type)
# Let us forget internal squashing when it comes to
# Let us forget internal squashing when it comes to
# ifquery. It can surprise people relying of ifquery
# output
self._ifaceobj_squash_internal = False
@@ -1662,7 +1810,7 @@ class ifupdownMain(ifupdownBase):
ifupdownflags.flags.WITH_DEPENDS = True
if ops[0] == 'query-syntax':
self._modules_help()
self._modules_help(format)
return
elif ops[0] == 'query-running':
# create fake devices to all dependents that dont have config
@@ -1675,8 +1823,11 @@ class ifupdownMain(ifupdownBase):
raise
if ifacenames and ops[0] != 'query-running':
# If iface list is given, always check if iface is present
ifacenames = self._preprocess_ifacenames(ifacenames)
# If iface list is given, always check if iface is present
ifacenames = self._preprocess_ifacenames(ifacenames)
if allow_classes:
filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
# if iface list not given by user, assume all from config file
if not ifacenames: ifacenames = self.ifaceobjdict.keys()
@@ -1684,10 +1835,16 @@ class ifupdownMain(ifupdownBase):
# filter interfaces based on auto and allow classes
if ops[0] == 'query-running':
filtered_ifacenames = ifacenames
else:
filtered_ifacenames = [i for i in ifacenames
if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
elif not allow_classes:
filtered_ifacenames = [
i for i in ifacenames
if self._iface_whitelisted(
auto,
allow_classes,
excludepats, i
)
]
if not filtered_ifacenames:
raise Exception('no ifaces found matching ' +
'given allow lists')
@@ -1706,7 +1863,7 @@ class ifupdownMain(ifupdownBase):
return self.print_ifaceobjs_raw(filtered_ifacenames)
ret = self._sched_ifaces(filtered_ifacenames, ops,
followdependents=True
followdependents=True
if ifupdownflags.flags.WITH_DEPENDS else False)
if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS:
@@ -1778,7 +1935,7 @@ class ifupdownMain(ifupdownBase):
# old interface config is read into self.ifaceobjdict
self.read_old_iface_config()
# reinitialize dependency graph
# reinitialize dependency graph
self.dependency_graph = OrderedDict({})
falready_up_ifacenames_not_present = [i for i in
already_up_ifacenames_not_present
@@ -1882,14 +2039,14 @@ class ifupdownMain(ifupdownBase):
# these are saved interfaces and dependency for these
# have been checked before they became part of saved state.
try:
self.flags.CHECK_SHARED_DEPENDENTS = False
self.flags.CHECK_SHARED_DEPENDENTS = False
self.populate_dependency_info(upops)
self.flags.CHECK_SHARED_DEPENDENTS = True
except Exception, e:
self.logger.info("error generating dependency graph for "
"saved interfaces (%s)" %str(e))
pass
# make sure we pick up built-in interfaces
# if config file had 'ifreload_down_changed' variable
# set, also look for interfaces that changed to down them
@@ -1923,7 +2080,7 @@ class ifupdownMain(ifupdownBase):
# for example: remove a bond section from the interfaces
# file, but leave it around as a bridge port
# XXX: Ideally its better to just add it to the
# ifacedownlist. But we will be cautious here
# ifacedownlist. But we will be cautious here
# and just print a warning
if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
@@ -1936,6 +2093,16 @@ class ifupdownMain(ifupdownBase):
% (newifaceobjlist[objidx].name,
str(newifaceobjlist[objidx].upperifaces),
newifaceobjlist[objidx].name))
if (lastifaceobjlist[0].link_kind and
not newifaceobjlist[0].link_kind):
self.logger.warn('%s: moved from being a %s to a'
' physical interface (non-logical interface).'
'This interface will be downed.\n'
' If this was not intentional, please restore the'
' original interface definition and execute ifreload'
% (newifaceobjlist[objidx].name,
ifaceLinkKind.to_str(lastifaceobjlist[0].link_kind)))
ifacedownlist.append(newifaceobjlist[objidx].name)
if not down_changed:
continue
if len(newifaceobjlist) != len(lastifaceobjlist):
@@ -1955,7 +2122,7 @@ class ifupdownMain(ifupdownBase):
if ifacedownlist:
self.logger.info('reload: scheduling down on interfaces: %s'
%str(ifacedownlist))
# reinitialize dependency graph
# reinitialize dependency graph
self.dependency_graph = OrderedDict({})
# Generate dependency info for old config
@@ -1970,7 +2137,7 @@ class ifupdownMain(ifupdownBase):
# Hence during reload, set this to true.
# This is being added to avoid a failure in
# scheduler._check_upperifaces when we are dowing
# a builtin bridge port
# a builtin bridge port
self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
self._sched_ifaces(ifacedownlist, downops,
followdependents=False,
@@ -2065,11 +2232,9 @@ class ifupdownMain(ifupdownBase):
for i in ifacenames:
for ifaceobj in self.get_ifaceobjs(i):
if (self.is_ifaceobj_builtin(ifaceobj) or
not ifaceobj.is_config_present()):
if self.is_ifaceobj_builtin(ifaceobj):
continue
ifaceobj.dump_raw(self.logger)
print '\n'
if (ifupdownflags.flags.WITH_DEPENDS and
not ifupdownflags.flags.ALL):
dlist = ifaceobj.lowerifaces

183
ifupdown2/ifupdown/log.py Normal file
View File

@@ -0,0 +1,183 @@
#!/usr/bin/env python
#
# Copyright 2016-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Julien Fortin, julien@cumulusnetworks.com
#
import sys
import json
import struct
import select
import logging
import logging.handlers
from cStringIO import StringIO
class Log:
LOGGER_NAME = sys.argv[0].split('/')[-1]
def __init__(self):
"""
- On start the daemon will log on syslog.
- For each client commands we might need to adjust the target
(stderr/stdout):
if -v --verbose or -d --debug are provided we override
sys.stdout and sys.stderr with string buffers to be able to send
back the content of these buffer on the UNIX socket back to the
client.
if -l or --syslog we make sure to use syslog.
"""
self.stdout_buffer = None
self.stderr_buffer = None
self.root = logging.getLogger()
self.root.name = Log.LOGGER_NAME
self.root.setLevel(logging.INFO)
self.root_info = self.root.info
self.root_debug = self.root.debug
self.root_error = self.root.error
self.root_warning = self.root.warning
self.root_critical = self.root.critical
self.root.info = self.info
self.root.debug = self.debug
self.root.error = self.error
self.root.warning = self.warning
self.root.critical = self.critical
logging.addLevelName(logging.CRITICAL, 'critical')
logging.addLevelName(logging.WARNING, 'warning')
logging.addLevelName(logging.ERROR, 'error')
logging.addLevelName(logging.DEBUG, 'debug')
logging.addLevelName(logging.INFO, 'info')
self.syslog = True
self.socket = None
# syslog
facility = logging.handlers.SysLogHandler.LOG_DAEMON
address = '/dev/log'
format = '%(name)s: %(levelname)s: %(message)s'
self.syslog_handler = logging.handlers.SysLogHandler(address=address, facility=facility)
self.syslog_handler.setFormatter(logging.Formatter(format))
# console
format = '%(levelname)s: %(message)s'
self.console_handler = logging.StreamHandler(sys.stderr)
self.console_handler.setFormatter(logging.Formatter(format))
if self.LOGGER_NAME[-1] == 'd':
self.update_current_logger(syslog=True, verbose=True, debug=False)
else:
self.update_current_logger(syslog=False, verbose=False, debug=False)
def update_current_logger(self, syslog, verbose, debug):
self.syslog = syslog
self.root.setLevel(self.get_log_level(verbose=verbose, debug=debug))
self.root.handlers = [self.syslog_handler if self.syslog else self.console_handler]
self.flush()
def flush(self):
if self.socket:
result = dict()
stdout = self._flush_buffer('stdout', self.stdout_buffer, result)
stderr = self._flush_buffer('stderr', self.stderr_buffer, result)
if stdout or stderr:
try:
self.tx_data(json.dumps(result))
self.redirect_stdouput()
except select.error as e:
# haven't seen the case yet
self.socket = None
self.update_current_logger(syslog=True, verbose=True)
self.critical(str(e))
exit(84)
self.console_handler.flush()
self.syslog_handler.flush()
def tx_data(self, data, socket=None):
socket_obj = socket if socket else self.socket
ready = select.select([], [socket_obj], [])
if ready and ready[1] and ready[1][0] == socket_obj:
frmt = "=%ds" % len(data)
packed_msg = struct.pack(frmt, data)
packed_hdr = struct.pack('=I', len(packed_msg))
socket_obj.sendall(packed_hdr)
socket_obj.sendall(packed_msg)
def set_socket(self, socket):
self.socket = socket
self.redirect_stdouput()
def redirect_stdouput(self):
self.stdout_buffer = sys.stdout = StringIO()
self.stderr_buffer = self.console_handler.stream = sys.stderr = StringIO()
def error(self, msg, *args, **kwargs):
self.root_error(msg, *args, **kwargs)
self.flush()
def critical(self, msg, *args, **kwargs):
self.root_critical(msg, *args, **kwargs)
self.flush()
def warning(self, msg, *args, **kwargs):
self.root_warning(msg, *args, **kwargs)
self.flush()
def info(self, msg, *args, **kwargs):
self.root_info(msg, *args, **kwargs)
self.flush()
def debug(self, msg, *args, **kwargs):
self.root_debug(msg, *args, **kwargs)
self.flush()
def get_current_log_level(self):
return self.root.level
def is_syslog(self): return self.syslog
@staticmethod
def get_log_level(verbose=False, debug=False):
log_level = logging.WARNING
if debug:
log_level = logging.DEBUG
elif verbose:
log_level = logging.INFO
return log_level
@staticmethod
def _flush_buffer(stream, buff, dictionary):
if buff:
data = buff.getvalue()
if data:
dictionary[stream] = data
return True
log = Log()
"""
#logging.basicConfig( format="%(filename)s: %(username)s says '%(message)s' in %(funcname)s" )
Logger.debug(msg, *args, **kwargs)
Logs a message with level DEBUG on this logger. The msg is the message format string, and the args are the arguments which are merged into msg using the string formatting operator. (Note that this means that you can use keywords in the format string, together with a single dictionary argument.)
There are two keyword arguments in kwargs which are inspected: exc_info which, if it does not evaluate as false, causes exception information to be added to the logging message. If an exception tuple (in the format returned by sys.exc_info()) is provided, it is used; otherwise, sys.exc_info() is called to get the exception information.
"""
"""
USE FILTER TO IGNORE "EXITS" MESSAGES
Now that you know the basic plot, let me introduce one more character - the Filter.
Filter as the name suggests, allows you to filter a message before you log it. Yes, messages are filtered based on the level setting, but adding a Filter gives you more fine grained control of messages you log.
Both Loggers and Handlers can have multiple Filters. You can add Filters using addFilter and removeFilter methods.
When a Logger/Handler receives a message, it consults all of its filters. If the filter(record) method on any of the Filters attached returns False (or 0) the message is dropped.
The official documentation, though detailed, is actually pretty confusing about the role of Filters. This is a pity; because Filters can be handy when you want to drop a message based on a regular expression, error code, contextual information and pretty much anything else. The default Filter is pretty much useless (and the doc string is very confusing too). Just inherit from the default filter and override the filter method according to what you want to filter out. (Be sure to download the source for logging module and check out the unit tests which have some good examples. See the references at the end of this post.)"""

277
ifupdown2/ifupdown/main.py Normal file
View File

@@ -0,0 +1,277 @@
#!/usr/bin/python
#
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Authors:
# Roopa Prabhu, roopa@cumulusnetworks.com
# Julien Fortin, julien@cumulusnetworks.com
# ifupdown2 --
# tool to configure network interfaces
#
import os
import sys
import signal
import StringIO
import ConfigParser
try:
from ifupdown2.ifupdown.log import log
from ifupdown2.ifupdown.argv import Parse
from ifupdown2.ifupdown.config import IFUPDOWN2_CONF_PATH
from ifupdown2.ifupdown.ifupdownmain import ifupdownMain
except ImportError:
from ifupdown.log import log
from ifupdown.argv import Parse
from ifupdown.config import IFUPDOWN2_CONF_PATH
from ifupdown.ifupdownmain import ifupdownMain
_SIGINT = signal.getsignal(signal.SIGINT)
_SIGTERM = signal.getsignal(signal.SIGTERM)
_SIGQUIT = signal.getsignal(signal.SIGQUIT)
configmap_g = None
class Ifupdown2:
def __init__(self, daemon, uid):
self.daemon = daemon
self.uid = uid
self.args = None
self.op = None
self.interfaces_filename = None
self.interfaces_file_iobuf = None
self.handlers = {
'up': self.run_up,
'down': self.run_down,
'query': self.run_query,
'reload': self.run_reload
}
def parse_argv(self, argv):
args_parse = Parse(argv)
args_parse.validate()
self.args = args_parse.get_args()
self.op = args_parse.get_op()
def update_logger(self, socket=None):
syslog = self.args.syslog if hasattr(self.args, 'syslog') else False
log.update_current_logger(syslog=syslog,
verbose=self.args.verbose,
debug=self.args.debug)
if socket:
log.set_socket(socket)
def main(self, stdin_buffer=None):
if self.op != 'query' and self.uid != 0:
raise Exception('must be root to run this command')
try:
self.read_config()
self.init(stdin_buffer)
self.handlers.get(self.op)(self.args)
except Exception, e:
if not str(e):
return 1
# if args and args.debug:
raise
# else:
if log:
log.error(str(e))
else:
print str(e)
# if args and not args.debug:
# print '\nrerun the command with \'-d\' for a detailed errormsg'
return 1
return 0
def init(self, stdin_buffer):
if hasattr(self.args, 'interfacesfile') and self.args.interfacesfile != None:
# Check to see if -i option is allowed by config file
# But for ifquery, we will not check this
if (not self.op == 'query' and
configmap_g.get('disable_cli_interfacesfile', '0') == '1'):
log.error('disable_cli_interfacesfile is set so users '
'not allowed to specify interfaces file on cli.')
raise Exception("")
if self.args.interfacesfile == '-':
# If interfaces file is stdin, read
if self.daemon:
self.interfaces_file_iobuf = stdin_buffer
else:
self.interfaces_file_iobuf = sys.stdin.read()
else:
self.interfaces_filename = self.args.interfacesfile
else:
# if the ifupdown2 config file does not have it, default to standard
self.interfaces_filename = configmap_g.get('default_interfaces_configfile',
'/etc/network/interfaces')
def read_config(self):
global configmap_g
with open(IFUPDOWN2_CONF_PATH, 'r') as f:
config = f.read()
configStr = '[ifupdown2]\n' + config
configFP = StringIO.StringIO(configStr)
parser = ConfigParser.RawConfigParser()
parser.readfp(configFP)
configmap_g = dict(parser.items('ifupdown2'))
# Preprocess config map
configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0')
if configval == '0':
# if multiple bridges not allowed, set the bridge-vlan-aware
# attribute in the 'no_repeats' config, so that the ifupdownmain
# module can catch it appropriately
configmap_g['no_repeats'] = {'bridge-vlan-aware': 'yes'}
configval = configmap_g.get('link_master_slave', '0')
if configval == '1':
# link_master_slave is only valid when all is set
if hasattr(self.args, 'all') and not self.args.all:
configmap_g['link_master_slave'] = '0'
configval = configmap_g.get('delay_admin_state_change', '0')
if configval == '1':
# reset link_master_slave if delay_admin_state_change is on
configmap_g['link_master_slave'] = '0'
def run_up(self, args):
log.debug('args = %s' % str(args))
try:
iflist = args.iflist
if len(args.iflist) == 0:
iflist = None
log.debug('creating ifupdown object ..')
cachearg = (False if (iflist or args.nocache or args.noact)
else True)
ifupdown_handle = ifupdownMain(daemon=self.daemon,
config=configmap_g,
force=args.force,
withdepends=args.withdepends,
perfmode=args.perfmode,
dryrun=args.noact,
cache=cachearg,
addons_enable=not args.noaddons,
statemanager_enable=not args.noaddons,
interfacesfile=self.interfaces_filename,
interfacesfileiobuf=self.interfaces_file_iobuf,
interfacesfileformat=args.interfacesfileformat)
if args.noaddons:
ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
excludepats=args.excludepats,
printdependency=args.printdependency,
syntaxcheck=args.syntaxcheck, type=args.type,
skipupperifaces=args.skipupperifaces)
else:
ifupdown_handle.up(['pre-up', 'up', 'post-up'],
args.all, args.CLASS, iflist,
excludepats=args.excludepats,
printdependency=args.printdependency,
syntaxcheck=args.syntaxcheck, type=args.type,
skipupperifaces=args.skipupperifaces)
except:
raise
def run_down(self, args):
log.debug('args = %s' % str(args))
try:
iflist = args.iflist
log.debug('creating ifupdown object ..')
ifupdown_handle = ifupdownMain(daemon=self.daemon,
config=configmap_g, force=args.force,
withdepends=args.withdepends,
perfmode=args.perfmode,
dryrun=args.noact,
addons_enable=not args.noaddons,
statemanager_enable=not args.noaddons,
interfacesfile=self.interfaces_filename,
interfacesfileiobuf=self.interfaces_file_iobuf,
interfacesfileformat=args.interfacesfileformat)
ifupdown_handle.down(['pre-down', 'down', 'post-down'],
args.all, args.CLASS, iflist,
excludepats=args.excludepats,
printdependency=args.printdependency,
usecurrentconfig=args.usecurrentconfig,
type=args.type)
except:
raise
def run_query(self, args):
log.debug('args = %s' % str(args))
try:
iflist = args.iflist
if args.checkcurr:
qop = 'query-checkcurr'
elif args.running:
qop = 'query-running'
elif args.raw:
qop = 'query-raw'
elif args.syntaxhelp:
qop = 'query-syntax'
elif args.printdependency:
qop = 'query-dependency'
elif args.printsavedstate:
qop = 'query-savedstate'
else:
qop = 'query'
cachearg = (False if (iflist or args.nocache or args.syntaxhelp or
(qop != 'query-checkcurr' and
qop != 'query-running')) else True)
if not iflist and qop == 'query-running':
iflist = [i for i in os.listdir('/sys/class/net/')
if os.path.isdir('/sys/class/net/%s' % i)]
log.debug('creating ifupdown object ..')
ifupdown_handle = ifupdownMain(daemon=self.daemon,
config=configmap_g,
withdepends=args.withdepends,
perfmode=args.perfmode,
cache=cachearg,
interfacesfile=self.interfaces_filename,
interfacesfileiobuf=self.interfaces_file_iobuf,
interfacesfileformat=args.interfacesfileformat,
withdefaults=args.withdefaults)
# list implies all auto interfaces (this is how ifupdown behaves)
if args.list:
args.all = True
ifupdown_handle.query([qop], args.all, args.list, args.CLASS, iflist,
excludepats=args.excludepats,
printdependency=args.printdependency,
format=args.format, type=args.type)
except:
raise
def run_reload(self, args):
log.debug('args = %s' % str(args))
try:
log.debug('creating ifupdown object ..')
ifupdown_handle = ifupdownMain(daemon=self.daemon,
config=configmap_g,
interfacesfile=self.interfaces_filename,
withdepends=args.withdepends,
perfmode=args.perfmode,
dryrun=args.noact)
ifupdown_handle.reload(['pre-up', 'up', 'post-up'],
['pre-down', 'down', 'post-down'],
auto=args.all, allow=args.CLASS, ifacenames=None,
excludepats=args.excludepats,
usecurrentconfig=args.usecurrentconfig,
syntaxcheck=args.syntaxcheck,
currentlyup=args.currentlyup)
except:
raise
@staticmethod
def set_signal_handlers():
signal.signal(signal.SIGQUIT, _SIGQUIT)
signal.signal(signal.SIGTERM, _SIGTERM)
signal.signal(signal.SIGINT, _SIGINT)

View File

@@ -0,0 +1,627 @@
#!/usr/bin/python
#
# Copyright 2016-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Julien Fortin, julien@cumulusnetworks.com
#
import sys
import socket
import logging
from collections import OrderedDict
try:
import ifupdown2.nlmanager.nlpacket
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
from ifupdown2.ifupdownaddons.cache import *
from ifupdown2.ifupdownaddons.utilsbase import utilsBase
from ifupdown2.nlmanager.nlmanager import Link, Address, Route, NetlinkPacket
except ImportError:
import nlmanager.nlpacket
import ifupdown.ifupdownflags as ifupdownflags
from ifupdownaddons.cache import *
from ifupdownaddons.utilsbase import utilsBase
from nlmanager.nlmanager import Link, Address, Route, NetlinkPacket
class Netlink(utilsBase):
VXLAN_UDP_PORT = 4789
def __init__(self, *args, **kargs):
utilsBase.__init__(self, *args, **kargs)
try:
sys.path.insert(0, '/usr/share/ifupdown2/')
try:
from ifupdown2.nlmanager.nlmanager import NetlinkManager
# Override the nlmanager's mac_int_to_str function to print the MACs
# like xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
ifupdown2.nlmanager.nlpacket.mac_int_to_str = self.mac_int_to_str
except ImportError:
from nlmanager.nlmanager import NetlinkManager
# Override the nlmanager's mac_int_to_str function to print the MACs
# like xx:xx:xx:xx:xx:xx instead of xxxx.xxxx.xxxx
nlmanager.nlpacket.mac_int_to_str = self.mac_int_to_str
# this should force the use of the local nlmanager
self._nlmanager_api = NetlinkManager(log_level=logging.WARNING)
self.link_kind_handlers = {
'vlan': self._link_dump_info_data_vlan,
'vrf': self._link_dump_info_data_vrf,
'vxlan': self._link_dump_info_data_vxlan,
'bond': self._link_dump_info_data_bond,
'bridge': self._link_dump_info_data_bridge
}
except Exception as e:
self.logger.error('cannot initialize ifupdown2\'s '
'netlink manager: %s' % str(e))
raise
@staticmethod
def IN_MULTICAST(a):
"""
/include/uapi/linux/in.h
#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
#define IN_MULTICAST(a) IN_CLASSD(a)
"""
return (int(a) & 0xf0000000) == 0xe0000000
@staticmethod
def mac_int_to_str(mac_int):
"""
Return an integer in MAC string format: xx:xx:xx:xx:xx:xx
"""
return ':'.join(("%012x" % mac_int)[i:i + 2] for i in range(0, 12, 2))
def get_iface_index(self, ifacename):
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.get_iface_index(ifacename)
except Exception as e:
raise Exception('%s: netlink: %s: cannot get ifindex: %s'
% (ifacename, ifacename, str(e)))
def get_iface_name(self, ifindex):
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.get_iface_name(ifindex)
except Exception as e:
raise Exception('netlink: cannot get ifname for index %s: %s' % (ifindex, str(e)))
def get_bridge_vlan(self, ifname):
self.logger.info('%s: netlink: /sbin/bridge -d -c -json vlan show' % ifname)
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.vlan_get()
except Exception as e:
raise Exception('netlink: get bridge vlan: %s' % str(e))
def bridge_set_vlan_filtering(self, ifname, vlan_filtering):
self.logger.info('%s: netlink: ip link set dev %s type bridge vlan_filtering %s'
% (ifname, ifname, vlan_filtering))
if ifupdownflags.flags.DRYRUN: return
try:
ifla_info_data = {Link.IFLA_BR_VLAN_FILTERING: int(vlan_filtering)}
return self._nlmanager_api.link_set_attrs(ifname, 'bridge', ifla_info_data=ifla_info_data)
except Exception as e:
raise Exception('%s: cannot set %s vlan_filtering %s' % (ifname, ifname, vlan_filtering))
def link_add_set(self,
ifname=None, ifindex=0,
kind=None, slave_kind=None,
ifla={},
ifla_info_data={},
ifla_info_slave_data={},
link_exists=False):
action = 'set' if ifindex or link_exists else 'add'
if slave_kind:
self.logger.info('%s: netlink: ip link set dev %s: %s slave attributes' % (ifname, ifname, slave_kind))
else:
self.logger.info('%s: netlink: ip link %s %s type %s with attributes' % (ifname, action, ifname, kind))
if ifla:
self.logger.debug('%s: ifla attributes a %s' % (ifname, ifla))
if ifla_info_data:
self.logger.debug('%s: ifla_info_data %s' % (ifname, ifla_info_data))
if ifla_info_slave_data:
self.logger.debug('%s: ifla_info_slave_data %s' % (ifname, ifla_info_slave_data))
if ifupdownflags.flags.DRYRUN: return
try:
self._nlmanager_api.link_add_set(ifname=ifname,
ifindex=ifindex,
kind=kind,
slave_kind=slave_kind,
ifla=ifla,
ifla_info_data=ifla_info_data,
ifla_info_slave_data=ifla_info_slave_data)
except Exception as e:
if kind and not slave_kind:
kind_str = kind
elif kind and slave_kind:
kind_str = '%s (%s slave)' % (kind, slave_kind)
else:
kind_str = '(%s slave)' % slave_kind
raise Exception('netlink: cannot %s %s %s with options: %s' % (action, kind_str, ifname, str(e)))
def link_del(self, ifname):
self.logger.info('%s: netlink: ip link del %s' % (ifname, ifname))
if ifupdownflags.flags.DRYRUN: return
try:
self._nlmanager_api.link_del(ifname=ifname)
except Exception as e:
raise Exception('netlink: cannot delete link %s: %s' % (ifname, str(e)))
def link_set_master(self, ifacename, master_dev, state=None):
self.logger.info('%s: netlink: ip link set dev %s master %s %s'
% (ifacename, ifacename, master_dev,
state if state else ''))
if ifupdownflags.flags.DRYRUN: return
try:
master = 0 if not master_dev else self.get_iface_index(master_dev)
return self._nlmanager_api.link_set_master(ifacename,
master_ifindex=master,
state=state)
except Exception as e:
raise Exception('netlink: %s: cannot set %s master %s: %s'
% (ifacename, ifacename, master_dev, str(e)))
def link_set_nomaster(self, ifacename, state=None):
self.logger.info('%s: netlink: ip link set dev %s nomaster %s'
% (ifacename, ifacename, state if state else ''))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_set_master(ifacename,
master_ifindex=0,
state=state)
except Exception as e:
raise Exception('netlink: %s: cannot set %s nomaster: %s'
% (ifacename, ifacename, str(e)))
def link_add_vlan(self, vlanrawdevice, ifacename, vlanid, vlan_protocol):
if vlan_protocol:
self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s protocol %s'
% (ifacename, vlanrawdevice, ifacename, vlanid, vlan_protocol))
else:
self.logger.info('%s: netlink: ip link add link %s name %s type vlan id %s'
% (ifacename, vlanrawdevice, ifacename, vlanid))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(vlanrawdevice)
try:
return self._nlmanager_api.link_add_vlan(ifindex, ifacename, vlanid, vlan_protocol)
except Exception as e:
raise Exception('netlink: %s: cannot create vlan %s: %s'
% (vlanrawdevice, vlanid, str(e)))
def link_add_macvlan(self, ifacename, macvlan_ifacename):
self.logger.info('%s: netlink: ip link add link %s name %s type macvlan mode private'
% (ifacename, ifacename, macvlan_ifacename))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(ifacename)
try:
return self._nlmanager_api.link_add_macvlan(ifindex, macvlan_ifacename)
except Exception as e:
raise Exception('netlink: %s: cannot create macvlan %s: %s'
% (ifacename, macvlan_ifacename, str(e)))
def link_set_updown(self, ifacename, state):
self.logger.info('%s: netlink: ip link set dev %s %s'
% (ifacename, ifacename, state))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_set_updown(ifacename, state)
except Exception as e:
raise Exception('netlink: cannot set link %s %s: %s'
% (ifacename, state, str(e)))
def link_set_protodown(self, ifacename, state):
self.logger.info('%s: netlink: set link %s protodown %s'
% (ifacename, ifacename, state))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_set_protodown(ifacename, state)
except Exception as e:
raise Exception('netlink: cannot set link %s protodown %s: %s'
% (ifacename, state, str(e)))
def link_add_bridge(self, ifname):
self.logger.info('%s: netlink: ip link add %s type bridge' % (ifname, ifname))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_add_bridge(ifname)
except Exception as e:
raise Exception('netlink: cannot create bridge %s: %s' % (ifname, str(e)))
def link_add_bridge_vlan(self, ifacename, vlanid):
self.logger.info('%s: netlink: bridge vlan add vid %s dev %s'
% (ifacename, vlanid, ifacename))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(ifacename)
try:
return self._nlmanager_api.link_add_bridge_vlan(ifindex, vlanid)
except Exception as e:
raise Exception('netlink: %s: cannot create bridge vlan %s: %s'
% (ifacename, vlanid, str(e)))
def link_del_bridge_vlan(self, ifacename, vlanid):
self.logger.info('%s: netlink: bridge vlan del vid %s dev %s'
% (ifacename, vlanid, ifacename))
if ifupdownflags.flags.DRYRUN: return
ifindex = self.get_iface_index(ifacename)
try:
return self._nlmanager_api.link_del_bridge_vlan(ifindex, vlanid)
except Exception as e:
raise Exception('netlink: %s: cannot remove bridge vlan %s: %s'
% (ifacename, vlanid, str(e)))
def link_add_vxlan(self, ifacename, vxlanid, local=None, dstport=VXLAN_UDP_PORT,
group=None, learning=True, ageing=None):
cmd = 'ip link add %s type vxlan id %s dstport %s' % (ifacename,
vxlanid,
dstport)
cmd += ' local %s' % local if local else ''
cmd += ' ageing %s' % ageing if ageing else ''
cmd += ' remote %s' % group if group else ' noremote'
cmd += ' nolearning' if not learning else ''
self.logger.info('%s: netlink: %s' % (ifacename, cmd))
if ifupdownflags.flags.DRYRUN: return
try:
return self._nlmanager_api.link_add_vxlan(ifacename,
vxlanid,
dstport=dstport,
local=local,
group=group,
learning=learning,
ageing=ageing)
except Exception as e:
raise Exception('netlink: %s: cannot create vxlan %s: %s'
% (ifacename, vxlanid, str(e)))
@staticmethod
def _link_dump_attr(link, ifla_attributes, dump):
for obj in ifla_attributes:
attr = link.attributes.get(obj['attr'])
if attr:
dump[obj['name']] = attr.get_pretty_value(obj=obj.get('func'))
@staticmethod
def _link_dump_linkdata_attr(linkdata, ifla_linkdata_attr, dump):
for obj in ifla_linkdata_attr:
attr = obj['attr']
if attr in linkdata:
func = obj.get('func')
value = linkdata.get(attr)
if func:
value = func(value)
if value or obj['accept_none']:
dump[obj['name']] = value
ifla_attributes = [
{
'attr': Link.IFLA_LINK,
'name': 'link',
'func': lambda x: netlink.get_iface_name(x) if x > 0 else None
},
{
'attr': Link.IFLA_MASTER,
'name': 'master',
'func': lambda x: netlink.get_iface_name(x) if x > 0 else None
},
{
'attr': Link.IFLA_IFNAME,
'name': 'ifname',
'func': str,
},
{
'attr': Link.IFLA_MTU,
'name': 'mtu',
'func': str
},
{
'attr': Link.IFLA_OPERSTATE,
'name': 'state',
'func': lambda x: '0%x' % int(x) if x > len(Link.oper_to_string) else Link.oper_to_string[x][8:]
}
]
ifla_address = {'attr': Link.IFLA_ADDRESS, 'name': 'hwaddress', 'func': str}
ifla_vxlan_attributes = [
{
'attr': Link.IFLA_VXLAN_LOCAL,
'name': 'local',
'func': str,
'accept_none': True
},
{
'attr': Link.IFLA_VXLAN_LOCAL6,
'name': 'local',
'func': str,
'accept_none': True
},
{
'attr': Link.IFLA_VXLAN_GROUP,
'name': 'svcnode',
'func': lambda x: str(x) if not Netlink.IN_MULTICAST(x) else None,
'accept_none': False
},
{
'attr': Link.IFLA_VXLAN_GROUP6,
'name': 'svcnode',
'func': lambda x: str(x) if not Netlink.IN_MULTICAST(x) else None,
'accept_none': False
},
{
'attr': Link.IFLA_VXLAN_LEARNING,
'name': 'learning',
'func': lambda x: 'on' if x else 'off',
'accept_none': True
}
]
def _link_dump_info_data_vlan(self, ifname, linkdata):
return {
'vlanid': str(linkdata.get(Link.IFLA_VLAN_ID, '')),
'vlan_protocol': linkdata.get(Link.IFLA_VLAN_PROTOCOL)
}
def _link_dump_info_data_vrf(self, ifname, linkdata):
vrf_info = {'table': str(linkdata.get(Link.IFLA_VRF_TABLE, ''))}
# to remove later when moved to a true netlink cache
linkCache.vrfs[ifname] = vrf_info
return vrf_info
def _link_dump_info_data_vxlan(self, ifname, linkdata):
for attr, value in (
('learning', 'on'),
('svcnode', None),
('vxlanid', str(linkdata.get(Link.IFLA_VXLAN_ID, ''))),
('ageing', str(linkdata.get(Link.IFLA_VXLAN_AGEING, ''))),
(Link.IFLA_VXLAN_PORT, linkdata.get(Link.IFLA_VXLAN_PORT))
):
linkdata[attr] = value
self._link_dump_linkdata_attr(linkdata, self.ifla_vxlan_attributes, linkdata)
return linkdata
ifla_bond_attributes = (
Link.IFLA_BOND_MODE,
Link.IFLA_BOND_MIIMON,
Link.IFLA_BOND_USE_CARRIER,
Link.IFLA_BOND_AD_LACP_RATE,
Link.IFLA_BOND_XMIT_HASH_POLICY,
Link.IFLA_BOND_MIN_LINKS,
Link.IFLA_BOND_NUM_PEER_NOTIF,
Link.IFLA_BOND_AD_ACTOR_SYSTEM,
Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
Link.IFLA_BOND_AD_LACP_BYPASS,
Link.IFLA_BOND_UPDELAY,
Link.IFLA_BOND_DOWNDELAY,
)
def _link_dump_info_data_bond(self, ifname, linkdata):
linkinfo = {}
for nl_attr in self.ifla_bond_attributes:
try:
linkinfo[nl_attr] = linkdata.get(nl_attr)
except Exception as e:
self.logger.debug('%s: parsing bond IFLA_INFO_DATA (%s): %s'
% (ifname, nl_attr, str(e)))
return linkinfo
# this dict contains the netlink attribute, cache key,
# and a callable to translate the netlink value into
# whatever value we need to store in the old cache to
# make sure we don't break anything
ifla_bridge_attributes = (
(Link.IFLA_BR_UNSPEC, Link.IFLA_BR_UNSPEC, None),
(Link.IFLA_BR_FORWARD_DELAY, "fd", lambda x: str(x / 100)),
(Link.IFLA_BR_HELLO_TIME, "hello", lambda x: str(x / 100)),
(Link.IFLA_BR_MAX_AGE, "maxage", lambda x: str(x / 100)),
(Link.IFLA_BR_AGEING_TIME, "ageing", lambda x: str(x / 100)),
(Link.IFLA_BR_STP_STATE, "stp", lambda x: 'yes' if x else 'no'),
(Link.IFLA_BR_PRIORITY, "bridgeprio", str),
(Link.IFLA_BR_VLAN_FILTERING, 'vlan_filtering', str),
(Link.IFLA_BR_VLAN_PROTOCOL, "vlan-protocol", str),
(Link.IFLA_BR_GROUP_FWD_MASK, Link.IFLA_BR_GROUP_FWD_MASK, None),
(Link.IFLA_BR_ROOT_ID, Link.IFLA_BR_ROOT_ID, None),
(Link.IFLA_BR_BRIDGE_ID, Link.IFLA_BR_BRIDGE_ID, None),
(Link.IFLA_BR_ROOT_PORT, Link.IFLA_BR_ROOT_PORT, None),
(Link.IFLA_BR_ROOT_PATH_COST, Link.IFLA_BR_ROOT_PATH_COST, None),
(Link.IFLA_BR_TOPOLOGY_CHANGE, Link.IFLA_BR_TOPOLOGY_CHANGE, None),
(Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, None),
(Link.IFLA_BR_HELLO_TIMER, Link.IFLA_BR_HELLO_TIMER, None),
(Link.IFLA_BR_TCN_TIMER, Link.IFLA_BR_TCN_TIMER, None),
(Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER, Link.IFLA_BR_TOPOLOGY_CHANGE_TIMER, None),
(Link.IFLA_BR_GC_TIMER, Link.IFLA_BR_GC_TIMER, None),
(Link.IFLA_BR_GROUP_ADDR, Link.IFLA_BR_GROUP_ADDR, None),
(Link.IFLA_BR_FDB_FLUSH, Link.IFLA_BR_FDB_FLUSH, None),
(Link.IFLA_BR_MCAST_ROUTER, "mcrouter", str),
(Link.IFLA_BR_MCAST_SNOOPING, "mcsnoop", str),
(Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, "mcqifaddr", str),
(Link.IFLA_BR_MCAST_QUERIER, "mcquerier", str),
(Link.IFLA_BR_MCAST_HASH_ELASTICITY, "hashel", str),
(Link.IFLA_BR_MCAST_HASH_MAX, "hashmax", str),
(Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, "mclmc", str),
(Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT, "mcsqc", str),
(Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, "mclmi", lambda x: str(x / 100)),
(Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, "mcmi", lambda x: str(x / 100)),
(Link.IFLA_BR_MCAST_QUERIER_INTVL, "mcqpi", lambda x: str(x / 100)),
(Link.IFLA_BR_MCAST_QUERY_INTVL, "mcqi", lambda x: str(x / 100)),
(Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, "mcqri", lambda x: str(x / 100)),
(Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, "mcsqi", lambda x: str(x / 100)),
(Link.IFLA_BR_NF_CALL_IPTABLES, Link.IFLA_BR_NF_CALL_IPTABLES, None),
(Link.IFLA_BR_NF_CALL_IP6TABLES, Link.IFLA_BR_NF_CALL_IP6TABLES, None),
(Link.IFLA_BR_NF_CALL_ARPTABLES, Link.IFLA_BR_NF_CALL_ARPTABLES, None),
(Link.IFLA_BR_VLAN_DEFAULT_PVID, Link.IFLA_BR_VLAN_DEFAULT_PVID, None),
(Link.IFLA_BR_PAD, Link.IFLA_BR_PAD, None),
(Link.IFLA_BR_VLAN_STATS_ENABLED, "vlan-stats", str),
(Link.IFLA_BR_MCAST_STATS_ENABLED, "mcstats", str),
(Link.IFLA_BR_MCAST_IGMP_VERSION, "igmp-version", str),
(Link.IFLA_BR_MCAST_MLD_VERSION, "mld-version", str)
)
def _link_dump_info_data_bridge(self, ifname, linkdata):
linkinfo = {}
for nl_attr, cache_key, func in self.ifla_bridge_attributes:
try:
if func:
linkinfo[cache_key] = func(linkdata.get(nl_attr))
else:
linkinfo[cache_key] = linkdata.get(nl_attr)
# we also store the value in pure netlink,
# to make the transition easier in the future
linkinfo[nl_attr] = linkdata.get(nl_attr)
except Exception as e:
self.logger.error('%s: parsing birdge IFLA_INFO_DATA %s: %s'
% (ifname, nl_attr, str(e)))
return linkinfo
def _link_dump_info_slave_data_bridge(self, ifname, info_slave_data):
return info_slave_data
def _link_dump_linkinfo(self, link, dump):
linkinfo = link.attributes[Link.IFLA_LINKINFO].get_pretty_value(dict)
if linkinfo:
info_kind = linkinfo.get(Link.IFLA_INFO_KIND)
info_data = linkinfo.get(Link.IFLA_INFO_DATA)
info_slave_kind = linkinfo.get(Link.IFLA_INFO_SLAVE_KIND)
info_slave_data = linkinfo.get(Link.IFLA_INFO_SLAVE_DATA)
dump['kind'] = info_kind
dump['slave_kind'] = info_slave_kind
if info_data:
link_kind_handler = self.link_kind_handlers.get(info_kind)
if callable(link_kind_handler):
dump['linkinfo'] = link_kind_handler(dump['ifname'], info_data)
if info_slave_data:
dump['info_slave_data'] = info_slave_data
def link_dump(self, ifname=None):
if ifname:
self.logger.info('netlink: ip link show dev %s' % ifname)
else:
self.logger.info('netlink: ip link show')
if ifupdownflags.flags.DRYRUN: return {}
links = dict()
try:
links_dump = self._nlmanager_api.link_dump(ifname)
except Exception as e:
raise Exception('netlink: link dump failed: %s' % str(e))
for link in links_dump:
try:
dump = dict()
flags = []
for flag, string in Link.flag_to_string.items():
if link.flags & flag:
flags.append(string[4:])
dump['flags'] = flags
dump['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
dump['ifindex'] = str(link.ifindex)
if link.device_type == Link.ARPHRD_ETHER:
self._link_dump_attr(link, [self.ifla_address], dump)
self._link_dump_attr(link, self.ifla_attributes, dump)
if Link.IFLA_LINKINFO in link.attributes:
self._link_dump_linkinfo(link, dump)
links[dump['ifname']] = dump
except Exception as e:
self.logger.warning('netlink: ip link show: %s' % str(e))
return links
def _addr_dump_extract_ifname(self, addr_packet):
addr_ifname_attr = addr_packet.attributes.get(Address.IFA_LABEL)
if addr_ifname_attr:
return addr_ifname_attr.get_pretty_value(str)
else:
return self.get_iface_name(addr_packet.ifindex)
@staticmethod
def _addr_filter(addr_ifname, addr):
return addr_ifname == 'lo' and addr in ['127.0.0.1/8', '::1/128', '0.0.0.0']
def _addr_dump_entry(self, ifaces, addr_packet, addr_ifname, ifa_attr):
attribute = addr_packet.attributes.get(ifa_attr)
if attribute:
address = attribute.get_pretty_value(str)
if hasattr(addr_packet, 'prefixlen'):
address = '%s/%d' % (address, addr_packet.prefixlen)
if self._addr_filter(addr_ifname, address):
return
addr_family = NetlinkPacket.af_family_to_string.get(addr_packet.family)
if not addr_family:
return
ifaces[addr_ifname]['addrs'][address] = {
'type': addr_family,
'scope': addr_packet.scope
}
ifa_address_attributes = [
Address.IFA_ADDRESS,
Address.IFA_LOCAL,
Address.IFA_BROADCAST,
Address.IFA_ANYCAST,
Address.IFA_MULTICAST
]
def addr_dump(self, ifname=None):
if ifname:
self.logger.info('netlink: ip addr show dev %s' % ifname)
else:
self.logger.info('netlink: ip addr show')
ifaces = dict()
addr_dump = self._nlmanager_api.addr_dump()
for addr_packet in addr_dump:
addr_ifname = self._addr_dump_extract_ifname(addr_packet)
if addr_packet.family not in [socket.AF_INET, socket.AF_INET6]:
continue
if ifname and ifname != addr_ifname:
continue
if addr_ifname not in ifaces:
ifaces[addr_ifname] = {'addrs': OrderedDict({})}
for ifa_attr in self.ifa_address_attributes:
self._addr_dump_entry(ifaces, addr_packet, addr_ifname, ifa_attr)
if ifname:
return {ifname: ifaces.get(ifname, {})}
return ifaces
netlink = Netlink()

View File

@@ -1,34 +1,35 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# networkInterfaces --
# ifupdown network interfaces file parser
#
import collections
import logging
import glob
import re
import os
import copy
from utils import utils
from iface import *
from template import templateEngine
import glob
import logging
import collections
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.template import templateEngine
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.template import templateEngine
whitespaces = '\n\t\r '
class networkInterfaces():
""" debian ifupdown /etc/network/interfaces file parser """
hotplugs = {}
auto_ifaces = []
callbacks = {}
auto_all = False
_addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'tunnel', 'ppp'],
'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'tunnel', 'ppp']}
_addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6'],
'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6']}
def __init__(self, interfacesfile='/etc/network/interfaces',
interfacesfileiobuf=None, interfacesfileformat='native',
@@ -50,6 +51,10 @@ class networkInterfaces():
Raises:
AttributeError, KeyError """
self.auto_ifaces = []
self.callbacks = {}
self.auto_all = False
self.logger = logging.getLogger('ifupdown.' +
self.__class__.__name__)
self.callbacks = {'iface_found' : None,
@@ -210,7 +215,7 @@ class networkInterfaces():
# For attributes that are related and that can have multiple
# entries, store them at the same index as their parent attribute.
# The example of such attributes is 'address' and its related
# attributes. since the related attributes can be optional,
# attributes. since the related attributes can be optional,
# we add null string '' in places where they are optional.
# XXX: this introduces awareness of attribute names in
# this class which is a violation.
@@ -257,6 +262,7 @@ class networkInterfaces():
for line_idx in range(cur_idx + 1, len(lines)):
l = lines[line_idx].strip(whitespaces)
if self.ignore_line(l) == 1:
ifaceobj.raw_config.append(l)
continue
attrs = re.split(self._ws_split_regex, l, 1)
if self._is_keyword(attrs[0]):
@@ -299,7 +305,7 @@ class networkInterfaces():
classes = self.get_allow_classes_for_iface(ifaceobj.name)
if classes:
[ifaceobj.set_class(c) for c in classes]
return lines_consumed # Return next index
def _create_ifaceobj_clone(self, ifaceobj, newifaceobjname,
@@ -494,7 +500,7 @@ class networkInterfaces():
errors += 1
self.callbacks.get('iface_found')(ifaceobj)
self.errors += errors
def load(self):
""" This member function loads the networkinterfaces file.

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
# Copyright 2015-2017 Cumulus Networks, Inc. All rights reserved.
#
#
'''
@@ -12,7 +12,7 @@ Initialize: This module defines a list of config file location based
on module. There are defined in the __init__(): All the
addon modules need to do is import the policymanager module.
import ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.policymanager as policymanager
Provides: an API to retrieve link attributes based on addon module name,
@@ -29,8 +29,9 @@ Provides: an API to retrieve link attributes based on addon module name,
'''
import json
import logging
import glob
import logging
class policymanager():
def __init__(self):
@@ -54,9 +55,9 @@ class policymanager():
self.logger.debug('reading %s system policy defaults config' \
% filename)
except Exception, e:
self.logger.info('could not read %s system policy defaults config' \
self.logger.warning('could not read %s system policy defaults config' \
% filename)
self.logger.info(' exception is %s' % str(e))
self.logger.warning(' exception is %s' % str(e))
for module in system_array.keys():
if self.system_policy_array.has_key(module):
@@ -74,9 +75,9 @@ class policymanager():
self.logger.debug('reading %s policy user defaults config' \
% filename)
except Exception, e:
self.logger.debug('could not read %s user policy defaults config' \
self.logger.warning('could not read %s user policy defaults config' \
% filename)
self.logger.debug(' exception is %s' % str(e))
self.logger.warning(' exception is %s' % str(e))
# customer added module attributes
for module in user_array.keys():
if self.system_policy_array.has_key(module):
@@ -136,7 +137,7 @@ class policymanager():
get_attr_default: Addon modules must use one of two types of access methods to
the default configs. In this method, we expect the default to be in
[module]['defaults'][attr]
[module]['defaults'][attr]
We first check the user_policy_array and return that value. But if
the user did not specify an override, we use the system_policy_array.
@@ -166,7 +167,7 @@ class policymanager():
get_module_globals: Addon modules must use one of two types of access methods to
the default configs. In this method, we expect the default to be in
[module]['module_globals'][attr]
[module]['module_globals'][attr]
We first check the user_policy_array and return that value. But if
the user did not specify an override, we use the system_policy_array.
@@ -192,23 +193,34 @@ class policymanager():
return val
def get_module_default(self,module_name=None):
'''
get_module_default: Addon modules can also access the entire config
This method returns indexed by "system" and "user": these are the
system-wide and user-defined policy arrays for a specific module.
'''
if not module_name:
return None
if self.system_policy_array.get(module_name) and \
self.user_policy_array.get(module_name):
mod_array = {"system":self.system_policy_array[module_name],
"user":self.user_policy_array[module_name]}
else:
# the module must not have these defined, return None
mod_array = None
def get_module_defaults(self, module_name):
"""
get_module_defaults: returns a merged dictionary of default values
specified in policy files. Users provided values override system
values.
"""
return mod_array
if not module_name:
raise NotImplementedError('get_module_defaults: module name can\'t be None')
defaults = dict()
defaults.update(self.system_policy_array.get(module_name, {}).get('defaults', {}))
defaults.update(self.user_policy_array.get(module_name, {}).get('defaults', {}))
return defaults
def get_iface_defaults(self, module_name):
defaults = dict()
if not module_name:
self.logger.info('get_iface_defaults: module name can\'t be None')
else:
defaults.update(self.system_policy_array.get(module_name, {}).get('iface_defaults', {}))
defaults.update(self.user_policy_array.get(module_name, {}).get('iface_defaults', {}))
return defaults
policymanager_api = policymanager()
def reset():
global policymanager_api
policymanager_api = policymanager()

View File

@@ -1,28 +1,36 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# ifaceScheduler --
# interface scheduler
#
from statemanager import *
import ifupdown.ifupdownflags as ifupdownflags
from iface import *
from graph import *
from collections import deque
from collections import OrderedDict
import logging
import traceback
import sys
from graph import *
from collections import deque
from threading import *
from ifupdownbase import *
from ifupdown.utils import utils
from sets import Set
try:
from ifupdown2.ifupdown.graph import *
from ifupdown2.ifupdown.ifupdownbase import *
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdown.statemanager import *
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.graph import *
from ifupdown.ifupdownbase import *
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdown.statemanager import *
import ifupdown.ifupdownflags as ifupdownflags
class ifaceSchedulerFlags():
""" Enumerates scheduler flags """
@@ -41,6 +49,11 @@ class ifaceScheduler():
_SCHED_STATUS = True
@classmethod
def reset(cls):
cls._STATE_CHECK = True
cls._SCHED_STATUS = True
@classmethod
def get_sched_status(cls):
return cls._SCHED_STATUS
@@ -74,7 +87,7 @@ class ifaceScheduler():
if hasattr(m, 'run'):
msg = ('%s: %s : running module %s' %(ifacename, op, mname))
if op == 'query-checkcurr':
# Dont check curr if the interface object was
# Dont check curr if the interface object was
# auto generated
if (ifaceobj.priv_flags and
ifaceobj.priv_flags.NOCONFIG):
@@ -108,7 +121,7 @@ class ifaceScheduler():
status)
if ifupdownobj.config.get('addon_scripts_support', '0') == '1':
# execute /etc/network/ scripts
# execute /etc/network/ scripts
os.environ['IFACE'] = ifaceobj.name if ifaceobj.name else ''
os.environ['LOGICAL'] = ifaceobj.name if ifaceobj.name else ''
os.environ['METHOD'] = ifaceobj.addr_method if ifaceobj.addr_method else ''
@@ -142,7 +155,7 @@ class ifaceScheduler():
for ifaceobj in ifaceobjs:
ifaceobj.status = ifaceStatus.SUCCESS
posthookfunc(ifupdownobj, ifaceobj, 'down')
return
return
for op in ops:
# first run ifupdownobj handlers. This is good enough
# for the first object in the list
@@ -397,7 +410,7 @@ class ifaceScheduler():
@classmethod
def run_upperifaces(cls, ifupdownobj, ifacenames, ops,
continueonfailure=True):
""" Run through valid upperifaces """
""" Run through valid upperifaces """
upperifaces = []
cls._get_valid_upperifaces(ifupdownobj, ifacenames, upperifaces)
@@ -468,7 +481,7 @@ class ifaceScheduler():
argument. Runs topological sort on interface dependency graph.
Args:
**ifupdownobj** (object): ifupdownMain object
**ifupdownobj** (object): ifupdownMain object
**ifacenames** (list): list of interface names
@@ -564,7 +577,7 @@ class ifaceScheduler():
if (not skipupperifaces and
ifupdownobj.config.get('skip_upperifaces', '0') == '0' and
((not ifupdownflags.flags.ALL and followdependents) or
followupperifaces) and
followupperifaces) and
'up' in ops[0]):
# If user had given a set of interfaces to bring up
# try and execute 'up' on the upperifaces

View File

@@ -1,17 +1,25 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# stateManager --
# interface state manager
#
import cPickle
from collections import OrderedDict
import logging
import exceptions
import os
from iface import *
import cPickle
import logging
try:
from ifupdown2.ifupdown.iface import *
import ifupdown2.ifupdown.exceptions as exceptions
except ImportError:
from ifupdown.iface import *
import ifupdown.exceptions as exceptions
class pickling():
""" class with helper methods for pickling/unpickling iface objects """
@@ -179,10 +187,14 @@ class stateManager():
ifaceobj = self.ifaces.get(i)
if ifaceobj is None:
raise exceptions.ifaceNotFoundError('ifname %s'
%i + ' not found')
% i + ' not found')
ifaceobj.dump(self.logger)
else:
for ifacename, ifaceobjs in self.ifaceobjdict.items():
[i.dump(self.logger) for i in ifaceobjs]
statemanager_api = stateManager()
def reset():
global statemanager_api
statemanager_api = stateManager()

View File

@@ -1,15 +1,17 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# template --
# helper class to render templates
#
import logging
import traceback
from utils import *
try:
from ifupdown2.ifupdown.utils import *
except ImportError:
from ifupdown.utils import *
class templateEngine():
""" provides template rendering methods """

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
# utils --
@@ -14,12 +14,19 @@ import fcntl
import signal
import logging
import subprocess
import ifupdownflags
from functools import partial
from ipaddr import IPNetwork, IPAddress
from ifupdown.iface import *
try:
from ifupdown2.ifupdown.iface import *
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.iface import *
import ifupdown.ifupdownflags as ifupdownflags
def signal_handler_f(ps, sig, frame):
if ps:
@@ -35,9 +42,11 @@ class utils():
"on": True,
"yes": True,
"1": True,
"fast": True,
"off": False,
"no": False,
"0": False,
"slow": False
}
_binary_bool = {
@@ -55,6 +64,81 @@ class utils():
'no': 'off'
}
_onoff_onezero = {
'1' : 'on',
'0' : 'off'
}
_yesno_onezero = {
'1' : 'yes',
'0' : 'no'
}
"""
Set debian path as default path for all the commands.
If command not present in debian path, search for the
commands in the other system directories.
This search is carried out to handle different locations
on different distros.
If the command is not found in any of the system
directories, command execution will fail because we have
set default path same as debian path.
"""
bridge_cmd = '/sbin/bridge'
ip_cmd = '/bin/ip'
brctl_cmd = '/sbin/brctl'
pidof_cmd = '/bin/pidof'
service_cmd = '/usr/sbin/service'
sysctl_cmd = '/sbin/sysctl'
modprobe_cmd = '/sbin/modprobe'
pstree_cmd = '/usr/bin/pstree'
ss_cmd = '/bin/ss'
vrrpd_cmd = '/usr/sbin/vrrpd'
ifplugd_cmd = '/usr/sbin/ifplugd'
mstpctl_cmd = '/sbin/mstpctl'
ethtool_cmd = '/sbin/ethtool'
systemctl_cmd = '/bin/systemctl'
dpkg_cmd = '/usr/bin/dpkg'
for cmd in ['bridge',
'ip',
'brctl',
'pidof',
'service',
'sysctl',
'modprobe',
'pstree',
'ss',
'vrrpd',
'ifplugd',
'mstpctl',
'ethtool',
'systemctl',
'dpkg'
]:
if os.path.exists(vars()[cmd + '_cmd']):
continue
for path in ['/bin/',
'/sbin/',
'/usr/bin/',
'/usr/sbin/',]:
if os.path.exists(path + cmd):
vars()[cmd + '_cmd'] = path + cmd
else:
logger.debug('warning: path %s not found: %s won\'t be usable' % (path + cmd, cmd))
@staticmethod
def get_onff_from_onezero(value):
if value in utils._onoff_onezero:
return utils._onoff_onezero[value]
return value
@staticmethod
def get_yesno_from_onezero(value):
if value in utils._yesno_onezero:
return utils._yesno_onezero[value]
return value
@staticmethod
def get_onoff_bool(value):
if value in utils._onoff_bool:
@@ -63,9 +147,7 @@ class utils():
@staticmethod
def get_boolean_from_string(value):
if value in utils._string_values:
return utils._string_values[value]
return False
return utils._string_values.get(value, False)
@staticmethod
def get_yesno_boolean(bool):
@@ -93,6 +175,22 @@ class utils():
if attr in attrsdict:
attrsdict[attr] = utils.boolean_support_binary(attrsdict[attr])
@staticmethod
def get_int_from_boolean_and_string(value):
try:
return int(value)
except:
return int(utils.get_boolean_from_string(value))
@staticmethod
def strip_hwaddress(hwaddress):
if hwaddress and hwaddress.startswith("ether"):
hwaddress = hwaddress[5:].strip()
return hwaddress.lower() if hwaddress else hwaddress
# we need to "normalize" the user provided MAC so it can match with
# what we have in the cache (data retrieved via a netlink dump by
# nlmanager). nlmanager return all macs in lower-case
@classmethod
def importName(cls, modulename, name):
""" Import a named object """
@@ -212,6 +310,25 @@ class utils():
cls.logger.warning('%s: %s' % (ifacename, e))
return ipaddrs
@classmethod
def get_ip_objs(cls, module_name, ifname, addrs_list):
addrs_obj_list = []
for a in addrs_list or []:
try:
addrs_obj_list.append(IPNetwork(a) if '/' in a else IPAddress(a))
except Exception as e:
cls.logger.warning('%s: %s: %s' % (module_name, ifname, str(e)))
return addrs_obj_list
@classmethod
def get_ip_obj(cls, module_name, ifname, addr):
if addr:
try:
return IPNetwork(addr) if '/' in addr else IPAddress(addr)
except Exception as e:
cls.logger.warning('%s: %s: %s' % (module_name, ifname, str(e)))
return None
@classmethod
def is_addr_ip_allowed_on(cls, ifaceobj, syntax_check=False):
msg = ('%s: ignoring ip address. Assigning an IP '

File diff suppressed because it is too large Load Diff

View File

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
@@ -30,8 +30,6 @@ class linkCache():
""" This class contains methods and instance variables to cache
link info """
_shared_state = {}
""" { <ifacename> : { 'ifindex': <index>,
'mtu': <mtu>,
'state' : <state>',
@@ -98,6 +96,11 @@ class linkCache():
def invalidate(cls):
cls.links = {}
@classmethod
def reset(cls):
cls.invalidate()
cls.vrfs = {}
@classmethod
def dump(cls):
print 'Dumping link cache'

View File

@@ -1,13 +1,18 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from ifupdown.utils import utils
from utilsbase import *
import os
try:
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.utilsbase import *
except ImportError:
from ifupdown.utils import utils
from ifupdownaddons.utilsbase import *
class dhclient(utilsBase):
""" This class contains helper methods to interact with the dhclient

View File

@@ -1,19 +1,29 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
import re
import io
import logging
import traceback
from ifupdown.utils import utils
from ifupdown.iface import *
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
import ifupdown2.ifupdown.exceptions as exceptions
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
import ifupdown.exceptions as exceptions
import ifupdown.policymanager as policymanager
import ifupdown.ifupdownflags as ifupdownflags
class NotSupported(Exception):
pass
@@ -24,8 +34,8 @@ class moduleBase(object):
Provides common infrastructure methods for all addon modules """
def __init__(self, *args, **kargs):
modulename = self.__class__.__name__
self.logger = logging.getLogger('ifupdown.' + modulename)
self.modulename = self.__class__.__name__
self.logger = logging.getLogger('ifupdown.' + self.modulename)
# vrfs are a global concept and a vrf context can be applicable
# to all global vrf commands. Get the default vrf-exec-cmd-prefix
@@ -39,12 +49,52 @@ class moduleBase(object):
self._bridge_stp_user_space = None
self.merge_modinfo_with_policy_files()
def merge_modinfo_with_policy_files(self):
"""
update addons modinfo dictionary with system/user defined values in policy files
Any value can be updated except the module help "mhelp"
We also check if the policy attributes really exist to make sure someone is not
trying to "inject" new attributes to prevent breakages and security issue
"""
attrs = dict(self.get_modinfo().get('attrs', {}))
if not attrs:
return
error_msg = 'this attribute doesn\'t exist or isn\'t supported'
# first check module_defaults
for key, value in policymanager.policymanager_api.get_module_defaults(self.modulename).items():
if not key in attrs:
self.logger.warning('%s: %s: %s' % (self.modulename, key, error_msg))
continue
attrs[key]['default'] = value
# then check module_globals (overrides module_defaults)
policy_modinfo = policymanager.policymanager_api.get_module_globals(self.modulename, '_modinfo')
if policy_modinfo:
policy_attrs = policy_modinfo.get('attrs', {})
update_attrs = dict()
for attr_name, attr_description in policy_attrs.items():
if attr_name not in attrs:
self.logger.warning('%s: %s: %s' % (self.modulename, attr_name, error_msg))
else:
update_attrs[attr_name] = attr_description
attrs.update(update_attrs)
return attrs
def log_warn(self, str, ifaceobj=None):
""" log a warning if err str is not one of which we should ignore """
if not self.ignore_error(str) and not ifupdownflags.flags.IGNORE_ERRORS:
if self.logger.getEffectiveLevel() == logging.DEBUG:
traceback.print_stack()
traceback.print_exc()
self.logger.warn(str)
if ifaceobj:
ifaceobj.set_status(ifaceStatus.WARNING)
@@ -55,6 +105,7 @@ class moduleBase(object):
if not self.ignore_error(str) and not ifupdownflags.flags.IGNORE_ERRORS:
if self.logger.getEffectiveLevel() == logging.DEBUG:
traceback.print_stack()
traceback.print_exc()
if raise_error:
if ifaceobj:
ifaceobj.set_status(ifaceStatus.ERROR)
@@ -66,7 +117,8 @@ class moduleBase(object):
def is_process_running(self, procName):
try:
utils.exec_command('/bin/pidof -x %s' % procName)
utils.exec_command('%s -x %s' %
(utils.pidof_cmd, procName))
except:
return False
else:
@@ -120,6 +172,12 @@ class moduleBase(object):
errmsg = ('error parsing glob expression \'%s\'' %expr +
' (supported glob syntax: swp1-10.300 or swp[1-10].300' +
' or swp[1-10]sub[0-4].300')
if ',' in expr:
self.logger.warn('%s: comma are not supported in glob: %s' % (ifacename, errmsg))
yield expr
return
regexs = self.glob_regexs
if regexs[0].match(expr):
@@ -249,11 +307,13 @@ class moduleBase(object):
def sysctl_set(self, variable, value):
""" set sysctl variable to value passed as argument """
utils.exec_command('sysctl %s=%s' % (variable, value))
utils.exec_command('%s %s=%s' %
(utils.sysctl_cmd, variable, value))
def sysctl_get(self, variable):
""" get value of sysctl variable """
output = utils.exec_command('sysctl %s' % variable)
output = utils.exec_command('%s %s' %
(utils.sysctl_cmd, variable))
split = output.split('=')
if len(split) > 1:
return split[1].strip()
@@ -296,7 +356,7 @@ class moduleBase(object):
ifaceobjcurr.update_config_with_status(attr_name,
runningattrvalue, 0)
def dict_key_subset(self, a, b):
def dict_key_subset(self, a, b):
""" returns a list of differing keys """
return [x for x in a if x in b]
@@ -337,7 +397,10 @@ class moduleBase(object):
try:
return self._modinfo
except:
return None
return {}
def get_attr_default_value(self, attrname):
return self.get_modinfo().get('attrs', {}).get(attrname, {}).get('default')
def get_overrides_ifupdown_scripts(self):
""" return the ifupdown scripts replaced by the current module """
@@ -361,19 +424,66 @@ class moduleBase(object):
pass
return (start, end)
def _handle_reserved_vlan(self, vlanid, logprefix=''):
def _handle_reserved_vlan(self, vlanid, logprefix='', end=-1):
""" Helper function to check and warn if the vlanid falls in the
reserved vlan range """
if vlanid in range(self._resv_vlan_range[0],
self._resv_vlan_range[1]):
self.logger.error('%s: reserved vlan %d being used'
%(logprefix, vlanid) + ' (reserved vlan range %d-%d)'
%(self._resv_vlan_range[0], self._resv_vlan_range[1]))
return True
return False
error = False
invalid_vlan = vlanid
if self._resv_vlan_range[0] <= vlanid <= self._resv_vlan_range[1]:
error = True
elif end > 0:
if self._resv_vlan_range[0] <= end <= self._resv_vlan_range[1]:
error = True
invalid_vlan = end
elif vlanid < self._resv_vlan_range[0] and end > self._resv_vlan_range[1]:
error = True
invalid_vlan = self._resv_vlan_range[0]
if error:
raise exceptions.ReservedVlanException('%s: reserved vlan %d being used (reserved vlan range %d-%d)'
% (logprefix, invalid_vlan, self._resv_vlan_range[0], self._resv_vlan_range[1]))
return error
def _valid_ethaddr(self, ethaddr):
""" Check if address is 00:00:00:00:00:00 """
if not ethaddr or re.match('00:00:00:00:00:00', ethaddr):
return False
return True
def _get_vlan_id_from_ifacename(self, ifacename):
if '.' in ifacename:
vid_str = ifacename.split('.', 2)
vlen = len(vid_str)
if vlen == 2:
vid_str = vid_str[1]
elif vlen == 3:
vid_str = vid_str[2]
elif ifacename.startswith('vlan'):
vid_str = ifacename[4:]
else:
return -1
try:
vid = int(vid_str)
except:
return -1
return vid
def _get_vlan_id(self, ifaceobj):
""" Derives vlanid from iface name
Example:
Returns 1 for ifname vlan0001 returns 1
Returns 1 for ifname vlan1
Returns 1 for ifname eth0.1
Returns 100 for ifname eth0.1.100
Returns -1 if vlan id cannot be determined
"""
vid_str = ifaceobj.get_attr_value_first('vlan-id')
try:
if vid_str: return int(vid_str)
except:
return -1
return self._get_vlan_id_from_ifacename(ifaceobj.name)

View File

@@ -1,15 +1,22 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from cache import MSTPAttrsCache
from utilsbase import *
from ifupdown.iface import *
from ifupdown.utils import utils
from cache import *
import json
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.cache import *
from ifupdown2.ifupdownaddons.utilsbase import *
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.cache import *
from ifupdownaddons.utilsbase import *
class mstpctlutil(utilsBase):
""" This class contains helper methods to interact with mstpd using
@@ -53,9 +60,13 @@ class mstpctlutil(utilsBase):
def __init__(self, *args, **kargs):
utilsBase.__init__(self, *args, **kargs)
@classmethod
def reset(cls):
cls._cache_fill_done = False
def is_mstpd_running(self):
try:
utils.exec_command('/bin/pidof mstpd')
utils.exec_command('%s mstpd'%utils.pidof_cmd)
except:
return False
else:
@@ -73,7 +84,8 @@ class mstpctlutil(utilsBase):
return attrs
mstpctl_bridgeport_attrs_dict = {}
try:
cmd = ['/sbin/mstpctl', 'showportdetail', bridgename, 'json']
cmd = [utils.mstpctl_cmd,
'showportdetail', bridgename, 'json']
output = utils.exec_commandl(cmd)
if not output:
return mstpctl_bridgeport_attrs_dict
@@ -95,7 +107,8 @@ class mstpctlutil(utilsBase):
mstpctl_bridge_attrs_dict = {}
try:
cmd = ['/sbin/mstpctl', 'showbridge', 'json', bridgename]
cmd = [utils.mstpctl_cmd,
'showbridge', 'json', bridgename]
output = utils.exec_commandl(cmd)
if not output:
return mstpctl_bridge_attrs_dict
@@ -147,10 +160,10 @@ class mstpctlutil(utilsBase):
if cache_value and cache_value == value:
return
if attrname == 'treeportcost' or attrname == 'treeportprio':
utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname,
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
bridgename, portname, '0', value])
else:
utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname,
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
bridgename, portname, value])
if json_attr:
self.update_bridge_port_cache(bridgename, portname, json_attr, value)
@@ -182,14 +195,12 @@ class mstpctlutil(utilsBase):
if attrvalue_curr and attrvalue_curr == attrvalue:
return
if attrname == 'treeprio':
utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname,
'%s' % bridgename, '0', '%s' % attrvalue],
stdout=False, stderr=None)
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
'%s' % bridgename, '0', '%s' % attrvalue], stderr=None)
self.update_bridge_cache(bridgename, attrname, str(attrvalue))
else:
utils.exec_commandl(['/sbin/mstpctl', 'set%s' % attrname,
'%s' % bridgename, '%s' % attrvalue],
stdout=False, stderr=None)
utils.exec_commandl([utils.mstpctl_cmd, 'set%s' % attrname,
'%s' % bridgename, '%s' % attrvalue], stderr=None)
self.update_bridge_cache(bridgename,
self._bridge_jsonAttr_map[attrname],
str(attrvalue))
@@ -211,22 +222,26 @@ class mstpctlutil(utilsBase):
attrvalue_curr = self.get_bridge_treeprio(bridgename)
if attrvalue_curr and attrvalue_curr == attrvalue:
return
utils.exec_commandl(['/sbin/mstpctl', 'settreeprio', bridgename, '0',
utils.exec_commandl([utils.mstpctl_cmd,
'settreeprio', bridgename, '0',
str(attrvalue)])
self.update_bridge_cache(bridgename, 'treeprio', str(attrvalue))
def showbridge(self, bridgename=None):
if bridgename:
return utils.exec_command('/sbin/mstpctl showbridge %s' % bridgename)
return utils.exec_command('%s showbridge %s' %
(utils.mstpctl_cmd, bridgename))
else:
return utils.exec_command('/sbin/mstpctl showbridge')
return utils.exec_command('%s showbridge' %utils.mstpctl_cmd)
def showportdetail(self, bridgename):
return utils.exec_command('/sbin/mstpctl showportdetail %s' % bridgename)
return utils.exec_command('%s showportdetail %s' %
(utils.mstpctl_cmd, bridgename))
def mstpbridge_exists(self, bridgename):
try:
utils.exec_command('mstpctl showbridge %s' % bridgename, stdout=False)
utils.exec_command('%s showbridge %s' %
(utils.mstpctl_cmd, bridgename))
return True
except:
return False

View File

@@ -1,12 +1,18 @@
#!/usr/bin/python
#
# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
# Copyright 2015-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
from utilsbase import *
from ifupdown.utils import utils
try:
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.utilsbase import *
except ImportError:
from ifupdown.utils import utils
from ifupdownaddons.utilsbase import *
class systemUtils():
@classmethod
@@ -23,7 +29,8 @@ class systemUtils():
if procname:
try:
utils.exec_command('/bin/pidof %s' % procname, stdout=False)
utils.exec_command('%s %s' %
(utils.pidof_cmd, procname))
except:
return False
else:
@@ -36,8 +43,8 @@ class systemUtils():
if not servicename:
return False
try:
utils.exec_commandl(['/usr/sbin/service', servicename, 'status'],
stdout=False)
utils.exec_commandl([utils.service_cmd,
servicename, 'status'])
except Exception:
# XXX: check for subprocess errors vs os error
return False
@@ -48,7 +55,8 @@ class systemUtils():
if not processname:
return False
try:
utils.exec_command('/bin/pidof %s' % processname, stdout=False)
utils.exec_command('%s %s' %
(utils.pidof_cmd, processname))
except:
return False
else:

View File

@@ -1,20 +1,26 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import logging
import re
import io
from ifupdown.utils import utils
import ifupdown.ifupdownflags as ifupdownflags
from ifupdown.iface import *
from cache import *
import time
import logging
try:
from ifupdown2.ifupdown.iface import *
from ifupdown2.ifupdown.utils import utils
from ifupdown2.ifupdownaddons.cache import *
import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
except ImportError:
from ifupdown.iface import *
from ifupdown.utils import utils
from ifupdownaddons.cache import *
import ifupdown.ifupdownflags as ifupdownflags
def profile(func):
def wrap(*args, **kwargs):
started_at = time.time()
@@ -64,7 +70,10 @@ class utilsBase(object):
return None
def sysctl_set(self, variable, value):
utils.exec_command('sysctl %s=%s' % (variable, value))
utils.exec_command('%s %s=%s' %
(utils.sysctl_cmd, variable, value))
def sysctl_get(self, variable):
return utils.exec_command('sysctl %s' % variable).split('=')[1].strip()
return utils.exec_command('%s %s' %
(utils.sysctl_cmd,
variable)).split('=')[1].strip()

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