mirror of
https://gitee.com/openharmony/third_party_libnl
synced 2024-11-30 13:40:43 +00:00
python interface to netlink protocols
currently includes experimental support for links, addresses and some traffic control
This commit is contained in:
parent
023c662327
commit
f443be6e74
@ -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
135
m4/ax_pkg_swig.m4
Normal 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
325
m4/ax_python_devel.m4
Normal 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
64
m4/ax_swig_python.m4
Normal 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
216
python/doc/conf.py
Normal 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
215
python/doc/core.rst
Normal 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
24
python/doc/index.rst
Normal 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
3
python/doc/route.rst
Normal file
@ -0,0 +1,3 @@
|
||||
**********************
|
||||
Routing
|
||||
**********************
|
47
python/doc/route_addr.rst
Normal file
47
python/doc/route_addr.rst
Normal 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
|
0
python/netlink/__init__.py
Normal file
0
python/netlink/__init__.py
Normal file
457
python/netlink/capi.i
Normal file
457
python/netlink/capi.i
Normal 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
737
python/netlink/core.py
Normal 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
1
python/netlink/fixes.h
Normal file
@ -0,0 +1 @@
|
||||
#include <stdint.h>
|
0
python/netlink/route/__init__.py
Normal file
0
python/netlink/route/__init__.py
Normal file
398
python/netlink/route/address.py
Normal file
398
python/netlink/route/address.py
Normal 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
338
python/netlink/route/capi.i
Normal 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 *);
|
596
python/netlink/route/link.py
Normal file
596
python/netlink/route/link.py
Normal 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]
|
0
python/netlink/route/links/__init__.py
Normal file
0
python/netlink/route/links/__init__.py
Normal file
21
python/netlink/route/links/dummy.py
Normal file
21
python/netlink/route/links/dummy.py
Normal 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
|
153
python/netlink/route/links/inet.py
Normal file
153
python/netlink/route/links/inet.py
Normal 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,
|
62
python/netlink/route/links/vlan.py
Normal file
62
python/netlink/route/links/vlan.py
Normal 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
|
185
python/netlink/route/qdisc.py
Normal file
185
python/netlink/route/qdisc.py
Normal 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
357
python/netlink/route/tc.py
Normal 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
146
python/netlink/util.py
Normal 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
29
python/setup.py
Normal 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'],
|
||||
)
|
Loading…
Reference in New Issue
Block a user