python interface to netlink protocols

currently includes experimental support for links, addresses
and some traffic control
This commit is contained in:
Thomas Graf 2011-05-10 12:17:33 +02:00
parent 023c662327
commit f443be6e74
25 changed files with 4514 additions and 0 deletions

View File

@ -27,6 +27,11 @@ AM_PROG_LIBTOOL
AM_PROG_LEX
AC_PROG_YACC
AM_PATH_PYTHON(2.6)
AX_PKG_SWIG
AX_PYTHON_DEVEL
AX_SWIG_PYTHON
AC_C_CONST
AC_C_INLINE

135
m4/ax_pkg_swig.m4 Normal file
View File

@ -0,0 +1,135 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# This macro searches for a SWIG installation on your system. If found,
# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
#
# You can use the optional first argument to check if the version of the
# available SWIG is greater than or equal to the value of the argument. It
# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
# the first N is mandatory.) If the version argument is given (e.g.
# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
# or higher.
#
# As usual, action-if-found is executed if SWIG is found, otherwise
# action-if-not-found is executed.
#
# In configure.in, use as:
#
# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
# AX_SWIG_ENABLE_CXX
# AX_SWIG_MULTI_MODULE_SUPPORT
# AX_SWIG_PYTHON
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 8
AC_DEFUN([AX_PKG_SWIG],[
# Ubuntu has swig 2.0 as /usr/bin/swig2.0
AC_PATH_PROGS([SWIG],[swig swig2.0])
if test -z "$SWIG" ; then
m4_ifval([$3],[$3],[:])
elif test -n "$1" ; then
AC_MSG_CHECKING([SWIG version])
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
AC_MSG_RESULT([$swig_version])
if test -n "$swig_version" ; then
# Calculate the required version number components
[required=$1]
[required_major=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_major" ; then
[required_major=0]
fi
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_minor" ; then
[required_minor=0]
fi
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_patch" ; then
[required_patch=0]
fi
# Calculate the available version number components
[available=$swig_version]
[available_major=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_major" ; then
[available_major=0]
fi
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_minor" ; then
[available_minor=0]
fi
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_patch" ; then
[available_patch=0]
fi
# Convert the version tuple into a single number for easier comparison.
# Using base 100 should be safe since SWIG internally uses BCD values
# to encode its version number.
required_swig_vernum=`expr $required_major \* 10000 \
\+ $required_minor \* 100 \+ $required_patch`
available_swig_vernum=`expr $available_major \* 10000 \
\+ $available_minor \* 100 \+ $available_patch`
if test $available_swig_vernum -lt $required_swig_vernum; then
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
SWIG=''
m4_ifval([$3],[$3],[])
else
AC_MSG_CHECKING([for SWIG library])
SWIG_LIB=`$SWIG -swiglib`
AC_MSG_RESULT([$SWIG_LIB])
m4_ifval([$2],[$2],[])
fi
else
AC_MSG_WARN([cannot determine SWIG version])
SWIG=''
m4_ifval([$3],[$3],[])
fi
fi
AC_SUBST([SWIG_LIB])
])

325
m4/ax_python_devel.m4 Normal file
View File

@ -0,0 +1,325 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PYTHON_DEVEL([version])
#
# DESCRIPTION
#
# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
# in your configure.ac.
#
# This macro checks for Python and tries to get the include path to
# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS)
# output variables. It also exports $(PYTHON_EXTRA_LIBS) and
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
#
# You can search for some particular version of Python by passing a
# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
# note that you *have* to pass also an operator along with the version to
# match, and pay special attention to the single quotes surrounding the
# version number. Don't use "PYTHON_VERSION" for this: that environment
# variable is declared as precious and thus reserved for the end-user.
#
# This macro should work for all versions of Python >= 2.1.0. As an end
# user, you can disable the check for the python version by setting the
# PYTHON_NOVERSIONCHECK environment variable to something else than the
# empty string.
#
# If you need to use this macro for an older Python version, please
# contact the authors. We're always open for feedback.
#
# LICENSE
#
# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2009 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2009 Andrew Collier <colliera@ukzn.ac.za>
# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 8
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
AC_DEFUN([AX_PYTHON_DEVEL],[
#
# Allow the use of a (user set) custom python version
#
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
version to use, for example '2.3'. This string
will be appended to the Python interpreter
canonical name.])
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
if test -z "$PYTHON"; then
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
PYTHON_VERSION=""
fi
#
# Check for a version of Python >= 2.1.0
#
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
ac_supports_python_ver=`$PYTHON -c "import sys; \
ver = sys.version.split ()[[0]]; \
print (ver >= '2.1.0')"`
if test "$ac_supports_python_ver" != "True"; then
if test -z "$PYTHON_NOVERSIONCHECK"; then
AC_MSG_RESULT([no])
AC_MSG_FAILURE([
This version of the AC@&t@_PYTHON_DEVEL macro
doesn't work properly with versions of Python before
2.1.0. You may need to re-run configure, setting the
variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
to something else than an empty string.
])
else
AC_MSG_RESULT([skip at user request])
fi
else
AC_MSG_RESULT([yes])
fi
#
# if the macro parameter ``version'' is set, honour it
#
if test -n "$1"; then
AC_MSG_CHECKING([for a version of Python $1])
ac_supports_python_ver=`$PYTHON -c "import sys; \
ver = sys.version.split ()[[0]]; \
print (ver $1)"`
if test "$ac_supports_python_ver" = "True"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([this package requires Python $1.
If you have it installed, but it isn't the default Python
interpreter in your system path, please pass the PYTHON_VERSION
variable to configure. See ``configure --help'' for reference.
])
PYTHON_VERSION=""
fi
fi
#
# Check if you have distutils, else fail
#
AC_MSG_CHECKING([for the distutils Python package])
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
if test -z "$ac_distutils_result"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot import Python module "distutils".
Please check your Python installation. The error was:
$ac_distutils_result])
PYTHON_VERSION=""
fi
#
# Check for Python include path
#
AC_MSG_CHECKING([for Python include path])
if test -z "$PYTHON_CPPFLAGS"; then
python_path=`$PYTHON -c "import distutils.sysconfig; \
print (distutils.sysconfig.get_python_inc ());"`
if test -n "${python_path}"; then
python_path="-I$python_path"
fi
PYTHON_CPPFLAGS=$python_path
fi
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
AC_SUBST([PYTHON_CPPFLAGS])
#
# Check for Python library path
#
AC_MSG_CHECKING([for Python library path])
if test -z "$PYTHON_LDFLAGS"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
ac_python_version=`cat<<EOD | $PYTHON -
# join all versioning strings, on some systems
# major/minor numbers could be in different list elements
from distutils.sysconfig import *
ret = ''
for e in get_config_vars ('VERSION'):
if (e != None):
ret += e
print (ret)
EOD`
if test -z "$ac_python_version"; then
if test -n "$PYTHON_VERSION"; then
ac_python_version=$PYTHON_VERSION
else
ac_python_version=`$PYTHON -c "import sys; \
print (sys.version[[:3]])"`
fi
fi
# Make the versioning information available to the compiler
AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
[If available, contains the Python version number currently in use.])
# First, the library directory:
ac_python_libdir=`cat<<EOD | $PYTHON -
# There should be only one
import distutils.sysconfig
for e in distutils.sysconfig.get_config_vars ('LIBDIR'):
if e != None:
print (e)
break
EOD`
# Before checking for libpythonX.Y, we need to know
# the extension the OS we're on uses for libraries
# (we take the first one, if there's more than one fix me!):
ac_python_soext=`$PYTHON -c \
"import distutils.sysconfig; \
print (distutils.sysconfig.get_config_vars('SO')[[0]])"`
# Now, for the library:
ac_python_soname=`$PYTHON -c \
"import distutils.sysconfig; \
print (distutils.sysconfig.get_config_vars('LDLIBRARY')[[0]])"`
# Strip away extension from the end to canonicalize its name:
ac_python_library=`echo "$ac_python_soname" | sed "s/${ac_python_soext}$//"`
# This small piece shamelessly adapted from PostgreSQL python macro;
# credits goes to momjian, I think. I'd like to put the right name
# in the credits, if someone can point me in the right direction... ?
#
if test -n "$ac_python_libdir" -a -n "$ac_python_library" \
-a x"$ac_python_library" != x"$ac_python_soname"
then
# use the official shared library
ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
PYTHON_LDFLAGS="-L$ac_python_libdir -l$ac_python_library"
else
# old way: use libpython from python_configdir
ac_python_libdir=`$PYTHON -c \
"from distutils.sysconfig import get_python_lib as f; \
import os; \
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
PYTHON_LDFLAGS="-L$ac_python_libdir -lpython$ac_python_version"
fi
if test -z "PYTHON_LDFLAGS"; then
AC_MSG_ERROR([
Cannot determine location of your Python DSO. Please check it was installed with
dynamic libraries enabled, or try setting PYTHON_LDFLAGS by hand.
])
fi
fi
AC_MSG_RESULT([$PYTHON_LDFLAGS])
AC_SUBST([PYTHON_LDFLAGS])
#
# Check for site packages
#
AC_MSG_CHECKING([for Python site-packages path])
if test -z "$PYTHON_SITE_PKG"; then
PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
print (distutils.sysconfig.get_python_lib(0,0));"`
fi
AC_MSG_RESULT([$PYTHON_SITE_PKG])
AC_SUBST([PYTHON_SITE_PKG])
#
# libraries which must be linked in when embedding
#
AC_MSG_CHECKING(python extra libraries)
if test -z "$PYTHON_EXTRA_LIBS"; then
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print (conf('LOCALMODLIBS') + ' ' + conf('LIBS'))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
AC_SUBST(PYTHON_EXTRA_LIBS)
#
# linking flags needed when embedding
#
AC_MSG_CHECKING(python extra linking flags)
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
print (conf('LINKFORSHARED'))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
#
# final check to see if everything compiles alright
#
AC_MSG_CHECKING([consistency of all components of python development environment])
# save current global flags
ac_save_LIBS="$LIBS"
ac_save_CPPFLAGS="$CPPFLAGS"
LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS"
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
AC_LANG_PUSH([C])
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <Python.h>]],
[[Py_Initialize();]])
],[pythonexists=yes],[pythonexists=no])
AC_LANG_POP([C])
# turn back to default flags
CPPFLAGS="$ac_save_CPPFLAGS"
LIBS="$ac_save_LIBS"
AC_MSG_RESULT([$pythonexists])
if test ! "x$pythonexists" = "xyes"; then
AC_MSG_FAILURE([
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
via the LDFLAGS environment variable.
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
============================================================================
ERROR!
You probably have to install the development version of the Python package
for your distribution. The exact name of this package varies among them.
============================================================================
])
PYTHON_VERSION=""
fi
#
# all done!
#
])

64
m4/ax_swig_python.m4 Normal file
View File

@ -0,0 +1,64 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_swig_python.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_SWIG_PYTHON([use-shadow-classes = {no, yes}])
#
# DESCRIPTION
#
# Checks for Python and provides the $(AX_SWIG_PYTHON_CPPFLAGS), and
# $(AX_SWIG_PYTHON_OPT) output variables.
#
# $(AX_SWIG_PYTHON_OPT) contains all necessary SWIG options to generate
# code for Python. Shadow classes are enabled unless the value of the
# optional first argument is exactly 'no'. If you need multi module
# support (provided by the AX_SWIG_MULTI_MODULE_SUPPORT macro) use
# $(AX_SWIG_PYTHON_LIBS) to link against the appropriate library. It
# contains the SWIG Python runtime library that is needed by the type
# check system for example.
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 7
AU_ALIAS([SWIG_PYTHON], [AX_SWIG_PYTHON])
AC_DEFUN([AX_SWIG_PYTHON],[
AC_REQUIRE([AX_PKG_SWIG])
AC_REQUIRE([AX_PYTHON_DEVEL])
test "x$1" != "xno" || swig_shadow=" -noproxy"
AC_SUBST([AX_SWIG_PYTHON_OPT],[-python$swig_shadow])
AC_SUBST([AX_SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
])

216
python/doc/conf.py Normal file
View File

@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
#
# libnl-python documentation build configuration file, created by
# sphinx-quickstart on Mon May 9 10:58:58 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'libnl-python'
copyright = u'2011, Thomas Graf <tgraf@suug.ch>'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'libnl-pythondoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'libnl-python.tex', u'libnl-python Documentation',
u'Thomas Graf \\textless{}tgraf@suug.ch\\textgreater{}', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'libnl-python', u'libnl-python Documentation',
[u'Thomas Graf <tgraf@suug.ch>'], 1)
]

215
python/doc/core.rst Normal file
View File

@ -0,0 +1,215 @@
*******************
Netlink Core Module
*******************
.. py:module:: netlink.core
Examples::
import netlink.core as netlink
===============
Object
===============
.. py:class:: Object
Base class for all classes representing a cacheable object
Example::
obj = netlink.Object("route/link", "link")
.. py:method:: clone
Clone the object and return a duplicate (used for COW)
.. py:method:: dump([params=None])
Call the libnl internal dump mechanism to dump the object
according to the parameters specified.
.. py:method:: apply(attr, val)
Applies a attribute=value pair and modifies the object accordingly.
Example::
obj.apply("mtu", 1200) # Sets attribute mtu to 1200 (link obj)
:raises: KeyError if attribute is unknown
:raises: ImmutableError if attribute is not mutable
.. py:attribute:: mark
True if the object is marked, otherwise False.
.. py:attribute:: shared
True if the object is used by multiple parties, otherwise False.
.. py:attribute:: refcnt
Number of users sharing a reference to the object
:rtype: int
.. py:attribute:: attrs
List of attributes
:rtype: list of strings
===============
Cache
===============
.. py:class:: Cache
Base class for all cache implementations.
A cache is a collection of cacheable objects which is typically used
by netlink protocols which handle any kind of object, e.g. network
links, network addresses, neighbours, ...
.. py:method:: subset(filter)
Returns a new cache containing the subset which matches the
provided filter.
:raises: ValueError if no filter is specified
:rtype: :py:class:`Cache`
.. py:method:: dump([params=None, filter=None])
Calls the libnl internal dump mechanism to dump the cache according
to the parameters and filter specified.
.. py:method:: clear()
Remove and possibly destroy all objects in the cache
.. py:method:: refill([socket=None]) -> :py:class:`Cache`
Clears and refills the cache with the content which is provided by
the kernel, e.g. for a link cache this would mean refilling the
cache with all configured network links.
.. py:method:: provide()
Caches which have been "provided" are made available to other users
(of the same application context) which "require" it. F.e. a link
cache is generally provided to allow others to translate interface
indexes to link names
.. py:method:: unprovide()
No longer make the cache available to others. If the cache has been
handed out already, that reference will still be valid.
===============
AbstractAddress
===============
.. py:class:: AbstractAddress
Abstract representation of an address. This class is not to be mistaken
with :py:class:`route.Address` which represents a configured network
address. This class represents the actual address in a family independent
way::
addr = netlink.AbstractAddress('127.0.0.1/8')
print addr # => '127.0.0.1/8'
print addr.prefixlen # => '8'
print addr.family # => 'inet'
print len(addr) # => '4' (32bit ipv4 address)
a = netlink.AbstractAddress('10.0.0.1/24')
b = netlink.AbstractAddress('10.0.0.2/24')
print a == b # => False
.. py:attribute:: prefixlen
Length of prefix in number of bits.
:rtype: int
.. py:attribute:: family
The family type of the address. Setting the address family can be
done with a string or a :py:class:`AddressFamily` object.
:rtype: :py:class:`AddressFamily`
.. py:attribute:: shared
True if address is in use by multiple callers, otherwise False
:rtype: bool
===============
AddressFamily
===============
.. py:class:: AddressFamily
Address family representation::
af = netlink.AddressFamily('inet6')
# raises:
# - ValueError if family name is not known
# - TypeError if invalid type is specified for family
print af # => 'inet6' (string representation)
print int(af) # => 10 (numeric representation)
print repr(af) # => AddressFamily('inet6')
===============
Exceptions
===============
.. py:exception:: NetlinkError
Generic exception raised by netlink modules.
.. py:exception:: KernelError
Raised if an error occured while communicating with the kernel. Contains
the error code returning which is automatically included in the error
message.
.. py:exception:: ImmutableError
Raised if an attribute is modified which is marked immutable.
===============
Socket
===============
.. py:class:: Socket
Netlink socket.
Note: It is not required to manually create and connect netlink sockets
when using caches. The caches will automatically lookup or create a
socket as needed.
.. py:attribute:: local_port
Local port (address) of netlink socket
.. py:attribute:: peer_port
Peer port (remote address) of netlink socket. If set, all messages
will be sent to that peer.
.. py:method:: connect(proto)
Connect the netlink socket using the specified netlink protocol::
sock.connect(netlink.NETLINK_ROUTE)
.. py:method:: disconnect()
Disconnect the socket
.. py:method:: set_bufsize(rx, tx)
Sets the size of the socket buffer

24
python/doc/index.rst Normal file
View File

@ -0,0 +1,24 @@
.. libnl-python documentation master file, created by
sphinx-quickstart on Mon May 9 10:58:58 2011.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to libnl-python's documentation!
========================================
Contents:
.. toctree::
:maxdepth: 2
core
route
route_addr
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

3
python/doc/route.rst Normal file
View File

@ -0,0 +1,3 @@
**********************
Routing
**********************

47
python/doc/route_addr.rst Normal file
View File

@ -0,0 +1,47 @@
=================
Network Addresses
=================
The **Address** module provides access to the network address configuration
of the kernel. It provides an interface to fetch all configured addresses,
add new addresses and to delete existing addresses.
Fetching the list of network addresses is achieved by creating a new
address cache::
import netlink.route.address as Address
addr_cache = Address.AddressCache()
addr_cache.refill()
for addr in addr_cache:
print addr
.. py:module:: netlink.route.addr
AddressCache
------------
.. py:class:: AddressCache
Represents a cache containing all or a subset of network addresses.
.. py:method:: lookup(ifindex, local)
Lookup the address which matches ifindex and local address
:raises: KeyError if address is not found.
Address
-------
.. py:class:: Address
Representation of a configured network address.
.. py:attribute:: ifindex
Interface index
:rtype: int

View File

457
python/netlink/capi.i Normal file
View File

@ -0,0 +1,457 @@
%module capi
%{
#include <netlink/netlink.h>
#include <netlink/types.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <netlink/object.h>
#include <netlink/cache.h>
%}
%include <stdint.i>
%include <cstring.i>
%inline %{
struct nl_dump_params *alloc_dump_params(void)
{
struct nl_dump_params *dp;
if (!(dp = calloc(1, sizeof(*dp))))
return NULL;
dp->dp_fd = stdout;
return dp;
}
void free_dump_params(struct nl_dump_params *dp)
{
free(dp);
}
%};
/* <netlink/types.h> */
enum nl_dump_type {
NL_DUMP_LINE, /**< Dump object briefly on one line */
NL_DUMP_DETAILS, /**< Dump all attributes but no statistics */
NL_DUMP_STATS, /**< Dump all attributes including statistics */
__NL_DUMP_MAX,
};
struct nl_dump_params
{
/**
* Specifies the type of dump that is requested.
*/
enum nl_dump_type dp_type;
/**
* Specifies the number of whitespaces to be put in front
* of every new line (indentation).
*/
int dp_prefix;
/**
* Causes the cache index to be printed for each element.
*/
int dp_print_index;
/**
* Causes each element to be prefixed with the message type.
*/
int dp_dump_msgtype;
/**
* A callback invoked for output
*
* Passed arguments are:
* - dumping parameters
* - string to append to the output
*/
void (*dp_cb)(struct nl_dump_params *, char *);
/**
* A callback invoked for every new line, can be used to
* customize the indentation.
*
* Passed arguments are:
* - dumping parameters
* - line number starting from 0
*/
void (*dp_nl_cb)(struct nl_dump_params *, int);
/**
* User data pointer, can be used to pass data to callbacks.
*/
void *dp_data;
/**
* File descriptor the dumping output should go to
*/
FILE * dp_fd;
/**
* Alternatively the output may be redirected into a buffer
*/
char * dp_buf;
/**
* Length of the buffer dp_buf
*/
size_t dp_buflen;
/**
* PRIVATE
* Set if a dump was performed prior to the actual dump handler.
*/
int dp_pre_dump;
/**
* PRIVATE
* Owned by the current caller
*/
int dp_ivar;
unsigned int dp_line;
};
/* <netlink/errno.h> */
extern const char *nl_geterror(int);
/* <netlink/utils.h> */
extern double nl_cancel_down_bytes(unsigned long long, char **);
extern double nl_cancel_down_bits(unsigned long long, char **);
extern double nl_cancel_down_us(uint32_t, char **);
extern long nl_size2int(const char *);
%cstring_output_maxsize(char *buf, const size_t len)
extern char *nl_size2str(const size_t, char *buf, const size_t len);
extern long nl_prob2int(const char *);
extern int nl_get_user_hz(void);
extern uint32_t nl_us2ticks(uint32_t);
extern uint32_t nl_ticks2us(uint32_t);
extern int nl_str2msec(const char *, uint64_t *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_msec2str(uint64_t, char *buf, size_t len);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_llproto2str(int, char *buf, size_t len);
extern int nl_str2llproto(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_ether_proto2str(int, char *buf, size_t len);
extern int nl_str2ether_proto(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_ip_proto2str(int, char *buf, size_t len);
extern int nl_str2ip_proto(const char *);
extern void nl_new_line(struct nl_dump_params *);
extern void nl_dump(struct nl_dump_params *, const char *, ...);
extern void nl_dump_line(struct nl_dump_params *, const char *, ...);
/* <netlink/netlink.h> */
extern struct nl_dump_params *alloc_dump_params(void);
extern void free_dump_params(struct nl_dump_params *);
extern int nl_connect(struct nl_sock *, int);
extern void nl_close(struct nl_sock *);
extern int nl_pickup(struct nl_sock *, int (*parser)(struct nl_cache_ops *,
struct sockaddr_nl *,
struct nlmsghdr *,
struct nl_parser_param *),
struct nl_object **);
/* <netlink/socket.h> */
extern struct nl_sock *nl_socket_alloc(void);
extern struct nl_sock *nl_socket_alloc_cb(struct nl_cb *);
extern void nl_socket_free(struct nl_sock *);
extern uint32_t nl_socket_get_local_port(const struct nl_sock *);
extern void nl_socket_set_local_port(struct nl_sock *, uint32_t);
extern uint32_t nl_socket_get_peer_port(const struct nl_sock *);
extern void nl_socket_set_peer_port(struct nl_sock *, uint32_t);
extern uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk);
extern void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups);
extern int nl_socket_set_buffer_size(struct nl_sock *, int, int);
/* <netlink/msg.h> */
extern int nlmsg_size(int);
extern int nlmsg_total_size(int);
extern int nlmsg_padlen(int);
extern void * nlmsg_data(const struct nlmsghdr *);
extern int nlmsg_datalen(const struct nlmsghdr *);
extern void * nlmsg_tail(const struct nlmsghdr *);
/* attribute access */
extern struct nlattr * nlmsg_attrdata(const struct nlmsghdr *, int);
extern int nlmsg_attrlen(const struct nlmsghdr *, int);
/* message parsing */
extern int nlmsg_valid_hdr(const struct nlmsghdr *, int);
extern int nlmsg_ok(const struct nlmsghdr *, int);
extern struct nlmsghdr * nlmsg_next(struct nlmsghdr *, int *);
extern int nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
int, struct nla_policy *);
extern struct nlattr * nlmsg_find_attr(struct nlmsghdr *, int, int);
extern int nlmsg_validate(struct nlmsghdr *, int, int,
struct nla_policy *);
extern struct nl_msg * nlmsg_alloc(void);
extern struct nl_msg * nlmsg_alloc_size(size_t);
extern struct nl_msg * nlmsg_alloc_simple(int, int);
extern void nlmsg_set_default_size(size_t);
extern struct nl_msg * nlmsg_inherit(struct nlmsghdr *);
extern struct nl_msg * nlmsg_convert(struct nlmsghdr *);
extern void * nlmsg_reserve(struct nl_msg *, size_t, int);
extern int nlmsg_append(struct nl_msg *, void *, size_t, int);
extern int nlmsg_expand(struct nl_msg *, size_t);
extern struct nlmsghdr * nlmsg_put(struct nl_msg *, uint32_t, uint32_t,
int, int, int);
extern struct nlmsghdr * nlmsg_hdr(struct nl_msg *);
extern void nlmsg_get(struct nl_msg *);
extern void nlmsg_free(struct nl_msg *);
/* attribute modification */
extern void nlmsg_set_proto(struct nl_msg *, int);
extern int nlmsg_get_proto(struct nl_msg *);
extern size_t nlmsg_get_max_size(struct nl_msg *);
extern void nlmsg_set_src(struct nl_msg *, struct sockaddr_nl *);
extern struct sockaddr_nl *nlmsg_get_src(struct nl_msg *);
extern void nlmsg_set_dst(struct nl_msg *, struct sockaddr_nl *);
extern struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *);
extern void nlmsg_set_creds(struct nl_msg *, struct ucred *);
extern struct ucred * nlmsg_get_creds(struct nl_msg *);
extern char * nl_nlmsgtype2str(int, char *, size_t);
extern int nl_str2nlmsgtype(const char *);
extern char * nl_nlmsg_flags2str(int, char *, size_t);
extern int nl_msg_parse(struct nl_msg *,
void (*cb)(struct nl_object *, void *),
void *);
extern void nl_msg_dump(struct nl_msg *, FILE *);
%inline %{
struct nl_object *cast_obj(void *obj)
{
return (struct nl_object *) obj;
}
struct nl_object *object_alloc_name(const char *name)
{
struct nl_object *obj;
if (nl_object_alloc_name(name, &obj) < 0)
return NULL;
return obj;
}
%};
extern struct nl_object *nl_object_alloc(struct nl_object_ops *);
extern void nl_object_free(struct nl_object *);
extern struct nl_object *nl_object_clone(struct nl_object *);
extern void nl_object_get(struct nl_object *);
extern void nl_object_put(struct nl_object *);
extern int nl_object_shared(struct nl_object *);
%cstring_output_maxsize(char *buf, size_t len)
extern void nl_object_dump_buf(struct nl_object *, char *buf, size_t len);
extern void nl_object_dump(struct nl_object *, struct nl_dump_params *);
extern int nl_object_identical(struct nl_object *, struct nl_object *);
extern uint32_t nl_object_diff(struct nl_object *, struct nl_object *);
extern int nl_object_match_filter(struct nl_object *, struct nl_object *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_object_attrs2str(struct nl_object *, uint32_t, char *buf, size_t len);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_object_attr_list(struct nl_object *, char *buf, size_t len);
extern void nl_object_mark(struct nl_object *);
extern void nl_object_unmark(struct nl_object *);
extern int nl_object_is_marked(struct nl_object *);
extern int nl_object_get_refcnt(struct nl_object *);
/* <netlink/cache.h> */
typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *);
%inline %{
struct nl_cache *alloc_cache_name(const char *name)
{
struct nl_cache *c;
if (nl_cache_alloc_name(name, &c) < 0)
return NULL;
return c;
}
struct nl_cache_mngr *alloc_cache_mngr(struct nl_sock *sock,
int protocol, int flags)
{
struct nl_cache_mngr *mngr;
if (nl_cache_mngr_alloc(sock, protocol, flags, &mngr) < 0)
return NULL;
return mngr;
}
struct nl_cache *cache_mngr_add(struct nl_cache_mngr *mngr,
const char *name, change_func_t func,
void *arg)
{
struct nl_cache *cache;
if (nl_cache_mngr_add(mngr, name, func, arg, &cache) < 0)
return NULL;
return cache;
}
%}
/* Access Functions */
extern int nl_cache_nitems(struct nl_cache *);
extern int nl_cache_nitems_filter(struct nl_cache *,
struct nl_object *);
extern struct nl_cache_ops * nl_cache_get_ops(struct nl_cache *);
extern struct nl_object * nl_cache_get_first(struct nl_cache *);
extern struct nl_object * nl_cache_get_last(struct nl_cache *);
extern struct nl_object * nl_cache_get_next(struct nl_object *);
extern struct nl_object * nl_cache_get_prev(struct nl_object *);
extern struct nl_cache * nl_cache_alloc(struct nl_cache_ops *);
extern struct nl_cache * nl_cache_subset(struct nl_cache *,
struct nl_object *);
extern void nl_cache_clear(struct nl_cache *);
extern void nl_cache_free(struct nl_cache *);
/* Cache modification */
extern int nl_cache_add(struct nl_cache *,
struct nl_object *);
extern int nl_cache_parse_and_add(struct nl_cache *,
struct nl_msg *);
extern void nl_cache_remove(struct nl_object *);
extern int nl_cache_refill(struct nl_sock *,
struct nl_cache *);
extern int nl_cache_pickup(struct nl_sock *,
struct nl_cache *);
extern int nl_cache_resync(struct nl_sock *,
struct nl_cache *,
change_func_t,
void *);
extern int nl_cache_include(struct nl_cache *,
struct nl_object *,
change_func_t,
void *);
extern void nl_cache_set_arg1(struct nl_cache *, int);
extern void nl_cache_set_arg2(struct nl_cache *, int);
/* General */
extern int nl_cache_is_empty(struct nl_cache *);
extern struct nl_object * nl_cache_search(struct nl_cache *,
struct nl_object *);
extern void nl_cache_mark_all(struct nl_cache *);
/* Dumping */
extern void nl_cache_dump(struct nl_cache *,
struct nl_dump_params *);
extern void nl_cache_dump_filter(struct nl_cache *,
struct nl_dump_params *,
struct nl_object *);
/* Iterators */
extern void nl_cache_foreach(struct nl_cache *,
void (*cb)(struct nl_object *,
void *),
void *arg);
extern void nl_cache_foreach_filter(struct nl_cache *,
struct nl_object *,
void (*cb)(struct
nl_object *,
void *),
void *arg);
/* --- cache management --- */
/* Cache type management */
extern struct nl_cache_ops * nl_cache_ops_lookup(const char *);
extern struct nl_cache_ops * nl_cache_ops_associate(int, int);
extern struct nl_msgtype * nl_msgtype_lookup(struct nl_cache_ops *, int);
extern void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *);
extern int nl_cache_mngt_register(struct nl_cache_ops *);
extern int nl_cache_mngt_unregister(struct nl_cache_ops *);
/* Global cache provisioning/requiring */
extern void nl_cache_mngt_provide(struct nl_cache *);
extern void nl_cache_mngt_unprovide(struct nl_cache *);
extern struct nl_cache * nl_cache_mngt_require(const char *);
struct nl_cache_mngr;
#define NL_AUTO_PROVIDE 1
extern int nl_cache_mngr_get_fd(struct nl_cache_mngr *);
extern int nl_cache_mngr_poll(struct nl_cache_mngr *,
int);
extern int nl_cache_mngr_data_ready(struct nl_cache_mngr *);
extern void nl_cache_mngr_free(struct nl_cache_mngr *);
/* <netlink/addr.h> */
%inline %{
struct nl_addr *addr_parse(const char *addr, int guess)
{
struct nl_addr *result;
if (nl_addr_parse(addr, guess, &result) < 0)
return NULL;
return result;
}
%};
extern struct nl_addr *nl_addr_alloc(size_t);
extern struct nl_addr *nl_addr_alloc_attr(struct nlattr *, int);
extern struct nl_addr *nl_addr_build(int, void *, size_t);
extern struct nl_addr *nl_addr_clone(struct nl_addr *);
extern struct nl_addr *nl_addr_get(struct nl_addr *);
extern void nl_addr_put(struct nl_addr *);
extern int nl_addr_shared(struct nl_addr *);
extern int nl_addr_cmp(struct nl_addr *, struct nl_addr *);
extern int nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
extern int nl_addr_iszero(struct nl_addr *);
extern int nl_addr_valid(char *, int);
extern int nl_addr_guess_family(struct nl_addr *);
extern int nl_addr_fill_sockaddr(struct nl_addr *, struct sockaddr *, socklen_t *);
extern int nl_addr_info(struct nl_addr *, struct addrinfo **);
extern int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen);
extern void nl_addr_set_family(struct nl_addr *, int);
extern int nl_addr_get_family(struct nl_addr *);
extern int nl_addr_set_binary_addr(struct nl_addr *, void *, size_t);
extern void *nl_addr_get_binary_addr(struct nl_addr *);
extern unsigned int nl_addr_get_len(struct nl_addr *);
extern void nl_addr_set_prefixlen(struct nl_addr *, int);
extern unsigned int nl_addr_get_prefixlen(struct nl_addr *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_af2str(int, char *buf, size_t len);
extern int nl_str2af(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *nl_addr2str(struct nl_addr *, char *buf, size_t len);

737
python/netlink/core.py Normal file
View File

@ -0,0 +1,737 @@
#
# Netlink interface based on libnl
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""netlink library based on libnl
This module provides an interface to netlink sockets
The module contains the following public classes:
- Socket -- The netlink socket
- Object -- Abstract object (based on struct nl_obect in libnl) used as
base class for all object types which can be put into a Cache
- Cache -- A collection of objects which are derived from the base
class Object. Used for netlink protocols which maintain a list
or tree of objects.
- DumpParams --
The following exceptions are defined:
- NetlinkError -- Base exception for all general purpose exceptions raised.
- KernelError -- Raised when the kernel returns an error as response to a
request.
All other classes or functions in this module are considered implementation
details.
"""
import capi
import sys
import socket
import struct
__all__ = ['Message', 'Socket', 'DumpParams', 'Object', 'Cache', 'KernelError',
'NetlinkError']
__version__ = "0.1"
# netlink protocols
NETLINK_ROUTE = 0
# NETLINK_UNUSED = 1
NETLINK_USERSOCK = 2
NETLINK_FIREWALL = 3
NETLINK_INET_DIAG = 4
NETLINK_NFLOG = 5
NETLINK_XFRM = 6
NETLINK_SELINUX = 7
NETLINK_ISCSI = 8
NETLINK_AUDIT = 9
NETLINK_FIB_LOOKUP = 10
NETLINK_CONNECTOR = 11
NETLINK_NETFILTER = 12
NETLINK_IP6_FW = 13
NETLINK_DNRTMSG = 14
NETLINK_KOBJECT_UEVENT = 15
NETLINK_GENERIC = 16
NETLINK_SCSITRANSPORT = 18
NETLINK_ECRYPTFS = 19
NL_DONTPAD = 0
NL_AUTO_PORT = 0
NL_AUTO_SEQ = 0
NL_DUMP_LINE = 0
NL_DUMP_DETAILS = 1
NL_DUMP_STATS = 2
NLM_F_REQUEST = 1
NLM_F_MULTI = 2
NLM_F_ACK = 4
NLM_F_ECHO = 8
NLM_F_ROOT = 0x100
NLM_F_MATCH = 0x200
NLM_F_ATOMIC = 0x400
NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
NLM_F_REPLACE = 0x100
NLM_F_EXCL = 0x200
NLM_F_CREATE = 0x400
NLM_F_APPEND = 0x800
class NetlinkError(Exception):
def __init__(self, error):
self._error = error
self._msg = capi.nl_geterror(error)
def __str__(self):
return self._msg
class KernelError(NetlinkError):
def __str__(self):
return "Kernel returned: " + self._msg
class ImmutableError(NetlinkError):
def __init__(self, msg):
self._msg = msg
def __str__(self):
return "Immutable attribute: " + self._msg
class Message(object):
"""Netlink message"""
def __init__(self, size=0):
if size == 0:
self._msg = capi.nlmsg_alloc()
else:
self._msg = capi.nlmsg_alloc_size(size)
if self._msg is None:
raise Exception("Message allocation returned NULL")
def __del__(self):
capi.nlmsg_free(self._msg)
def __len__(self):
return capi.nlmsg_len(nlmsg_hdr(self._msg))
@property
def protocol(self):
return capi.nlmsg_get_proto(self._msg)
@protocol.setter
def protocol(self, value):
capi.nlmsg_set_proto(self._msg, value)
@property
def maxSize(self):
return capi.nlmsg_get_max_size(self._msg)
@property
def hdr(self):
return capi.nlmsg_hdr(self._msg)
@property
def data(self):
return capi.nlmsg_data(self._msg)
@property
def attrs(self):
return capi.nlmsg_attrdata(self._msg)
def send(self, socket):
socket.send(self)
class Socket(object):
"""Netlink socket"""
def __init__(self, cb=None):
if cb is None:
self._sock = capi.nl_socket_alloc()
else:
self._sock = capi.nl_socket_alloc_cb(cb)
if self._sock is None:
raise Exception("NULL pointer returned while allocating socket")
def __del__(self):
capi.nl_socket_free(self._sock)
def __str__(self):
return "nlsock<" + str(self.localPort) + ">"
@property
def local_port(self):
return capi.nl_socket_get_local_port(self._sock)
@local_port.setter
def local_port(self, value):
capi.nl_socket_set_local_port(self._sock, int(value))
@property
def peer_port(self):
return capi.nl_socket_get_peer_port(self._sock)
@peer_port.setter
def peer_port(self, value):
capi.nl_socket_set_peer_port(self._sock, int(value))
@property
def peer_groups(self):
return capi.nl_socket_get_peer_groups(self._sock)
@peer_groups.setter
def peer_groups(self, value):
capi.nl_socket_set_peer_groups(self._sock, value)
def set_bufsize(self, rx, tx):
capi.nl_socket_set_buffer_size(self._sock, rx, tx)
def connect(self, proto):
capi.nl_connect(self._sock, proto)
return self
def disconnect(self):
capi.nl_close(self._sock)
def sendto(self, buf):
ret = capi.nl_sendto(self._sock, buf, len(buf))
if ret < 0:
raise Exception("Failed to send")
else:
return ret
_sockets = {}
def lookup_socket(protocol):
try:
sock = _sockets[protocol]
except KeyError:
sock = Socket()
sock.connect(protocol)
_sockets[protocol] = sock
return sock
class DumpParams(object):
"""Dumping parameters"""
def __init__(self, type=NL_DUMP_LINE):
self._dp = capi.alloc_dump_params()
if not self._dp:
raise Exception("Unable to allocate struct nl_dump_params")
self._dp.dp_type = type
def __del__(self):
capi.free_dump_params(self._dp)
@property
def type(self):
return self._dp.dp_type
@type.setter
def type(self, value):
self._dp.dp_type = value
@property
def prefix(self):
return self._dp.dp_prefix
@prefix.setter
def prefix(self, value):
self._dp.dp_prefix = value
# underscore this to make sure it is deleted first upon module deletion
_defaultDumpParams = DumpParams(type=NL_DUMP_LINE)
###########################################################################
# Cacheable Object (Base Class)
class Object(object):
"""Cacheable object (base class)"""
def __init__(self, obj_name, name, obj=None):
self._obj_name = obj_name
self._name = name
if not obj:
obj = capi.object_alloc_name(self._obj_name)
self._nl_object = obj
# Create a clone which stores the original state to notice
# modifications
clone_obj = capi.nl_object_clone(self._nl_object)
self._orig = self._obj2type(clone_obj)
def __del__(self):
if not self._nl_object:
raise ValueError()
capi.nl_object_put(self._nl_object)
def __str__(self):
if hasattr(self, 'format'):
return self.format()
else:
return capi.nl_object_dump_buf(self._nl_object, 4096).rstrip()
def _new_instance(self):
raise NotImplementedError()
def clone(self):
"""Clone object"""
return self._new_instance(capi.nl_object_clone(self._nl_object))
def dump(self, params=None):
"""Dump object as human readable text"""
if params is None:
params = _defaultDumpParams
capi.nl_object_dump(self._nl_object, params._dp)
#####################################################################
# mark
@property
def mark(self):
if capi.nl_object_is_marked(self.obj):
return True
else:
return False
@mark.setter
def mark(self, value):
if value:
capi.nl_object_mark(self._nl_object)
else:
capi.nl_object_unmark(self._nl_object)
#####################################################################
# shared
@property
def shared(self):
return capi.nl_object_shared(self._nl_object) != 0
#####################################################################
# attrs
@property
def attrs(self):
attr_list = capi.nl_object_attr_list(self._nl_object, 1024)
return re.split('\W+', attr_list[0])
#####################################################################
# refcnt
@property
def refcnt(self):
return capi.nl_object_get_refcnt(self._nl_object)
# this method resolves multiple levels of sub types to allow
# accessing properties of subclass/subtypes (e.g. link.vlan.id)
def _resolve(self, attr):
obj = self
l = attr.split('.')
while len(l) > 1:
obj = getattr(obj, l.pop(0))
return (obj, l.pop(0))
def _setattr(self, attr, val):
obj, attr = self._resolve(attr)
return setattr(obj, attr, val)
def _hasattr(self, attr):
obj, attr = self._resolve(attr)
return hasattr(obj, attr)
def apply(self, attr, val):
try:
d = attrs[self._name + "." + attr]
except KeyError:
raise KeyError("Unknown " + self._name +
" attribute: " + attr)
if 'immutable' in d:
raise ImmutableError(attr)
if not self._hasattr(attr):
raise KeyError("Invalid " + self._name +
" attribute: " + attr)
self._setattr(attr, val)
class ObjIterator(object):
def __init__(self, cache, obj):
self._cache = cache
capi.nl_object_get(obj)
self._nl_object = obj
self._first = 1
self._end = 0
def __del__(self):
if self._nl_object:
capi.nl_object_put(self._nl_object)
def __iter__(self):
return self
def get_next(self):
return capi.nl_cache_get_next(self._nl_object)
def next(self):
if self._end:
raise StopIteration()
if self._first:
ret = self._nl_object
self._first = 0
else:
ret = self.get_next()
if not ret:
self._end = 1
raise StopIteration()
# return ref of previous element and acquire ref of current
# element to have object stay around until we fetched the
# next ptr
capi.nl_object_put(self._nl_object)
capi.nl_object_get(ret)
self._nl_object = ret
# reference used inside object
capi.nl_object_get(ret)
return self._cache._new_object(ret)
class ReverseObjIterator(ObjIterator):
def get_next(self):
return capi.nl_cache_get_prev(self._nl_object)
###########################################################################
# Cache
class Cache(object):
"""Collection of netlink objects"""
def __init__(self):
raise NotImplementedError()
def __del(self):
capi.nl_cache_free(self._c_cache)
def __len__(self):
return capi.nl_cache_nitems(self._c_cache)
def __iter__(self):
obj = capi.nl_cache_get_first(self._c_cache)
return ObjIterator(self, obj)
def __reversed__(self):
obj = capi.nl_cache_get_last(self._c_cache)
return ReverseObjIterator(self, obj)
def __contains__(self, item):
obj = capi.nl_cache_search(self._c_cache, item._nl_object)
if obj is None:
return False
else:
capi.nl_object_put(obj)
return True
# called by sub classes to allocate type specific caches by name
def _alloc_cache_name(self, name):
return capi.alloc_cache_name(name)
# implemented by sub classes, must return new instasnce of cacheable
# object
def _new_object(self, obj):
raise NotImplementedError()
# implemented by sub classes, must return instance of sub class
def _new_cache(self, cache):
raise NotImplementedError()
def subset(self, filter):
"""Return new cache containing subset of cache
Cretes a new cache containing all objects which match the
specified filter.
"""
if not filter:
raise ValueError()
c = capi.nl_cache_subset(self._c_cache, filter._nl_object)
return self._new_cache(cache=c)
def dump(self, params=None, filter=None):
"""Dump (print) cache as human readable text"""
if not params:
params = _defaultDumpParams
if filter:
filter = filter._nl_object
capi.nl_cache_dump_filter(self._c_cache, params._dp, filter)
def clear(self):
"""Remove all cache entries"""
capi.nl_cache_clear(self._c_cache)
# Called by sub classes to set first cache argument
def _set_arg1(self, arg):
self.arg1 = arg
capi.nl_cache_set_arg1(self._c_cache, arg)
# Called by sub classes to set second cache argument
def _set_arg2(self, arg):
self.arg2 = arg
capi.nl_cache_set_arg2(self._c_cache, arg)
def refill(self, socket=None):
"""Clear cache and refill it"""
if socket is None:
socket = lookup_socket(self._protocol)
capi.nl_cache_refill(socket._sock, self._c_cache)
return self
def resync(self, socket=None, cb=None):
"""Synchronize cache with content in kernel"""
if socket is None:
socket = lookup_socket(self._protocol)
capi.nl_cache_resync(socket._sock, self._c_cache, cb)
def provide(self):
"""Provide this cache to others
Caches which have been "provided" are made available
to other users (of the same application context) which
"require" it. F.e. a link cache is generally provided
to allow others to translate interface indexes to
link names
"""
capi.nl_cache_mngt_provide(self._c_cache)
def unprovide(self):
"""Unprovide this cache
No longer make the cache available to others. If the cache
has been handed out already, that reference will still
be valid.
"""
capi.nl_cache_mngt_unprovide(self._c_cache)
###########################################################################
# Cache Manager (Work in Progress)
NL_AUTO_PROVIDE = 1
class CacheManager(object):
def __init__(self, protocol, flags=None):
self._sock = Socket()
self._sock.connect(protocol)
if not flags:
flags = NL_AUTO_PROVIDE
self._mngr = cache_mngr_alloc(self._sock._sock, protocol, flags)
def __del__(self):
if self._sock:
self._sock.disconnect()
if self._mngr:
capi.nl_cache_mngr_free(self._mngr)
def add(self, name):
capi.cache_mngr_add(self._mngr, name, None, None)
###########################################################################
# Address Family
class AddressFamily(object):
"""Address family representation
af = AddressFamily('inet6')
# raises:
# - ValueError if family name is not known
# - TypeError if invalid type is specified for family
print af # => 'inet6' (string representation)
print int(af) # => 10 (numeric representation)
print repr(af) # => AddressFamily('inet6')
"""
def __init__(self, family=socket.AF_UNSPEC):
if isinstance(family, str):
family = capi.nl_str2af(family)
if family < 0:
raise ValueError('Unknown family name')
elif not isinstance(family, int):
raise TypeError()
self._family = family
def __str__(self):
return capi.nl_af2str(self._family, 32)[0]
def __len__(self):
return len(str(self))
def __int__(self):
return self._family
def __repr__(self):
return 'AddressFamily(\'' + str(self) + '\')'
###########################################################################
# Abstract Address
class AbstractAddress(object):
"""Abstract address object
addr = AbstractAddress('127.0.0.1/8')
print addr # => '127.0.0.1/8'
print addr.prefixlen # => '8'
print addr.family # => 'inet'
print len(addr) # => '4' (32bit ipv4 address)
a = AbstractAddress('10.0.0.1/24')
b = AbstractAddress('10.0.0.2/24')
print a == b # => False
"""
def __init__(self, addr):
self._nl_addr = None
if isinstance(addr, str):
addr = capi.addr_parse(addr, socket.AF_UNSPEC)
if addr is None:
raise ValueError('Invalid address format')
elif addr:
capi.nl_addr_get(addr)
self._nl_addr = addr
def __del__(self):
if self._nl_addr:
capi.nl_addr_put(self._nl_addr)
def __cmp__(self, other):
if isinstance(other, str):
other = AbstractAddress(other)
diff = self.prefixlen - other.prefixlen
if diff == 0:
diff = capi.nl_addr_cmp(self._nl_addr, other._nl_addr)
return diff
def contains(self, item):
diff = int(self.family) - int(item.family)
if diff:
return False
if item.prefixlen < self.prefixlen:
return False
diff = capi.nl_addr_cmp_prefix(self._nl_addr, item._nl_addr)
return diff == 0
def __nonzero__(self):
if self._nl_addr:
return not capi.nl_addr_iszero(self._nl_addr)
else:
return False
def __len__(self):
if self._nl_addr:
return capi.nl_addr_get_len(self._nl_addr)
else:
return 0
def __str__(self):
if self._nl_addr:
return capi.nl_addr2str(self._nl_addr, 64)[0]
else:
return "none"
@property
def shared(self):
"""True if address is shared (multiple users)"""
if self._nl_addr:
return capi.nl_addr_shared(self._nl_addr) != 0
else:
return False
@property
def prefixlen(self):
"""Length of prefix (number of bits)"""
if self._nl_addr:
return capi.nl_addr_get_prefixlen(self._nl_addr)
else:
return 0
@prefixlen.setter
def prefixlen(self, value):
if not self._nl_addr:
raise TypeError()
capi.nl_addr_set_prefixlen(self._nl_addr, int(value))
@property
def family(self):
"""Address family"""
f = 0
if self._nl_addr:
f = capi.nl_addr_get_family(self._nl_addr)
return AddressFamily(f)
@family.setter
def family(self, value):
if not self._nl_addr:
raise TypeError()
if not isinstance(value, AddressFamily):
value = AddressFamily(value)
capi.nl_addr_set_family(self._nl_addr, int(value))
# global dictionay for all object attributes
#
# attrs[type][keyword] : value
#
# keyword:
# type = { int | str }
# immutable = { True | False }
# fmt = func (formatting function)
#
attrs = {}
def attr(name, **kwds):
attrs[name] = {}
for k in kwds:
attrs[name][k] = kwds[k]
def nlattr(name, **kwds):
"""netlink object attribute decorator
decorator used to mark mutable and immutable properties
of netlink objects. All properties marked as such are
regarded to be accessable.
@netlink.nlattr('my_type.my_attr', type=int)
@property
def my_attr(self):
return self._my_attr
"""
attrs[name] = {}
for k in kwds:
attrs[name][k] = kwds[k]
def wrap_fn(func):
return func
return wrap_fn

1
python/netlink/fixes.h Normal file
View File

@ -0,0 +1 @@
#include <stdint.h>

View File

View File

@ -0,0 +1,398 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""Module providing access to network addresses
"""
__version__ = "1.0"
__all__ = [
'AddressCache',
'Address']
import datetime
import netlink.core as netlink
import netlink.capi as core_capi
import netlink.route.capi as capi
import netlink.route.link as Link
import netlink.util as util
###########################################################################
# Address Cache
class AddressCache(netlink.Cache):
"""Cache containing network addresses"""
def __init__(self, cache=None):
if not cache:
cache = self._alloc_cache_name("route/addr")
self._protocol = netlink.NETLINK_ROUTE
self._c_cache = cache
def __getitem__(self, key):
# Using ifindex=0 here implies that the local address itself
# is unique, otherwise the first occurence is returned.
return self.lookup(0, key)
def lookup(self, ifindex, local):
if type(local) is str:
local = netlink.AbstractAddress(local)
addr = capi.rtnl_addr_get(self._c_cache, ifindex,
local._nl_addr)
if addr is None:
raise KeyError()
return Address._from_capi(addr)
def _new_object(self, obj):
return Address(obj)
def _new_cache(self, cache):
return AddressCache(cache=cache)
###########################################################################
# Address Object
class Address(netlink.Object):
"""Network address"""
def __init__(self, obj=None):
netlink.Object.__init__(self, "route/addr", "address", obj)
self._rtnl_addr = self._obj2type(self._nl_object)
@classmethod
def _from_capi(cls, obj):
return cls(capi.addr2obj(obj))
def _obj2type(self, obj):
return capi.obj2addr(obj)
def __cmp__(self, other):
# sort by:
# 1. network link
# 2. address family
# 3. local address (including prefixlen)
diff = self.ifindex - other.ifindex
if diff == 0:
diff = self.family - other.family
if diff == 0:
diff = capi.nl_addr_cmp(self.local, other.local)
return diff
def _new_instance(self, obj):
return Address(obj)
#####################################################################
# ifindex
@netlink.nlattr('address.ifindex', type=int, immutable=True,
fmt=util.num)
@property
def ifindex(self):
"""interface index"""
return capi.rtnl_addr_get_ifindex(self._rtnl_addr)
@ifindex.setter
def ifindex(self, value):
link = Link.resolve(value)
if not link:
raise ValueError()
self.link = link
#####################################################################
# link
@netlink.nlattr('address.link', type=str, fmt=util.string)
@property
def link(self):
link = capi.rtnl_addr_get_link(self._rtnl_addr)
if not link:
return None
return Link.Link.from_capi(link)
@link.setter
def link(self, value):
if type(value) is str:
try:
value = Link.resolve(value)
except KeyError:
raise ValueError()
capi.rtnl_addr_set_link(self._rtnl_addr, value._rtnl_link)
# ifindex is immutable but we assume that if _orig does not
# have an ifindex specified, it was meant to be given here
if capi.rtnl_addr_get_ifindex(self._orig) == 0:
capi.rtnl_addr_set_ifindex(self._orig, value.ifindex)
#####################################################################
# label
@netlink.nlattr('address.label', type=str, fmt=util.string)
@property
def label(self):
"""address label"""
return capi.rtnl_addr_get_label(self._rtnl_addr)
@label.setter
def label(self, value):
capi.rtnl_addr_set_label(self._rtnl_addr, value)
#####################################################################
# flags
@netlink.nlattr('address.flags', type=str, fmt=util.string)
@property
def flags(self):
"""Flags"""
flags = capi.rtnl_addr_get_flags(self._rtnl_addr)
return capi.rtnl_addr_flags2str(flags, 256)[0].split(',')
def _set_flag(self, flag):
if flag[0] == '-':
i = capi.rtnl_addr_str2flags(flag[1:])
capi.rtnl_addr_unset_flags(self._rtnl_addr, i)
else:
i = capi.rtnl_addr_str2flags(flag[1:])
capi.rtnl_addr_set_flags(self._rtnl_addr, i)
@flags.setter
def flags(self, value):
if type(value) is list:
for flag in value:
self._set_flag(flag)
else:
self._set_flag(value)
#####################################################################
# family
@netlink.nlattr('address.family', type=int, immutable=True,
fmt=util.num)
@property
def family(self):
"""Address family"""
fam = capi.rtnl_addr_get_family(self._rtnl_addr)
return netlink.AddressFamily(fam)
@family.setter
def family(self, value):
if not isinstance(value, AddressFamily):
value = AddressFamily(value)
capi.rtnl_addr_set_family(self._rtnl_addr, int(value))
#####################################################################
# scope
@netlink.nlattr('address.scope', type=int, fmt=util.num)
@property
def scope(self):
"""Address scope"""
scope = capi.rtnl_addr_get_scope(self._rtnl_addr)
return capi.rtnl_scope2str(scope, 32)[0]
@scope.setter
def scope(self, value):
if type(value) is str:
value = capi.rtnl_str2scope(value)
capi.rtnl_addr_set_scope(self._rtnl_addr, value)
#####################################################################
# local address
@netlink.nlattr('address.local', type=str, immutable=True,
fmt=util.addr)
@property
def local(self):
"""Local address"""
a = capi.rtnl_addr_get_local(self._rtnl_addr)
return netlink.AbstractAddress(a)
@local.setter
def local(self, value):
a = netlink.AbstractAddress(value)
capi.rtnl_addr_set_local(self._rtnl_addr, a._nl_addr)
# local is immutable but we assume that if _orig does not
# have a local address specified, it was meant to be given here
if capi.rtnl_addr_get_local(self._orig) is None:
capi.rtnl_addr_set_local(self._orig, a._nl_addr)
#####################################################################
# Peer address
@netlink.nlattr('address.peer', type=str, fmt=util.addr)
@property
def peer(self):
"""Peer address"""
a = capi.rtnl_addr_get_peer(self._rtnl_addr)
return netlink.AbstractAddress(a)
@peer.setter
def peer(self, value):
a = netlink.AbstractAddress(value)
capi.rtnl_addr_set_peer(self._rtnl_addr, a._nl_addr)
#####################################################################
# Broadcast address
@netlink.nlattr('address.broadcast', type=str, fmt=util.addr)
@property
def broadcast(self):
"""Broadcast address"""
a = capi.rtnl_addr_get_broadcast(self._rtnl_addr)
return netlink.AbstractAddress(a)
@broadcast.setter
def broadcast(self, value):
a = netlink.AbstractAddress(value)
capi.rtnl_addr_set_broadcast(self._rtnl_addr, a._nl_addr)
#####################################################################
# Multicast address
@netlink.nlattr('address.multicast', type=str, fmt=util.addr)
@property
def multicast(self):
"""multicast address"""
a = capi.rtnl_addr_get_multicast(self._rtnl_addr)
return netlink.AbstractAddress(a)
@multicast.setter
def multicast(self, value):
try:
a = netlink.AbstractAddress(value)
except ValueError as err:
raise AttributeError('multicast', err)
capi.rtnl_addr_set_multicast(self._rtnl_addr, a._nl_addr)
#####################################################################
# Anycast address
@netlink.nlattr('address.anycast', type=str, fmt=util.addr)
@property
def anycast(self):
"""anycast address"""
a = capi.rtnl_addr_get_anycast(self._rtnl_addr)
return netlink.AbstractAddress(a)
@anycast.setter
def anycast(self, value):
a = netlink.AbstractAddress(value)
capi.rtnl_addr_set_anycast(self._rtnl_addr, a._nl_addr)
#####################################################################
# Valid lifetime
@netlink.nlattr('address.valid_lifetime', type=int, immutable=True,
fmt=util.num)
@property
def valid_lifetime(self):
"""Valid lifetime"""
msecs = capi.rtnl_addr_get_valid_lifetime(self._rtnl_addr)
if msecs == 0xFFFFFFFF:
return None
else:
return datetime.timedelta(seconds=msecs)
@valid_lifetime.setter
def valid_lifetime(self, value):
capi.rtnl_addr_set_valid_lifetime(self._rtnl_addr, int(value))
#####################################################################
# Preferred lifetime
@netlink.nlattr('address.preferred_lifetime', type=int,
immutable=True, fmt=util.num)
@property
def preferred_lifetime(self):
"""Preferred lifetime"""
msecs = capi.rtnl_addr_get_preferred_lifetime(self._rtnl_addr)
if msecs == 0xFFFFFFFF:
return None
else:
return datetime.timedelta(seconds=msecs)
@preferred_lifetime.setter
def preferred_lifetime(self, value):
capi.rtnl_addr_set_preferred_lifetime(self._rtnl_addr, int(value))
#####################################################################
# Creation Time
@netlink.nlattr('address.create_time', type=int, immutable=True,
fmt=util.num)
@property
def create_time(self):
"""Creation time"""
hsec = capi.rtnl_addr_get_create_time(self._rtnl_addr)
return datetime.timedelta(milliseconds=10*hsec)
#####################################################################
# Last Update
@netlink.nlattr('address.last_update', type=int, immutable=True,
fmt=util.num)
@property
def last_update(self):
"""Last update"""
hsec = capi.rtnl_addr_get_last_update_time(self._rtnl_addr)
return datetime.timedelta(milliseconds=10*hsec)
#####################################################################
# add()
def add(self, socket=None, flags=None):
if not socket:
socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
if not flags:
flags = netlink.NLM_F_CREATE
ret = capi.rtnl_addr_add(socket._sock, self._rtnl_addr, flags)
if ret < 0:
raise netlink.KernelError(ret)
#####################################################################
# delete()
def delete(self, socket):
"""Attempt to delete this link in the kernel"""
ret = capi.rtnl_addr_delete(socket._sock, self._addr)
if ret < 0:
raise netlink.KernelError(ret)
###################################################################
# private properties
#
# Used for formatting output. USE AT OWN RISK
@property
def _flags(self):
return ','.join(self.flags)
###################################################################
#
# format(details=False, stats=False)
#
def format(self, details=False, stats=False, nodev=False, indent=''):
"""Return address as formatted text"""
fmt = util.MyFormatter(self, indent)
buf = fmt.format('{a|local!b}')
if not nodev:
buf += fmt.format(' {a|ifindex}')
buf += fmt.format(' {a|scope}')
if self.label:
buf += fmt.format(' "{a|label}"')
buf += fmt.format(' <{a|_flags}>')
if details:
buf += fmt.nl('\t{t|broadcast} {t|multicast}') \
+ fmt.nl('\t{t|peer} {t|anycast}')
if self.valid_lifetime:
buf += fmt.nl('\t{s|valid-lifetime!k} '\
'{a|valid_lifetime}')
if self.preferred_lifetime:
buf += fmt.nl('\t{s|preferred-lifetime!k} '\
'{a|preferred_lifetime}')
if stats and (self.create_time or self.last_update):
buf += self.nl('\t{s|created!k} {a|create_time}'\
' {s|last-updated!k} {a|last_update}')
return buf

338
python/netlink/route/capi.i Normal file
View File

@ -0,0 +1,338 @@
%module capi
%{
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
#include <netlink/route/link/inet.h>
#include <netlink/route/tc.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/addr.h>
%}
%include <stdint.i>
%include <cstring.i>
%inline %{
struct nl_object *link2obj(struct rtnl_link *link)
{
return OBJ_CAST(link);
}
struct rtnl_link *obj2link(struct nl_object *obj)
{
return (struct rtnl_link *) obj;
}
struct rtnl_link *get_from_kernel(struct nl_sock *sk, int ifindex, const char *name)
{
struct rtnl_link *link;
if (rtnl_link_get_kernel(sk, ifindex, name, &link) < 0)
return NULL;
return link;
}
uint32_t inet_get_conf(struct rtnl_link *link, const unsigned int id)
{
uint32_t result;
if (rtnl_link_inet_get_conf(link, id, &result) < 0)
return 0;
return result;
}
%};
extern struct nl_object *link2obj(struct rtnl_link *);
extern struct rtnl_link *obj2link(struct nl_object *);
/* <netlink/route/rtnl.h> */
%cstring_output_maxsize(char *buf, size_t len)
extern char * rtnl_scope2str(int, char *buf, size_t len);
extern int rtnl_str2scope(const char *);
/* <netlink/route/link.h> */
extern struct rtnl_link *rtnl_link_alloc(void);
extern struct rtnl_link *rtnl_link_get(struct nl_cache *, int);
extern struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *, const char *);
extern int rtnl_link_build_add_request(struct rtnl_link *, int, struct nl_msg **);
extern int rtnl_link_add(struct nl_sock *, struct rtnl_link *, int);
extern int rtnl_link_build_change_request(struct rtnl_link *, struct rtnl_link *, int, struct nl_msg **);
extern int rtnl_link_change(struct nl_sock *, struct rtnl_link *, struct rtnl_link *, int);
extern int rtnl_link_build_delete_request(const struct rtnl_link *, struct nl_msg **);
extern int rtnl_link_delete(struct nl_sock *, const struct rtnl_link *);
extern int rtnl_link_build_get_request(int, const char *, struct nl_msg **);
extern char *rtnl_link_stat2str(int, char *, size_t);
extern int rtnl_link_str2stat(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *rtnl_link_flags2str(int, char *buf, size_t len);
extern int rtnl_link_str2flags(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *rtnl_link_operstate2str(uint8_t, char *buf, size_t len);
extern int rtnl_link_str2operstate(const char *);
%cstring_output_maxsize(char *buf, size_t len)
extern char *rtnl_link_mode2str(uint8_t, char *buf, size_t len);
extern int rtnl_link_str2mode(const char *);
extern void rtnl_link_set_qdisc(struct rtnl_link *, const char *);
extern char *rtnl_link_get_qdisc(struct rtnl_link *);
extern void rtnl_link_set_name(struct rtnl_link *, const char *);
extern char *rtnl_link_get_name(struct rtnl_link *);
extern void rtnl_link_set_flags(struct rtnl_link *, unsigned int);
extern void rtnl_link_unset_flags(struct rtnl_link *, unsigned int);
extern unsigned int rtnl_link_get_flags(struct rtnl_link *);
extern void rtnl_link_set_mtu(struct rtnl_link *, unsigned int);
extern unsigned int rtnl_link_get_mtu(struct rtnl_link *);
extern void rtnl_link_set_txqlen(struct rtnl_link *, unsigned int);
extern unsigned int rtnl_link_get_txqlen(struct rtnl_link *);
extern void rtnl_link_set_weight(struct rtnl_link *, unsigned int);
extern unsigned int rtnl_link_get_weight(struct rtnl_link *);
extern void rtnl_link_set_ifindex(struct rtnl_link *, int);
extern int rtnl_link_get_ifindex(struct rtnl_link *);
extern void rtnl_link_set_family(struct rtnl_link *, int);
extern int rtnl_link_get_family(struct rtnl_link *);
extern void rtnl_link_set_arptype(struct rtnl_link *, unsigned int);
extern unsigned int rtnl_link_get_arptype(struct rtnl_link *);
extern void rtnl_link_set_addr(struct rtnl_link *, struct nl_addr *);
extern struct nl_addr *rtnl_link_get_addr(struct rtnl_link *);
extern void rtnl_link_set_broadcast(struct rtnl_link *, struct nl_addr *);
extern struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *);
extern void rtnl_link_set_link(struct rtnl_link *, int);
extern int rtnl_link_get_link(struct rtnl_link *);
extern void rtnl_link_set_master(struct rtnl_link *, int);
extern int rtnl_link_get_master(struct rtnl_link *);
extern void rtnl_link_set_operstate(struct rtnl_link *, uint8_t);
extern uint8_t rtnl_link_get_operstate(struct rtnl_link *);
extern void rtnl_link_set_linkmode(struct rtnl_link *, uint8_t);
extern uint8_t rtnl_link_get_linkmode(struct rtnl_link *);
extern const char *rtnl_link_get_ifalias(struct rtnl_link *);
extern void rtnl_link_set_ifalias(struct rtnl_link *, const char *);
extern int rtnl_link_get_num_vf(struct rtnl_link *, uint32_t *);
extern uint64_t rtnl_link_get_stat(struct rtnl_link *, int);
extern int rtnl_link_set_stat(struct rtnl_link *, const unsigned int, const uint64_t);
extern int rtnl_link_set_info_type(struct rtnl_link *, const char *);
extern char *rtnl_link_get_info_type(struct rtnl_link *);
/* <netlink/route/link/vlan.h> */
struct vlan_map
{
uint32_t vm_from;
uint32_t vm_to;
};
#define VLAN_PRIO_MAX 7
%cstring_output_maxsize(char *buf, size_t len)
extern char *rtnl_link_vlan_flags2str(int, char *buf, size_t len);
extern int rtnl_link_vlan_str2flags(const char *);
extern int rtnl_link_vlan_set_id(struct rtnl_link *, int);
extern int rtnl_link_vlan_get_id(struct rtnl_link *);
extern int rtnl_link_vlan_set_flags(struct rtnl_link *, unsigned int);
extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, unsigned int);
extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *);
extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, int, uint32_t);
extern uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *);
extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, uint32_t, int);
extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, int *);
/* <netlink/route/link/inet.h> */
%cstring_output_maxsize(char *buf, size_t len)
extern const char *rtnl_link_inet_devconf2str(int, char *buf, size_t len);
extern unsigned int rtnl_link_inet_str2devconf(const char *);
extern int rtnl_link_inet_set_conf(struct rtnl_link *, const unsigned int, uint32_t);
/* <netlink/route/tc.h> */
%inline %{
uint32_t tc_str2handle(const char *name)
{
uint32_t result;
if (rtnl_tc_str2handle(name, &result) < 0)
return 0;
return result;
}
%};
extern void rtnl_tc_set_ifindex(struct rtnl_tc *, int);
extern int rtnl_tc_get_ifindex(struct rtnl_tc *);
extern void rtnl_tc_set_link(struct rtnl_tc *, struct rtnl_link *);
extern struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *);
extern void rtnl_tc_set_mtu(struct rtnl_tc *, uint32_t);
extern uint32_t rtnl_tc_get_mtu(struct rtnl_tc *);
extern void rtnl_tc_set_mpu(struct rtnl_tc *, uint32_t);
extern uint32_t rtnl_tc_get_mpu(struct rtnl_tc *);
extern void rtnl_tc_set_overhead(struct rtnl_tc *, uint32_t);
extern uint32_t rtnl_tc_get_overhead(struct rtnl_tc *);
extern void rtnl_tc_set_linktype(struct rtnl_tc *, uint32_t);
extern uint32_t rtnl_tc_get_linktype(struct rtnl_tc *);
extern void rtnl_tc_set_handle(struct rtnl_tc *, uint32_t);
extern uint32_t rtnl_tc_get_handle(struct rtnl_tc *);
extern void rtnl_tc_set_parent(struct rtnl_tc *, uint32_t);
extern uint32_t rtnl_tc_get_parent(struct rtnl_tc *);
extern int rtnl_tc_set_kind(struct rtnl_tc *, const char *);
extern char * rtnl_tc_get_kind(struct rtnl_tc *);
extern uint64_t rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat);
extern int rtnl_tc_calc_txtime(int, int);
extern int rtnl_tc_calc_bufsize(int, int);
extern int rtnl_tc_calc_cell_log(int);
extern int rtnl_tc_read_classid_file(void);
%cstring_output_maxsize(char *buf, size_t len)
extern char * rtnl_tc_handle2str(uint32_t, char *buf, size_t len);
extern int rtnl_classid_generate(const char *, uint32_t *, uint32_t);
/* <netlink/route/qdisc.h> */
%inline %{
struct nl_object *qdisc2obj(struct rtnl_qdisc *qdisc)
{
return OBJ_CAST(qdisc);
}
struct rtnl_qdisc *obj2qdisc(struct nl_object *obj)
{
return (struct rtnl_qdisc *) obj;
}
struct rtnl_tc *obj2tc(struct nl_object *obj)
{
return TC_CAST(obj);
}
%};
extern struct rtnl_qdisc *
rtnl_qdisc_alloc(void);
extern struct rtnl_qdisc *
rtnl_qdisc_get(struct nl_cache *, int, uint32_t);
extern struct rtnl_qdisc *
rtnl_qdisc_get_by_parent(struct nl_cache *, int, uint32_t);
extern int rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int,
struct nl_msg **);
extern int rtnl_qdisc_add(struct nl_sock *, struct rtnl_qdisc *, int);
extern int rtnl_qdisc_build_update_request(struct rtnl_qdisc *,
struct rtnl_qdisc *,
int, struct nl_msg **);
extern int rtnl_qdisc_update(struct nl_sock *, struct rtnl_qdisc *,
struct rtnl_qdisc *, int);
extern int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *,
struct nl_msg **);
extern int rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *);
/* <netlink/route/addr.h> */
%inline %{
struct nl_object *addr2obj(struct rtnl_addr *addr)
{
return OBJ_CAST(addr);
}
struct rtnl_addr *obj2addr(struct nl_object *obj)
{
return (struct rtnl_addr *) obj;
}
%};
extern struct rtnl_addr *rtnl_addr_alloc(void);
extern struct rtnl_addr *
rtnl_addr_get(struct nl_cache *, int, struct nl_addr *);
extern int rtnl_addr_build_add_request(struct rtnl_addr *, int,
struct nl_msg **);
extern int rtnl_addr_add(struct nl_sock *, struct rtnl_addr *, int);
extern int rtnl_addr_build_delete_request(struct rtnl_addr *, int,
struct nl_msg **);
extern int rtnl_addr_delete(struct nl_sock *,
struct rtnl_addr *, int);
%cstring_output_maxsize(char *buf, size_t len)
extern char * rtnl_addr_flags2str(int, char *buf, size_t len);
extern int rtnl_addr_str2flags(const char *);
extern int rtnl_addr_set_label(struct rtnl_addr *, const char *);
extern char * rtnl_addr_get_label(struct rtnl_addr *);
extern void rtnl_addr_set_ifindex(struct rtnl_addr *, int);
extern int rtnl_addr_get_ifindex(struct rtnl_addr *);
extern void rtnl_addr_set_link(struct rtnl_addr *, struct rtnl_link *);
extern struct rtnl_link *
rtnl_addr_get_link(struct rtnl_addr *);
extern void rtnl_addr_set_family(struct rtnl_addr *, int);
extern int rtnl_addr_get_family(struct rtnl_addr *);
extern void rtnl_addr_set_prefixlen(struct rtnl_addr *, int);
extern int rtnl_addr_get_prefixlen(struct rtnl_addr *);
extern void rtnl_addr_set_scope(struct rtnl_addr *, int);
extern int rtnl_addr_get_scope(struct rtnl_addr *);
extern void rtnl_addr_set_flags(struct rtnl_addr *, unsigned int);
extern void rtnl_addr_unset_flags(struct rtnl_addr *, unsigned int);
extern unsigned int rtnl_addr_get_flags(struct rtnl_addr *);
extern int rtnl_addr_set_local(struct rtnl_addr *,
struct nl_addr *);
extern struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *);
extern int rtnl_addr_set_peer(struct rtnl_addr *, struct nl_addr *);
extern struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *);
extern int rtnl_addr_set_broadcast(struct rtnl_addr *, struct nl_addr *);
extern struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *);
extern int rtnl_addr_set_multicast(struct rtnl_addr *, struct nl_addr *);
extern struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *);
extern int rtnl_addr_set_anycast(struct rtnl_addr *, struct nl_addr *);
extern struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *);
extern uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *);
extern void rtnl_addr_set_valid_lifetime(struct rtnl_addr *, uint32_t);
extern uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *);
extern void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *, uint32_t);
extern uint32_t rtnl_addr_get_create_time(struct rtnl_addr *);
extern uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *);

View File

@ -0,0 +1,596 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""Module providing access to network links
This module provides an interface to view configured network links,
modify them and to add and delete virtual network links.
The following is a basic example:
import netlink.core as netlink
import netlink.route.link as link
sock = netlink.Socket()
sock.connect(netlink.NETLINK_ROUTE)
cache = link.LinkCache() # create new empty link cache
cache.refill(sock) # fill cache with all configured links
eth0 = cache['eth0'] # lookup link "eth0"
print eth0 # print basic configuration
The module contains the following public classes:
- Link -- Represents a network link. Instances can be created directly
via the constructor (empty link objects) or via the refill()
method of a LinkCache.
- LinkCache -- Derived from netlink.Cache, holds any number of
network links (Link instances). Main purpose is to keep
a local list of all network links configured in the
kernel.
The following public functions exist:
- get_from_kernel(socket, name)
"""
__version__ = "0.1"
__all__ = [
'LinkCache',
'Link',
'get_from_kernel']
import socket
import sys
import netlink.core as netlink
import netlink.capi as core_capi
import netlink.route.capi as capi
import netlink.route.links.inet as inet
import netlink.util as util
###########################################################################
# Link statistics definitions
RX_PACKETS = 0
TX_PACKETS = 1
RX_BYTES = 2
TX_BYTES = 3
RX_ERRORS = 4
TX_ERRORS = 5
RX_DROPPED = 6
TX_DROPPED = 7
RX_COMPRESSED = 8
TX_COMPRESSED = 9
RX_FIFO_ERR = 10
TX_FIFO_ERR = 11
RX_LEN_ERR = 12
RX_OVER_ERR = 13
RX_CRC_ERR = 14
RX_FRAME_ERR = 15
RX_MISSED_ERR = 16
TX_ABORT_ERR = 17
TX_CARRIER_ERR = 18
TX_HBEAT_ERR = 19
TX_WIN_ERR = 20
COLLISIONS = 21
MULTICAST = 22
IP6_INPKTS = 23
IP6_INHDRERRORS = 24
IP6_INTOOBIGERRORS = 25
IP6_INNOROUTES = 26
IP6_INADDRERRORS = 27
IP6_INUNKNOWNPROTOS = 28
IP6_INTRUNCATEDPKTS = 29
IP6_INDISCARDS = 30
IP6_INDELIVERS = 31
IP6_OUTFORWDATAGRAMS = 32
IP6_OUTPKTS = 33
IP6_OUTDISCARDS = 34
IP6_OUTNOROUTES = 35
IP6_REASMTIMEOUT = 36
IP6_REASMREQDS = 37
IP6_REASMOKS = 38
IP6_REASMFAILS = 39
IP6_FRAGOKS = 40
IP6_FRAGFAILS = 41
IP6_FRAGCREATES = 42
IP6_INMCASTPKTS = 43
IP6_OUTMCASTPKTS = 44
IP6_INBCASTPKTS = 45
IP6_OUTBCASTPKTS = 46
IP6_INOCTETS = 47
IP6_OUTOCTETS = 48
IP6_INMCASTOCTETS = 49
IP6_OUTMCASTOCTETS = 50
IP6_INBCASTOCTETS = 51
IP6_OUTBCASTOCTETS = 52
ICMP6_INMSGS = 53
ICMP6_INERRORS = 54
ICMP6_OUTMSGS = 55
ICMP6_OUTERRORS = 56
###########################################################################
# Link Cache
class LinkCache(netlink.Cache):
"""Cache of network links"""
def __init__(self, family=socket.AF_UNSPEC, cache=None):
if not cache:
cache = self._alloc_cache_name("route/link")
self._protocol = netlink.NETLINK_ROUTE
self._c_cache = cache
self._set_arg1(family)
def __getitem__(self, key):
if type(key) is int:
link = capi.rtnl_link_get(self._c_cache, key)
elif type(key) is str:
link = capi.rtnl_link_get_by_name(self._c_cache, key)
if link is None:
raise KeyError()
else:
return Link.from_capi(link)
def _new_object(self, obj):
return Link(obj)
def _new_cache(self, cache):
return LinkCache(family=self.arg1, cache=cache)
###########################################################################
# Link Object
class Link(netlink.Object):
"""Network link"""
def __init__(self, obj=None):
netlink.Object.__init__(self, "route/link", "link", obj)
self._rtnl_link = self._obj2type(self._nl_object)
self._type = None
if self.type:
self._type_lookup(self.type)
self.inet = inet.InetLink(self)
self.af = {'inet' : self.inet }
@classmethod
def from_capi(cls, obj):
return cls(capi.link2obj(obj))
def _obj2type(self, obj):
return capi.obj2link(obj)
def __cmp__(self, other):
return self.ifindex - other.ifindex
def _new_instance(self, obj):
if not obj:
raise ValueError()
return Link(obj)
def _type_lookup(self, name):
rname = 'netlink.route.links.' + name
tmp = __import__(rname)
mod = sys.modules[rname]
# this will create a type instance and assign it to
# link.<type>, e.g. link.vlan.id
self._type = mod.assign_type(self)
#####################################################################
# ifindex
@netlink.nlattr('link.ifindex', type=int, immutable=True, fmt=util.num)
@property
def ifindex(self):
"""interface index"""
return capi.rtnl_link_get_ifindex(self._rtnl_link)
@ifindex.setter
def ifindex(self, value):
capi.rtnl_link_set_ifindex(self._rtnl_link, int(value))
# ifindex is immutable but we assume that if _orig does not
# have an ifindex specified, it was meant to be given here
if capi.rtnl_link_get_ifindex(self._orig) == 0:
capi.rtnl_link_set_ifindex(self._orig, int(value))
#####################################################################
# name
@netlink.nlattr('link.name', type=str, fmt=util.bold)
@property
def name(self):
"""Name of link"""
return capi.rtnl_link_get_name(self._rtnl_link)
@name.setter
def name(self, value):
capi.rtnl_link_set_name(self._rtnl_link, value)
# name is the secondary identifier, if _orig does not have
# the name specified yet, assume it was meant to be specified
# here. ifindex will always take priority, therefore if ifindex
# is specified as well, this will be ignored automatically.
if capi.rtnl_link_get_name(self._orig) is None:
capi.rtnl_link_set_name(self._orig, value)
#####################################################################
# flags
@netlink.nlattr('link.flags', type=str, fmt=util.string)
@property
def flags(self):
"""Flags"""
flags = capi.rtnl_link_get_flags(self._rtnl_link)
return capi.rtnl_link_flags2str(flags, 256)[0].split(',')
def _set_flag(self, flag):
if flag[0] == '-':
i = capi.rtnl_link_str2flags(flag[1:])
capi.rtnl_link_unset_flags(self._rtnl_link, i)
else:
i = capi.rtnl_link_str2flags(flag[1:])
capi.rtnl_link_set_flags(self._rtnl_link, i)
@flags.setter
def flags(self, value):
if type(value) is list:
for flag in value:
self._set_flag(flag)
else:
self._set_flag(value)
#####################################################################
# mtu
@netlink.nlattr('link.mtu', type=int, fmt=util.num)
@property
def mtu(self):
"""Maximum Transmission Unit"""
return capi.rtnl_link_get_mtu(self._rtnl_link)
@mtu.setter
def mtu(self, value):
capi.rtnl_link_set_mtu(self._rtnl_link, int(value))
#####################################################################
# family
@netlink.nlattr('link.family', type=int, immutable=True, fmt=util.num)
@property
def family(self):
"""Address family"""
return capi.rtnl_link_get_family(self._rtnl_link)
@family.setter
def family(self, value):
capi.rtnl_link_set_family(self._rtnl_link, value)
#####################################################################
# address
@netlink.nlattr('link.address', type=str, fmt=util.addr)
@property
def address(self):
"""Hardware address (MAC address)"""
a = capi.rtnl_link_get_addr(self._rtnl_link)
return netlink.AbstractAddress(a)
@address.setter
def address(self, value):
capi.rtnl_link_set_addr(self._rtnl_link, value._addr)
#####################################################################
# broadcast
@netlink.nlattr('link.broadcast', type=str, fmt=util.addr)
@property
def broadcast(self):
"""Hardware broadcast address"""
a = capi.rtnl_link_get_broadcast(self._rtnl_link)
return netlink.AbstractAddress(a)
@broadcast.setter
def broadcast(self, value):
capi.rtnl_link_set_broadcast(self._rtnl_link, value._addr)
#####################################################################
# qdisc
@netlink.nlattr('link.qdisc', type=str, immutable=True, fmt=util.string)
@property
def qdisc(self):
"""Name of qdisc (cannot be changed)"""
return capi.rtnl_link_get_qdisc(self._rtnl_link)
@qdisc.setter
def qdisc(self, value):
capi.rtnl_link_set_qdisc(self._rtnl_link, value)
#####################################################################
# txqlen
@netlink.nlattr('link.txqlen', type=int, fmt=util.num)
@property
def txqlen(self):
""""Length of transmit queue"""
return capi.rtnl_link_get_txqlen(self._rtnl_link)
@txqlen.setter
def txqlen(self, value):
capi.rtnl_link_set_txqlen(self._rtnl_link, int(value))
#####################################################################
# weight
@netlink.nlattr('link.weight', type=str, fmt=util.string)
@property
def weight(self):
"""Weight"""
v = capi.rtnl_link_get_weight(self._rtnl_link)
if v == 4294967295:
return 'max'
else:
return str(v)
@weight.setter
def weight(self, value):
if value == 'max':
v = 4294967295
else:
v = int(value)
capi.rtnl_link_set_weight(self._rtnl_link, v)
#####################################################################
# arptype
@netlink.nlattr('link.arptype', type=str, immutable=True, fmt=util.string)
@property
def arptype(self):
"""Type of link (cannot be changed)"""
type = capi.rtnl_link_get_arptype(self._rtnl_link)
return core_capi.nl_llproto2str(type, 64)[0]
@arptype.setter
def arptype(self, value):
i = core_capi.nl_str2llproto(value)
capi.rtnl_link_set_arptype(self._rtnl_link, i)
#####################################################################
# operstate
@netlink.nlattr('link.operstate', type=str, immutable=True,
fmt=util.string, title='state')
@property
def operstate(self):
"""Operational status"""
operstate = capi.rtnl_link_get_operstate(self._rtnl_link)
return capi.rtnl_link_operstate2str(operstate, 32)[0]
@operstate.setter
def operstate(self, value):
i = capi.rtnl_link_str2operstate(flag)
capi.rtnl_link_set_operstate(self._rtnl_link, i)
#####################################################################
# mode
@netlink.nlattr('link.mode', type=str, immutable=True, fmt=util.string)
@property
def mode(self):
"""Link mode"""
mode = capi.rtnl_link_get_linkmode(self._rtnl_link)
return capi.rtnl_link_mode2str(mode, 32)[0]
@mode.setter
def mode(self, value):
i = capi.rtnl_link_str2mode(flag)
capi.rtnl_link_set_linkmode(self._rtnl_link, i)
#####################################################################
# alias
@netlink.nlattr('link.alias', type=str, fmt=util.string)
@property
def alias(self):
"""Interface alias (SNMP)"""
return capi.rtnl_link_get_ifalias(self._rtnl_link)
@alias.setter
def alias(self, value):
capi.rtnl_link_set_ifalias(self._rtnl_link, value)
#####################################################################
# type
@netlink.nlattr('link.type', type=str, fmt=util.string)
@property
def type(self):
"""Link type"""
return capi.rtnl_link_get_info_type(self._rtnl_link)
@type.setter
def type(self, value):
if capi.rtnl_link_set_info_type(self._rtnl_link, value) < 0:
raise NameError("unknown info type")
self._type_lookup(value)
#####################################################################
# get_stat()
def get_stat(self, stat):
"""Retrieve statistical information"""
if type(stat) is str:
stat = capi.rtnl_link_str2stat(stat)
if stat < 0:
raise NameError("unknown name of statistic")
return capi.rtnl_link_get_stat(self._rtnl_link, stat)
#####################################################################
# add()
def add(self, socket=None, flags=None):
if not socket:
socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
if not flags:
flags = netlink.NLM_F_CREATE
ret = capi.rtnl_link_add(socket._sock, self._rtnl_link, flags)
if ret < 0:
raise netlink.KernelError(ret)
#####################################################################
# change()
def change(self, socket=None, flags=0):
"""Commit changes made to the link object"""
if not socket:
socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
if not self._orig:
raise NetlinkError("Original link not available")
ret = capi.rtnl_link_change(socket._sock, self._orig, self._rtnl_link, flags)
if ret < 0:
raise netlink.KernelError(ret)
#####################################################################
# delete()
def delete(self, socket=None):
"""Attempt to delete this link in the kernel"""
if not socket:
socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
ret = capi.rtnl_link_delete(socket._sock, self._rtnl_link)
if ret < 0:
raise netlink.KernelError(ret)
###################################################################
# private properties
#
# Used for formatting output. USE AT OWN RISK
@property
def _state(self):
if 'up' in self.flags:
buf = util.good('up')
if 'lowerup' not in self.flags:
buf += ' ' + util.bad('no-carrier')
else:
buf = util.bad('down')
return buf
@property
def _brief(self):
buf = ''
if self.type:
if self._type and hasattr(self._type, 'brief'):
buf += self._type.brief()
else:
buf += util.yellow(self.type)
return buf + self._foreach_af('brief')
@property
def _flags(self):
ignore = ['up', 'running', 'lowerup']
return ','.join([flag for flag in self.flags if flag not in ignore])
def _foreach_af(self, name, args=None):
buf = ''
for af in self.af:
try:
func = getattr(self.af[af], name)
s = str(func(args))
if len(s) > 0:
buf += ' ' + s
except AttributeError:
pass
return buf
###################################################################
#
# format(details=False, stats=False)
#
def format(self, details=False, stats=False, indent=''):
"""Return link as formatted text"""
fmt = util.MyFormatter(self, indent)
buf = fmt.format('{a|ifindex} {a|name} {a|arptype} {a|address} '\
'{a|_state} <{a|_flags}> {a|_brief}')
if details:
buf += fmt.nl('\t{t|mtu} {t|txqlen} {t|weight} '\
'{t|qdisc} {t|operstate}')
buf += fmt.nl('\t{t|broadcast} {t|alias}')
buf += self._foreach_af('details', fmt)
if stats:
l = [['Packets', RX_PACKETS, TX_PACKETS],
['Bytes', RX_BYTES, TX_BYTES],
['Errors', RX_ERRORS, TX_ERRORS],
['Dropped', RX_DROPPED, TX_DROPPED],
['Compressed', RX_COMPRESSED, TX_COMPRESSED],
['FIFO Errors', RX_FIFO_ERR, TX_FIFO_ERR],
['Length Errors', RX_LEN_ERR, None],
['Over Errors', RX_OVER_ERR, None],
['CRC Errors', RX_CRC_ERR, None],
['Frame Errors', RX_FRAME_ERR, None],
['Missed Errors', RX_MISSED_ERR, None],
['Abort Errors', None, TX_ABORT_ERR],
['Carrier Errors', None, TX_CARRIER_ERR],
['Heartbeat Errors', None, TX_HBEAT_ERR],
['Window Errors', None, TX_WIN_ERR],
['Collisions', None, COLLISIONS],
['Multicast', None, MULTICAST],
['', None, None],
['Ipv6:', None, None],
['Packets', IP6_INPKTS, IP6_OUTPKTS],
['Bytes', IP6_INOCTETS, IP6_OUTOCTETS],
['Discards', IP6_INDISCARDS, IP6_OUTDISCARDS],
['Multicast Packets', IP6_INMCASTPKTS, IP6_OUTMCASTPKTS],
['Multicast Bytes', IP6_INMCASTOCTETS, IP6_OUTMCASTOCTETS],
['Broadcast Packets', IP6_INBCASTPKTS, IP6_OUTBCASTPKTS],
['Broadcast Bytes', IP6_INBCASTOCTETS, IP6_OUTBCASTOCTETS],
['Delivers', IP6_INDELIVERS, None],
['Forwarded', None, IP6_OUTFORWDATAGRAMS],
['No Routes', IP6_INNOROUTES, IP6_OUTNOROUTES],
['Header Errors', IP6_INHDRERRORS, None],
['Too Big Errors', IP6_INTOOBIGERRORS, None],
['Address Errors', IP6_INADDRERRORS, None],
['Unknown Protocol', IP6_INUNKNOWNPROTOS, None],
['Truncated Packets', IP6_INTRUNCATEDPKTS, None],
['Reasm Timeouts', IP6_REASMTIMEOUT, None],
['Reasm Requests', IP6_REASMREQDS, None],
['Reasm Failures', IP6_REASMFAILS, None],
['Reasm OK', IP6_REASMOKS, None],
['Frag Created', None, IP6_FRAGCREATES],
['Frag Failures', None, IP6_FRAGFAILS],
['Frag OK', None, IP6_FRAGOKS],
['', None, None],
['ICMPv6:', None, None],
['Messages', ICMP6_INMSGS, ICMP6_OUTMSGS],
['Errors', ICMP6_INERRORS, ICMP6_OUTERRORS]]
buf += '\n\t%s%s%s%s\n' % (33 * ' ', util.title('RX'),
15 * ' ', util.title('TX'))
for row in l:
row[0] = util.kw(row[0])
row[1] = self.get_stat(row[1]) if row[1] else ''
row[2] = self.get_stat(row[2]) if row[2] else ''
buf += '\t{0:27} {1:>16} {2:>16}\n'.format(*row)
buf += self._foreach_af('stats')
return buf
def get(name, socket=None):
"""Lookup Link object directly from kernel"""
if not name:
raise ValueError()
if not socket:
socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
link = capi.get_from_kernel(socket._sock, 0, name)
if not link:
return None
return Link.from_capi(link)
link_cache = LinkCache()
def resolve(name):
socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
link_cache.refill()
return link_cache[name]

View File

View File

@ -0,0 +1,21 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""Dummy
"""
__version__ = "1.0"
__all__ = ['assign_type']
import netlink.core as netlink
import netlink.route.capi as capi
class DummyLink(object):
def __init__(self, link):
self._rtnl_link = link
def assign_type(link):
link.dummy = DummyLink(link._rtnl_link)
return link.dummy

View File

@ -0,0 +1,153 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""IPv4
"""
__all__ = ['']
import netlink.core as netlink
import netlink.route.capi as capi
import netlink.util as util
DEVCONF_FORWARDING = 1
DEVCONF_MC_FORWARDING = 2
DEVCONF_PROXY_ARP = 3
DEVCONF_ACCEPT_REDIRECTS = 4
DEVCONF_SECURE_REDIRECTS = 5
DEVCONF_SEND_REDIRECTS = 6
DEVCONF_SHARED_MEDIA = 7
DEVCONF_RP_FILTER = 8
DEVCONF_ACCEPT_SOURCE_ROUTE = 9
DEVCONF_BOOTP_RELAY = 10
DEVCONF_LOG_MARTIANS = 11
DEVCONF_TAG = 12
DEVCONF_ARPFILTER = 13
DEVCONF_MEDIUM_ID = 14
DEVCONF_NOXFRM = 15
DEVCONF_NOPOLICY = 16
DEVCONF_FORCE_IGMP_VERSION = 17
DEVCONF_ARP_ANNOUNCE = 18
DEVCONF_ARP_IGNORE = 19
DEVCONF_PROMOTE_SECONDARIES = 20
DEVCONF_ARP_ACCEPT = 21
DEVCONF_ARP_NOTIFY = 22
DEVCONF_ACCEPT_LOCAL = 23
DEVCONF_SRC_VMARK = 24
DEVCONF_PROXY_ARP_PVLAN = 25
DEVCONF_MAX = DEVCONF_PROXY_ARP_PVLAN
def _resolve(id):
if type(id) is str:
id = capi.rtnl_link_inet_str2devconf(id)[0]
if id < 0:
raise NameError("unknown configuration id")
return id
class InetLink(object):
def __init__(self, link):
self._link = link
def details(self, fmt):
buf = '\n' + fmt.nl('\t%s\n\t' % util.title('Configuration:'))
for i in range(DEVCONF_FORWARDING,DEVCONF_MAX+1):
if i & 1 and i > 1:
buf += fmt.nl('\t')
txt = util.kw(capi.rtnl_link_inet_devconf2str(i, 32)[0])
buf += fmt.format('{0:28s} {1:12} ', txt,
self.get_conf(i))
return buf
def get_conf(self, id):
return capi.inet_get_conf(self._link._rtnl_link, _resolve(id))
def set_conf(self, id, value):
return capi.rtnl_link_inet_set_conf(self._link._rtnl_link,
_resolve(id), int(value))
@netlink.nlattr('link.inet.forwarding', type=bool, fmt=util.bool)
@property
def forwarding(self):
return bool(self.get_conf(DEVCONF_FORWARDING))
@forwarding.setter
def forwarding(self, value):
self.set_conf(DEVCONF_FORWARDING, int(value))
@netlink.nlattr('link.inet.mc_forwarding', type=bool, fmt=util.bool)
@property
def mc_forwarding(self):
return bool(self.get_conf(DEVCONF_MC_FORWARDING))
@mc_forwarding.setter
def mc_forwarding(self, value):
self.set_conf(DEVCONF_MC_FORWARDING, int(value))
@netlink.nlattr('link.inet.proxy_arp', type=bool, fmt=util.bool)
@property
def proxy_arp(self):
return bool(self.get_conf(DEVCONF_PROXY_ARP))
@proxy_arp.setter
def proxy_arp(self, value):
self.set_conf(DEVCONF_PROXY_ARP, int(value))
@netlink.nlattr('link.inet.accept_redirects', type=bool, fmt=util.bool)
@property
def accept_redirects(self):
return bool(self.get_conf(DEVCONF_ACCEPT_REDIRECTS))
@accept_redirects.setter
def accept_redirects(self, value):
self.set_conf(DEVCONF_ACCEPT_REDIRECTS, int(value))
@netlink.nlattr('link.inet.secure_redirects', type=bool, fmt=util.bool)
@property
def secure_redirects(self):
return bool(self.get_conf(DEVCONF_SECURE_REDIRECTS))
@secure_redirects.setter
def secure_redirects(self, value):
self.set_conf(DEVCONF_SECURE_REDIRECTS, int(value))
@netlink.nlattr('link.inet.send_redirects', type=bool, fmt=util.bool)
@property
def send_redirects(self):
return bool(self.get_conf(DEVCONF_SEND_REDIRECTS))
@send_redirects.setter
def send_redirects(self, value):
self.set_conf(DEVCONF_SEND_REDIRECTS, int(value))
@netlink.nlattr('link.inet.shared_media', type=bool, fmt=util.bool)
@property
def shared_media(self):
return bool(self.get_conf(DEVCONF_SHARED_MEDIA))
@shared_media.setter
def shared_media(self, value):
self.set_conf(DEVCONF_SHARED_MEDIA, int(value))
# IPV4_DEVCONF_RP_FILTER,
# IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
# IPV4_DEVCONF_BOOTP_RELAY,
# IPV4_DEVCONF_LOG_MARTIANS,
# IPV4_DEVCONF_TAG,
# IPV4_DEVCONF_ARPFILTER,
# IPV4_DEVCONF_MEDIUM_ID,
# IPV4_DEVCONF_NOXFRM,
# IPV4_DEVCONF_NOPOLICY,
# IPV4_DEVCONF_FORCE_IGMP_VERSION,
# IPV4_DEVCONF_ARP_ANNOUNCE,
# IPV4_DEVCONF_ARP_IGNORE,
# IPV4_DEVCONF_PROMOTE_SECONDARIES,
# IPV4_DEVCONF_ARP_ACCEPT,
# IPV4_DEVCONF_ARP_NOTIFY,
# IPV4_DEVCONF_ACCEPT_LOCAL,
# IPV4_DEVCONF_SRC_VMARK,
# IPV4_DEVCONF_PROXY_ARP_PVLAN,

View File

@ -0,0 +1,62 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""VLAN network link
"""
import netlink.core as netlink
import netlink.route.capi as capi
class VLANLink(object):
def __init__(self, link):
self._link = link
###################################################################
# id
@netlink.nlattr('link.vlan.id', type=int)
@property
def id(self):
"""vlan identifier"""
return capi.rtnl_link_vlan_get_id(self._link)
@id.setter
def id(self, value):
capi.rtnl_link_vlan_set_id(self._link, int(value))
###################################################################
# flags
@netlink.nlattr('link.vlan.flags', type=str)
@property
def flags(self):
"""vlan flags"""
flags = capi.rtnl_link_vlan_get_flags(self._link)
return capi.rtnl_link_vlan_flags2str(flags, 256)[0].split(',')
def _set_flag(self, flag):
i = capi.rtnl_link_vlan_str2flags(flag[1:])
if flag[0] == '-':
capi.rtnl_link_vlan_unset_flags(self._link, i)
else:
capi.rtnl_link_vlan_set_flags(self._link, i)
@flags.setter
def flags(self, value):
if type(value) is list:
for flag in value:
self._set_flag(flag)
else:
self._set_flag(value)
###################################################################
# TODO:
# - ingress map
# - egress map
def brief(self):
return 'vlan-id ' + self.id
def assign_type(link):
link.vlan = VLANLink(link._link)
return link.vlan

View File

@ -0,0 +1,185 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
__all__ = [
'QdiscCache',
'Qdisc']
import netlink.core as netlink
import netlink.capi as core_capi
import netlink.route.capi as capi
import netlink.util as util
import netlink.route.tc as tc
###########################################################################
# Link Cache
class QdiscCache(netlink.Cache):
"""Cache of qdiscs"""
def __init__(self, cache=None):
if not cache:
cache = self._alloc_cache_name("route/qdisc")
self._protocol = netlink.NETLINK_ROUTE
self._c_cache = cache
# def __getitem__(self, key):
# if type(key) is int:
# link = capi.rtnl_link_get(self._this, key)
# elif type(key) is str:
# link = capi.rtnl_link_get_by_name(self._this, key)
#
# if qdisc is None:
# raise KeyError()
# else:
# return Qdisc._from_capi(capi.qdisc2obj(qdisc))
def _new_object(self, obj):
return Qdisc(obj)
def _new_cache(self, cache):
return QdiscCache(cache=cache)
###########################################################################
# Qdisc Object
class Qdisc(tc.Tc):
"""Network link"""
def __init__(self, obj=None):
self._name = "qdisc"
self._abbr = "qdisc"
netlink.Object.__init__(self, "route/qdisc", "qdisc", obj)
self._tc = capi.obj2tc(self._nl_object)
self._rtnl_qdisc = self._obj2type(self._nl_object)
netlink.attr('qdisc.handle', fmt=util.handle)
netlink.attr('qdisc.parent', fmt=util.handle)
netlink.attr('qdisc.kind', fmt=util.bold)
def _obj2type(self, obj):
return capi.obj2qdisc(obj)
def __cmp__(self, other):
return self.handle - other.handle
def _new_instance(self, obj):
if not obj:
raise ValueError()
return Qdisc(obj)
# #####################################################################
# # add()
# def add(self, socket, flags=None):
# if not flags:
# flags = netlink.NLM_F_CREATE
#
# ret = capi.rtnl_link_add(socket._sock, self._link, flags)
# if ret < 0:
# raise netlink.KernelError(ret)
#
# #####################################################################
# # change()
# def change(self, socket, flags=0):
# """Commit changes made to the link object"""
# if not self._orig:
# raise NetlinkError("Original link not available")
# ret = capi.rtnl_link_change(socket._sock, self._orig, self._link, flags)
# if ret < 0:
# raise netlink.KernelError(ret)
#
# #####################################################################
# # delete()
# def delete(self, socket):
# """Attempt to delete this link in the kernel"""
# ret = capi.rtnl_link_delete(socket._sock, self._link)
# if ret < 0:
# raise netlink.KernelError(ret)
@property
def _dev(self):
buf = util.kw('dev') + ' '
if self.link:
return buf + util.string(self.link.name)
else:
return buf + util.num(self.ifindex)
@property
def _parent(self):
return util.kw('parent') + ' ' + str(self.parent)
###################################################################
#
# format(details=False, stats=False)
#
def format(self, details=False, stats=False):
"""Return qdisc as formatted text"""
fmt = util.MyFormatter(self)
buf = fmt.format('qdisc {kind} {handle} {_dev} {_parent}')
if details:
fmt = util.MyFormatter(self)
buf += fmt.format('\n'\
'\t{mtu} {mpu} {overhead}\n')
# if stats:
# l = [['Packets', RX_PACKETS, TX_PACKETS],
# ['Bytes', RX_BYTES, TX_BYTES],
# ['Errors', RX_ERRORS, TX_ERRORS],
# ['Dropped', RX_DROPPED, TX_DROPPED],
# ['Compressed', RX_COMPRESSED, TX_COMPRESSED],
# ['FIFO Errors', RX_FIFO_ERR, TX_FIFO_ERR],
# ['Length Errors', RX_LEN_ERR, None],
# ['Over Errors', RX_OVER_ERR, None],
# ['CRC Errors', RX_CRC_ERR, None],
# ['Frame Errors', RX_FRAME_ERR, None],
# ['Missed Errors', RX_MISSED_ERR, None],
# ['Abort Errors', None, TX_ABORT_ERR],
# ['Carrier Errors', None, TX_CARRIER_ERR],
# ['Heartbeat Errors', None, TX_HBEAT_ERR],
# ['Window Errors', None, TX_WIN_ERR],
# ['Collisions', None, COLLISIONS],
# ['Multicast', None, MULTICAST],
# ['', None, None],
# ['Ipv6:', None, None],
# ['Packets', IP6_INPKTS, IP6_OUTPKTS],
# ['Bytes', IP6_INOCTETS, IP6_OUTOCTETS],
# ['Discards', IP6_INDISCARDS, IP6_OUTDISCARDS],
# ['Multicast Packets', IP6_INMCASTPKTS, IP6_OUTMCASTPKTS],
# ['Multicast Bytes', IP6_INMCASTOCTETS, IP6_OUTMCASTOCTETS],
# ['Broadcast Packets', IP6_INBCASTPKTS, IP6_OUTBCASTPKTS],
# ['Broadcast Bytes', IP6_INBCASTOCTETS, IP6_OUTBCASTOCTETS],
# ['Delivers', IP6_INDELIVERS, None],
# ['Forwarded', None, IP6_OUTFORWDATAGRAMS],
# ['No Routes', IP6_INNOROUTES, IP6_OUTNOROUTES],
# ['Header Errors', IP6_INHDRERRORS, None],
# ['Too Big Errors', IP6_INTOOBIGERRORS, None],
# ['Address Errors', IP6_INADDRERRORS, None],
# ['Unknown Protocol', IP6_INUNKNOWNPROTOS, None],
# ['Truncated Packets', IP6_INTRUNCATEDPKTS, None],
# ['Reasm Timeouts', IP6_REASMTIMEOUT, None],
# ['Reasm Requests', IP6_REASMREQDS, None],
# ['Reasm Failures', IP6_REASMFAILS, None],
# ['Reasm OK', IP6_REASMOKS, None],
# ['Frag Created', None, IP6_FRAGCREATES],
# ['Frag Failures', None, IP6_FRAGFAILS],
# ['Frag OK', None, IP6_FRAGOKS],
# ['', None, None],
# ['ICMPv6:', None, None],
# ['Messages', ICMP6_INMSGS, ICMP6_OUTMSGS],
# ['Errors', ICMP6_INERRORS, ICMP6_OUTERRORS]]
#
# buf += '\n\t%s%s%s%s\n' % (33 * ' ', util.title('RX'),
# 15 * ' ', util.title('TX'))
#
# for row in l:
# row[0] = util.kw(row[0])
# row[1] = self.get_stat(row[1]) if row[1] else ''
# row[2] = self.get_stat(row[2]) if row[2] else ''
# buf += '\t{0:27} {1:>16} {2:>16}\n'.format(*row)
return buf

357
python/netlink/route/tc.py Normal file
View File

@ -0,0 +1,357 @@
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
__all__ = [
'TcCache',
'Tc',
'QdiscCache',
'Qdisc']
import socket
import sys
import netlink.core as netlink
import netlink.capi as core_capi
import netlink.route.capi as capi
import netlink.util as util
from netlink.route.link import Link
TC_PACKETS = 0
TC_BYTES = 1
TC_RATE_BPS = 2
TC_RATE_PPS = 3
TC_QLEN = 4
TC_BACKLOG = 5
TC_DROPS = 6
TC_REQUEUES = 7
TC_OVERLIMITS = 9
TC_H_ROOT = 0xFFFFFFFF
TC_H_INGRESS = 0xFFFFFFF1
class Handle(object):
def __init__(self, val=None):
if type(val) is str:
val = capi.tc_str2handle(val)
elif not val:
val = 0
self._val = int(val)
def __int__(self):
return self._val
def __str__(self):
return capi.rtnl_tc_handle2str(self._val, 64)[0]
def isroot(self):
return self._val == TC_H_ROOT or self._val == TC_H_INGRESS
###########################################################################
# TC Cache
class TcCache(netlink.Cache):
"""Cache of traffic control object"""
def __getitem__(self, key):
raise NotImplementedError()
###########################################################################
# Tc Object
class Tc(netlink.Object):
def __cmp__(self, other):
return self.ifindex - other.ifindex
def isroot(self):
return self.parent.isroot()
#####################################################################
# ifindex
@property
def ifindex(self):
"""interface index"""
return capi.rtnl_tc_get_ifindex(self._tc)
@ifindex.setter
def ifindex(self, value):
capi.rtnl_tc_set_ifindex(self._tc, int(value))
#####################################################################
# link
@property
def link(self):
link = capi.rtnl_tc_get_link(self._tc)
if not link:
return None
else:
return Link._from_capi(link)
@link.setter
def link(self, value):
capi.rtnl_tc_set_link(self._tc, value._link)
#####################################################################
# mtu
@property
def mtu(self):
return capi.rtnl_tc_get_mtu(self._tc)
@mtu.setter
def mtu(self, value):
capi.rtnl_tc_set_mtu(self._tc, int(value))
#####################################################################
# mpu
@property
def mpu(self):
return capi.rtnl_tc_get_mpu(self._tc)
@mpu.setter
def mpu(self, value):
capi.rtnl_tc_set_mpu(self._tc, int(value))
#####################################################################
# overhead
@property
def overhead(self):
return capi.rtnl_tc_get_overhead(self._tc)
@overhead.setter
def overhead(self, value):
capi.rtnl_tc_set_overhead(self._tc, int(value))
#####################################################################
# linktype
@property
def linktype(self):
return capi.rtnl_tc_get_linktype(self._tc)
@linktype.setter
def linktype(self, value):
capi.rtnl_tc_set_linktype(self._tc, int(value))
#####################################################################
# handle
@property
def handle(self):
return Handle(capi.rtnl_tc_get_handle(self._tc))
@handle.setter
def handle(self, value):
capi.rtnl_tc_set_handle(self._tc, int(value))
#####################################################################
# parent
@property
def parent(self):
return Handle(capi.rtnl_tc_get_parent(self._tc))
@parent.setter
def parent(self, value):
capi.rtnl_tc_set_parent(self._tc, int(value))
#####################################################################
# kind
@property
def kind(self):
return capi.rtnl_tc_get_kind(self._tc)
@kind.setter
def kind(self, value):
capi.rtnl_tc_set_kind(self._tc, value)
def get_stat(self, id):
return capi.rtnl_tc_get_stat(self._tc, id)
class TcTree(object):
def __init__(self, link, sock):
self._qdisc_cache = QdiscCache().refill(sock)
def __getitem__(self, key):
pass
# if type(key) is int:
# link = capi.rtnl_link_get(self._this, key)
# elif type(key) is str:
# link = capi.rtnl_link_get_by_name(self._this, key)
#
# if qdisc is None:
# raise KeyError()
# else:
# return Qdisc._from_capi(capi.qdisc2obj(qdisc))
###########################################################################
# Link Cache
class QdiscCache(netlink.Cache):
"""Cache of qdiscs"""
def __init__(self, cache=None):
if not cache:
cache = self._alloc_cache_name("route/qdisc")
self._c_cache = cache
# def __getitem__(self, key):
# if type(key) is int:
# link = capi.rtnl_link_get(self._this, key)
# elif type(key) is str:
# link = capi.rtnl_link_get_by_name(self._this, key)
#
# if qdisc is None:
# raise KeyError()
# else:
# return Qdisc._from_capi(capi.qdisc2obj(qdisc))
def _new_object(self, obj):
return Qdisc(obj)
def _new_cache(self, cache):
return QdiscCache(cache=cache)
###########################################################################
# Qdisc Object
class Qdisc(Tc):
"""Network link"""
def __init__(self, obj=None):
self._name = "qdisc"
self._abbr = "qdisc"
if not obj:
self._qdisc = capi.rtnl_qdisc_alloc()
else:
self._qdisc = capi.obj2qdisc(obj)
self._obj = capi.qdisc2obj(self._qdisc)
self._orig = capi.obj2qdisc(core_capi.nl_object_clone(self._obj))
Tc.__init__(self)
netlink.attr('qdisc.handle', fmt=util.handle)
netlink.attr('qdisc.parent', fmt=util.handle)
netlink.attr('qdisc.kind', fmt=util.bold)
def __cmp__(self, other):
return self.handle - other.handle
def _new_instance(self, obj):
if not obj: raise ValueError()
return Qdisc(obj)
# #####################################################################
# # add()
# def add(self, socket, flags=None):
# if not flags:
# flags = netlink.NLM_F_CREATE
#
# ret = capi.rtnl_link_add(socket._sock, self._link, flags)
# if ret < 0:
# raise netlink.KernelError(ret)
#
# #####################################################################
# # change()
# def change(self, socket, flags=0):
# """Commit changes made to the link object"""
# if not self._orig:
# raise NetlinkError("Original link not available")
# ret = capi.rtnl_link_change(socket._sock, self._orig, self._link, flags)
# if ret < 0:
# raise netlink.KernelError(ret)
#
# #####################################################################
# # delete()
# def delete(self, socket):
# """Attempt to delete this link in the kernel"""
# ret = capi.rtnl_link_delete(socket._sock, self._link)
# if ret < 0:
# raise netlink.KernelError(ret)
@property
def _dev(self):
buf = util.kw('dev') + ' '
if self.link:
return buf + util.string(self.link.name)
else:
return buf + util.num(self.ifindex)
@property
def _parent(self):
return util.kw('parent') + ' ' + str(self.parent)
###################################################################
#
# format(details=False, stats=False)
#
def format(self, details=False, stats=False):
"""Return qdisc as formatted text"""
fmt = util.BriefFormatter(self)
buf = fmt.format('qdisc {kind} {handle} {_dev} {_parent}')
if details:
fmt = util.DetailFormatter(self)
buf += fmt.format('\n'\
'\t{mtu} {mpu} {overhead}\n')
# if stats:
# l = [['Packets', RX_PACKETS, TX_PACKETS],
# ['Bytes', RX_BYTES, TX_BYTES],
# ['Errors', RX_ERRORS, TX_ERRORS],
# ['Dropped', RX_DROPPED, TX_DROPPED],
# ['Compressed', RX_COMPRESSED, TX_COMPRESSED],
# ['FIFO Errors', RX_FIFO_ERR, TX_FIFO_ERR],
# ['Length Errors', RX_LEN_ERR, None],
# ['Over Errors', RX_OVER_ERR, None],
# ['CRC Errors', RX_CRC_ERR, None],
# ['Frame Errors', RX_FRAME_ERR, None],
# ['Missed Errors', RX_MISSED_ERR, None],
# ['Abort Errors', None, TX_ABORT_ERR],
# ['Carrier Errors', None, TX_CARRIER_ERR],
# ['Heartbeat Errors', None, TX_HBEAT_ERR],
# ['Window Errors', None, TX_WIN_ERR],
# ['Collisions', None, COLLISIONS],
# ['Multicast', None, MULTICAST],
# ['', None, None],
# ['Ipv6:', None, None],
# ['Packets', IP6_INPKTS, IP6_OUTPKTS],
# ['Bytes', IP6_INOCTETS, IP6_OUTOCTETS],
# ['Discards', IP6_INDISCARDS, IP6_OUTDISCARDS],
# ['Multicast Packets', IP6_INMCASTPKTS, IP6_OUTMCASTPKTS],
# ['Multicast Bytes', IP6_INMCASTOCTETS, IP6_OUTMCASTOCTETS],
# ['Broadcast Packets', IP6_INBCASTPKTS, IP6_OUTBCASTPKTS],
# ['Broadcast Bytes', IP6_INBCASTOCTETS, IP6_OUTBCASTOCTETS],
# ['Delivers', IP6_INDELIVERS, None],
# ['Forwarded', None, IP6_OUTFORWDATAGRAMS],
# ['No Routes', IP6_INNOROUTES, IP6_OUTNOROUTES],
# ['Header Errors', IP6_INHDRERRORS, None],
# ['Too Big Errors', IP6_INTOOBIGERRORS, None],
# ['Address Errors', IP6_INADDRERRORS, None],
# ['Unknown Protocol', IP6_INUNKNOWNPROTOS, None],
# ['Truncated Packets', IP6_INTRUNCATEDPKTS, None],
# ['Reasm Timeouts', IP6_REASMTIMEOUT, None],
# ['Reasm Requests', IP6_REASMREQDS, None],
# ['Reasm Failures', IP6_REASMFAILS, None],
# ['Reasm OK', IP6_REASMOKS, None],
# ['Frag Created', None, IP6_FRAGCREATES],
# ['Frag Failures', None, IP6_FRAGFAILS],
# ['Frag OK', None, IP6_FRAGOKS],
# ['', None, None],
# ['ICMPv6:', None, None],
# ['Messages', ICMP6_INMSGS, ICMP6_OUTMSGS],
# ['Errors', ICMP6_INERRORS, ICMP6_OUTERRORS]]
#
# buf += '\n\t%s%s%s%s\n' % (33 * ' ', util.title('RX'),
# 15 * ' ', util.title('TX'))
#
# for row in l:
# row[0] = util.kw(row[0])
# row[1] = self.get_stat(row[1]) if row[1] else ''
# row[2] = self.get_stat(row[2]) if row[2] else ''
# buf += '\t{0:27} {1:>16} {2:>16}\n'.format(*row)
return buf

146
python/netlink/util.py Normal file
View File

@ -0,0 +1,146 @@
#
# Utilities
#
# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
#
"""utility module for netlink
"""
import netlink.core as netlink
from string import Formatter
__version__ = "1.0"
def _color(t, c):
return chr(0x1b)+"["+str(c)+"m"+str(t)+chr(0x1b)+"[0m"
def black(t):
return _color(t, 30)
def red(t):
return _color(t, 31)
def green(t):
return _color(t, 32)
def yellow(t):
return _color(t, 33)
def blue(t):
return _color(t, 34)
def mangenta(t):
return _color(t, 35)
def cyan(t):
return _color(t, 36)
def white(t):
return _color(t, 37)
def bold(t):
return _color(t, 1)
def kw(t):
return yellow(t)
def num(t):
return str(t)
def string(t):
return t
def addr(t):
return str(t)
def bad(t):
return red(t)
def good(t):
return green(t)
def title(t):
return t
def bool(t):
return str(t)
def handle(t):
return str(t)
class MyFormatter(Formatter):
def __init__(self, obj, indent=''):
self._obj = obj
self._indent = indent
def _nlattr(self, key):
value = getattr(self._obj, key)
title = None
if type(value) == 'instancemethod':
value = value()
try:
d = netlink.attrs[self._obj._name + '.' + key]
if 'fmt' in d:
value = d['fmt'](value)
if 'title' in d:
title = d['title']
except KeyError:
pass
return title, str(value)
def get_value(self, key, args, kwds):
# Let default get_value() handle ints
if not isinstance(key, str):
return Formatter.get_value(self, key, args, kwds)
# HACK, we allow defining strings via fields to allow
# conversions
if key[:2] == 's|':
return key[2:]
if key[:2] == 't|':
# title mode ("TITLE ATTR")
include_title = True
elif key[:2] == 'a|':
# plain attribute mode ("ATTR")
include_title = False
else:
# No special field, have default get_value() get it
return Formatter.get_value(self, key, args, kwds)
key = key[2:]
(title, value) = self._nlattr(key)
if include_title:
if not title:
title = key # fall back to key as title
value = kw(title) + ' ' + value
return value
def convert_field(self, value, conversion):
if conversion == 'r':
return repr(value)
elif conversion == 's':
return str(value)
elif conversion == 'k':
return kw(value)
elif conversion == 'b':
return bold(value)
elif conversion is None:
return value
raise ValueError("Unknown converion specifier {0!s}".format(conversion))
def nl(self):
return '\n' + self._indent
def nl(self, format_string=''):
return '\n' + self._indent + self.format(format_string)

29
python/setup.py Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env python
from distutils.core import setup, Extension
opts = ['-O', '-nodefaultctor']
include = ['../include']
netlink_capi = Extension('netlink/_capi',
sources = ['netlink/capi.i'],
include_dirs = include,
swig_opts = opts,
libraries = ['nl'],
)
route_capi = Extension('netlink/route/_capi',
sources = ['netlink/route/capi.i'],
include_dirs = include,
swig_opts = opts,
libraries = ['nl', 'nl-route'],
)
setup(name = 'netlink',
version = '1.0',
description = 'Python wrapper for netlink protocols',
author = 'Thomas Graf',
author_email = 'tgraf@suug.ch',
ext_modules = [netlink_capi, route_capi],
packages = ['netlink', 'netlink.route', 'netlink.route.links'],
)