diff options
author | JP Abgrall <jpa@google.com> | 2014-02-14 13:27:00 -0800 |
---|---|---|
committer | JP Abgrall <jpa@google.com> | 2014-02-14 13:27:00 -0800 |
commit | 823435f737de20d5ca9f4aa2ba0ae2950dbb5d4f (patch) | |
tree | e146cd87948eb11eb195d463b49dc8b1bdeb0db0 | |
parent | 0021213ea39d6a889b6ed6e24dc1c2142ae175bf (diff) | |
parent | 515d3af751f58f1645d09f0a750b759cdc7820c3 (diff) | |
download | android_external_libnl-823435f737de20d5ca9f4aa2ba0ae2950dbb5d4f.tar.gz android_external_libnl-823435f737de20d5ca9f4aa2ba0ae2950dbb5d4f.tar.bz2 android_external_libnl-823435f737de20d5ca9f4aa2ba0ae2950dbb5d4f.zip |
Merge remote-tracking branch 'upstream_linaro/linaro-libnl2_0'
* upstream_linaro/linaro-libnl2_0: (159 commits)
Updating group definition to follow 3.13 kernel
Adding version.h
Adding support for netlink API and quota in nfaccounting
Compile 2.0 with Kitkat
Don't include pktloc_syntax.h in BUILT_SOURCES
route_obj: don't add empty destination to nlmsg
automake: add ${top_builddir}/include to AM_CFLAGS
Use CPPFLAGS
Put preprocessor definitions in AM_CPPFLAGS
add user data to change_func_t for caches
Trivial fix for TBF memleak
libnl: optionally disable cli tools.
Ignore vim swap files
Let git ignore generated pktloc source files
Fix compile warning in utils.c
Fix compile warning in nl.c
Packet Location Interface
src/nf-queue.c: cleanup and improve performance of test program for NF_QUEUE
Don't install private header files.
object: fix attribute comparison
...
Conflicts:
Android.mk
include/linux/netfilter/nfnetlink.h
Change-Id: I383749ca16113b2ae8cfc7729aee8bbc8a36dc9e
241 files changed, 16414 insertions, 9794 deletions
@@ -1,9 +1,28 @@ -*.[od] -Makefile.opts -config.log -config.status -autom4te.cache -libnl-1.pc -configure -doc/Doxyfile -lib/defs.h +.deps +.libs +.dirstamp +*.in +*.la +*.lo +*.o +*.swp +Makefile +/lib/stamp-h1 + +/libnl-1.pc +/doc/Doxyfile +/lib/defs.h +cscope.* + +/aclocal.m4 +/autom4te.cache +/compile +/config.* +/configure +/depcomp +/libtool +/ltmain.sh +/install-sh +/missing + +/*.pc @@ -23,15 +23,12 @@ LOCAL_SRC_FILES := lib/cache.c \ lib/genl/genl.c \ lib/route/rtnl.c \ lib/route/route_utils.c \ - lib/netfilter/nfnl.c + lib/netfilter/nfnl.c \ + lib/error.c -#LOCAL_CFLAGS := LOCAL_C_INCLUDES := $(LOCAL_PATH)/include - #kernel/android-2.6.32/include LOCAL_MODULE_TAGS := eng LOCAL_MODULE := libnl include $(BUILD_SHARED_LIBRARY) -#include $(BUILD_STATIC_LIBRARY) - diff --git a/Makefile b/Makefile deleted file mode 100644 index 826b9a3..0000000 --- a/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# -# Makefile -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -ifeq ($(shell [ ! -r Makefile.opts ] && echo 1),) - include Makefile.opts -endif - -SUBDIRS := lib include doc src tests -.PHONY: all clean distclean install gendoc $(SUBDIRS) - -all: Makefile.opts - @for dir in $(SUBDIRS); do \ - echo "Entering $$dir" && $(MAKE) -C $$dir || exit $$?; \ - done - -clean: Makefile.opts - rm -f cscope.* - @for dir in $(SUBDIRS); do \ - echo "Entering $$dir" && $(MAKE) -C $$dir clean || exit $$?; \ - done - -distclean: clean - @$(RM) -rf Makefile.opts autom4te.cache config.log config.status - @for dir in $(SUBDIRS); do \ - echo "Entering $$dir" && $(MAKE) -C $$dir distclean || exit $$?; \ - done - -install: Makefile.opts - @for dir in $(SUBDIRS); do \ - echo "Entering $$dir" && cd $$dir && $(MAKE) install && cd ..; \ - done - mkdir -p $(DESTDIR)$(libdir)/pkgconfig/ - install -m 0644 libnl-1.pc $(DESTDIR)$(libdir)/pkgconfig/ - -gendoc: - $(MAKE) -C doc gendoc - -show: Makefile.opts - @echo "CC: $(CC)" - @echo "RM: $(RM)" - @echo "CFLAGS: $(CFLAGS)" - @echo "DEPFLAGS: $(DEPFLAGS)" - @echo "LDFLAGS: $(LDFLAGS)" - @echo "DESTDIR: $(DESTDIR)" - @echo "prefix: $(prefix)" - @echo "libdir: $(libdir)" - @echo "includedir: $(includedir)" - -cscope: - cscope -b -q -R -Iinclude -slib -ssrc - - -$(SUBDIRS): - cd $@ && $(MAKE) - --include Makefile.rules diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8f9438c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,20 @@ +# -*- Makefile -*- + +ACLOCAL_AMFLAGS = -I m4 + +OPT_DIRS = + +if ENABLE_CLI +OPT_DIRS += src +endif + +SUBDIRS = include lib doc $(OPT_DIRS) + +pkgconfig_DATA = libnl-2.0.pc + +sysconfdir = @sysconfdir@/libnl +sysconf_DATA = etc/pktloc + +.PHONY: cscope +cscope: + cscope -b -q -R -Iinclude -slib -ssrc; diff --git a/Makefile.opts.in b/Makefile.opts.in deleted file mode 100644 index 87d229b..0000000 --- a/Makefile.opts.in +++ /dev/null @@ -1,39 +0,0 @@ -# -# Makefile.opts.in -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -CC := @CC@ -CFLAGS := @CFLAGS@ -LDFLAGS := @LDFLAGS@ -CPPFLAGS := @CPPFLAGS@ -PACKAGE_NAME := @PACKAGE_NAME@ -PACKAGE_VERSION := @PACKAGE_VERSION@ - -LIBNL_LIB := @LIBNL_LIB@ - -prefix := @prefix@ -exec_prefix := @exec_prefix@ -libdir := @libdir@ -includedir := @includedir@ -mandir := @mandir@ -sysconfdir := @sysconfdir@ - -AR := ar -RM := rm -LN := ln - -DEPFLAGS += -M -I../include/ -I. $(CPPFLAGS) -CFLAGS += -g -I./include -I../include -I. $(CPPFLAGS) -D_GNU_SOURCE -MAKEFLAGS += --no-print-directory - -ifeq ($(CC),gcc) -CFLAGS += -Wall -ggdb -endif - diff --git a/Makefile.rules b/Makefile.rules deleted file mode 100644 index 5a1decf..0000000 --- a/Makefile.rules +++ /dev/null @@ -1,37 +0,0 @@ -# -# Makefile.rules -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -.SUFFIXES: -.SUFFIXES: .d .c - -%.o: %.c - @echo " CC $<"; \ - $(CC) $(CFLAGS) -c -o $@ $< - -%.d: %.c - @echo " DEP $<"; \ - $(CC) $(DEPFLAGS) $< > $@.tmp; \ - sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.tmp > $@; \ - rm -f $@.tmp - -Makefile.opts: - @echo "***" - @echo "*** No configuration found, please run ./configure" - @echo "***" - @exit 1 - -ifneq ($(MAKECMDGOALS),clean) -ifneq ($(MAKECMDGOALS),distclean) -ifneq ($(DEPS),) --include $(DEPS) -endif -endif -endif diff --git a/aclocal.m4 b/aclocal.m4 deleted file mode 100644 index 177c013..0000000 --- a/aclocal.m4 +++ /dev/null @@ -1,831 +0,0 @@ -dnl aclocal.m4 generated automatically by aclocal 1.4-p6 - -dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl This program is distributed in the hope that it will be useful, -dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without -dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A -dnl PARTICULAR PURPOSE. - -# lib-prefix.m4 serial 4 (gettext-0.14.2) -dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and -dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't -dnl require excessive bracketing. -ifdef([AC_HELP_STRING], -[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], -[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) - -dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed -dnl to access previously installed libraries. The basic assumption is that -dnl a user will want packages to use other packages he previously installed -dnl with the same --prefix option. -dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate -dnl libraries, but is otherwise very convenient. -AC_DEFUN([AC_LIB_PREFIX], -[ - AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) - AC_REQUIRE([AC_PROG_CC]) - AC_REQUIRE([AC_CANONICAL_HOST]) - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - dnl By default, look in $includedir and $libdir. - use_additional=yes - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - AC_LIB_ARG_WITH([lib-prefix], -[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib - --without-lib-prefix don't search for libraries in includedir and libdir], -[ - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - else - additional_includedir="$withval/include" - additional_libdir="$withval/lib" - fi - fi -]) - if test $use_additional = yes; then - dnl Potentially add $additional_includedir to $CPPFLAGS. - dnl But don't add it - dnl 1. if it's the standard /usr/include, - dnl 2. if it's already present in $CPPFLAGS, - dnl 3. if it's /usr/local/include and we are using GCC on Linux, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - for x in $CPPFLAGS; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - dnl Really add $additional_includedir to $CPPFLAGS. - CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" - fi - fi - fi - fi - dnl Potentially add $additional_libdir to $LDFLAGS. - dnl But don't add it - dnl 1. if it's the standard /usr/lib, - dnl 2. if it's already present in $LDFLAGS, - dnl 3. if it's /usr/local/lib and we are using GCC on Linux, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_libdir" != "X/usr/lib"; then - haveit= - for x in $LDFLAGS; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test "X$additional_libdir" = "X/usr/local/lib"; then - if test -n "$GCC"; then - case $host_os in - linux*) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LDFLAGS. - LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" - fi - fi - fi - fi - fi -]) - -dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, -dnl acl_final_exec_prefix, containing the values to which $prefix and -dnl $exec_prefix will expand at the end of the configure script. -AC_DEFUN([AC_LIB_PREPARE_PREFIX], -[ - dnl Unfortunately, prefix and exec_prefix get only finally determined - dnl at the end of configure. - if test "X$prefix" = "XNONE"; then - acl_final_prefix="$ac_default_prefix" - else - acl_final_prefix="$prefix" - fi - if test "X$exec_prefix" = "XNONE"; then - acl_final_exec_prefix='${prefix}' - else - acl_final_exec_prefix="$exec_prefix" - fi - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" - prefix="$acl_save_prefix" -]) - -dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the -dnl variables prefix and exec_prefix bound to the values they will have -dnl at the end of the configure script. -AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], -[ - acl_save_prefix="$prefix" - prefix="$acl_final_prefix" - acl_save_exec_prefix="$exec_prefix" - exec_prefix="$acl_final_exec_prefix" - $1 - exec_prefix="$acl_save_exec_prefix" - prefix="$acl_save_prefix" -]) - -# lib-link.m4 serial 6 (gettext-0.14.3) -dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl From Bruno Haible. - -AC_PREREQ(2.50) - -dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and -dnl the libraries corresponding to explicit and implicit dependencies. -dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and -dnl augments the CPPFLAGS variable. -AC_DEFUN([AC_LIB_LINKFLAGS], -[ - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - define([Name],[translit([$1],[./-], [___])]) - define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ - AC_LIB_LINKFLAGS_BODY([$1], [$2]) - ac_cv_lib[]Name[]_libs="$LIB[]NAME" - ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" - ac_cv_lib[]Name[]_cppflags="$INC[]NAME" - ]) - LIB[]NAME="$ac_cv_lib[]Name[]_libs" - LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" - INC[]NAME="$ac_cv_lib[]Name[]_cppflags" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) - AC_SUBST([LIB]NAME) - AC_SUBST([LTLIB]NAME) - dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the - dnl results of this search when this library appears as a dependency. - HAVE_LIB[]NAME=yes - undefine([Name]) - undefine([NAME]) -]) - -dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) -dnl searches for libname and the libraries corresponding to explicit and -dnl implicit dependencies, together with the specified include files and -dnl the ability to compile and link the specified testcode. If found, it -dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and -dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and -dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs -dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. -AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], -[ - AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) - AC_REQUIRE([AC_LIB_RPATH]) - define([Name],[translit([$1],[./-], [___])]) - define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - - dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME - dnl accordingly. - AC_LIB_LINKFLAGS_BODY([$1], [$2]) - - dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, - dnl because if the user has installed lib[]Name and not disabled its use - dnl via --without-lib[]Name-prefix, he wants to use it. - ac_save_CPPFLAGS="$CPPFLAGS" - AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) - - AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ - ac_save_LIBS="$LIBS" - LIBS="$LIBS $LIB[]NAME" - AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) - LIBS="$ac_save_LIBS" - ]) - if test "$ac_cv_lib[]Name" = yes; then - HAVE_LIB[]NAME=yes - AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) - AC_MSG_CHECKING([how to link with lib[]$1]) - AC_MSG_RESULT([$LIB[]NAME]) - else - HAVE_LIB[]NAME=no - dnl If $LIB[]NAME didn't lead to a usable library, we don't need - dnl $INC[]NAME either. - CPPFLAGS="$ac_save_CPPFLAGS" - LIB[]NAME= - LTLIB[]NAME= - fi - AC_SUBST([HAVE_LIB]NAME) - AC_SUBST([LIB]NAME) - AC_SUBST([LTLIB]NAME) - undefine([Name]) - undefine([NAME]) -]) - -dnl Determine the platform dependent parameters needed to use rpath: -dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, -dnl hardcode_direct, hardcode_minus_L. -AC_DEFUN([AC_LIB_RPATH], -[ - dnl Tell automake >= 1.10 to complain if config.rpath is missing. - m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) - AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS - AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld - AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host - AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir - AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ - CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ - ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh - . ./conftest.sh - rm -f ./conftest.sh - acl_cv_rpath=done - ]) - wl="$acl_cv_wl" - libext="$acl_cv_libext" - shlibext="$acl_cv_shlibext" - hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" - hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" - hardcode_direct="$acl_cv_hardcode_direct" - hardcode_minus_L="$acl_cv_hardcode_minus_L" - dnl Determine whether the user wants rpath handling at all. - AC_ARG_ENABLE(rpath, - [ --disable-rpath do not hardcode runtime library paths], - :, enable_rpath=yes) -]) - -dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and -dnl the libraries corresponding to explicit and implicit dependencies. -dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. -AC_DEFUN([AC_LIB_LINKFLAGS_BODY], -[ - define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], - [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) - dnl By default, look in $includedir and $libdir. - use_additional=yes - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - AC_LIB_ARG_WITH([lib$1-prefix], -[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib - --without-lib$1-prefix don't search for lib$1 in includedir and libdir], -[ - if test "X$withval" = "Xno"; then - use_additional=no - else - if test "X$withval" = "X"; then - AC_LIB_WITH_FINAL_PREFIX([ - eval additional_includedir=\"$includedir\" - eval additional_libdir=\"$libdir\" - ]) - else - additional_includedir="$withval/include" - additional_libdir="$withval/lib" - fi - fi -]) - dnl Search the library and its dependencies in $additional_libdir and - dnl $LDFLAGS. Using breadth-first-seach. - LIB[]NAME= - LTLIB[]NAME= - INC[]NAME= - rpathdirs= - ltrpathdirs= - names_already_handled= - names_next_round='$1 $2' - while test -n "$names_next_round"; do - names_this_round="$names_next_round" - names_next_round= - for name in $names_this_round; do - already_handled= - for n in $names_already_handled; do - if test "$n" = "$name"; then - already_handled=yes - break - fi - done - if test -z "$already_handled"; then - names_already_handled="$names_already_handled $name" - dnl See if it was already located by an earlier AC_LIB_LINKFLAGS - dnl or AC_LIB_HAVE_LINKFLAGS call. - uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` - eval value=\"\$HAVE_LIB$uppername\" - if test -n "$value"; then - if test "$value" = yes; then - eval value=\"\$LIB$uppername\" - test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" - eval value=\"\$LTLIB$uppername\" - test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" - else - dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined - dnl that this library doesn't exist. So just drop it. - : - fi - else - dnl Search the library lib$name in $additional_libdir and $LDFLAGS - dnl and the already constructed $LIBNAME/$LTLIBNAME. - found_dir= - found_la= - found_so= - found_a= - if test $use_additional = yes; then - if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then - found_dir="$additional_libdir" - found_so="$additional_libdir/lib$name.$shlibext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - else - if test -f "$additional_libdir/lib$name.$libext"; then - found_dir="$additional_libdir" - found_a="$additional_libdir/lib$name.$libext" - if test -f "$additional_libdir/lib$name.la"; then - found_la="$additional_libdir/lib$name.la" - fi - fi - fi - fi - if test "X$found_dir" = "X"; then - for x in $LDFLAGS $LTLIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - case "$x" in - -L*) - dir=`echo "X$x" | sed -e 's/^X-L//'` - if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then - found_dir="$dir" - found_so="$dir/lib$name.$shlibext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - else - if test -f "$dir/lib$name.$libext"; then - found_dir="$dir" - found_a="$dir/lib$name.$libext" - if test -f "$dir/lib$name.la"; then - found_la="$dir/lib$name.la" - fi - fi - fi - ;; - esac - if test "X$found_dir" != "X"; then - break - fi - done - fi - if test "X$found_dir" != "X"; then - dnl Found the library. - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" - if test "X$found_so" != "X"; then - dnl Linking with a shared library. We attempt to hardcode its - dnl directory into the executable's runpath, unless it's the - dnl standard /usr/lib. - if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then - dnl No hardcoding is needed. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - dnl Use an explicit option to hardcode DIR into the resulting - dnl binary. - dnl Potentially add DIR to ltrpathdirs. - dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $found_dir" - fi - dnl The hardcoding into $LIBNAME is system dependent. - if test "$hardcode_direct" = yes; then - dnl Using DIR/libNAME.so during linking hardcodes DIR into the - dnl resulting binary. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then - dnl Use an explicit option to hardcode DIR into the resulting - dnl binary. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - dnl Potentially add DIR to rpathdirs. - dnl The rpathdirs will be appended to $LIBNAME at the end. - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $found_dir" - fi - else - dnl Rely on "-L$found_dir". - dnl But don't add it if it's already contained in the LDFLAGS - dnl or the already constructed $LIBNAME - haveit= - for x in $LDFLAGS $LIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$found_dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" - fi - if test "$hardcode_minus_L" != no; then - dnl FIXME: Not sure whether we should use - dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" - dnl here. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" - else - dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH - dnl here, because this doesn't fit in flags passed to the - dnl compiler. So give up. No hardcoding. This affects only - dnl very old systems. - dnl FIXME: Not sure whether we should use - dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" - dnl here. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" - fi - fi - fi - fi - else - if test "X$found_a" != "X"; then - dnl Linking with a static library. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" - else - dnl We shouldn't come here, but anyway it's good to have a - dnl fallback. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" - fi - fi - dnl Assume the include files are nearby. - additional_includedir= - case "$found_dir" in - */lib | */lib/) - basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` - additional_includedir="$basedir/include" - ;; - esac - if test "X$additional_includedir" != "X"; then - dnl Potentially add $additional_includedir to $INCNAME. - dnl But don't add it - dnl 1. if it's the standard /usr/include, - dnl 2. if it's /usr/local/include and we are using GCC on Linux, - dnl 3. if it's already present in $CPPFLAGS or the already - dnl constructed $INCNAME, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_includedir" != "X/usr/include"; then - haveit= - if test "X$additional_includedir" = "X/usr/local/include"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - for x in $CPPFLAGS $INC[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-I$additional_includedir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_includedir"; then - dnl Really add $additional_includedir to $INCNAME. - INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" - fi - fi - fi - fi - fi - dnl Look for dependencies. - if test -n "$found_la"; then - dnl Read the .la file. It defines the variables - dnl dlname, library_names, old_library, dependency_libs, current, - dnl age, revision, installed, dlopen, dlpreopen, libdir. - save_libdir="$libdir" - case "$found_la" in - */* | *\\*) . "$found_la" ;; - *) . "./$found_la" ;; - esac - libdir="$save_libdir" - dnl We use only dependency_libs. - for dep in $dependency_libs; do - case "$dep" in - -L*) - additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` - dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. - dnl But don't add it - dnl 1. if it's the standard /usr/lib, - dnl 2. if it's /usr/local/lib and we are using GCC on Linux, - dnl 3. if it's already present in $LDFLAGS or the already - dnl constructed $LIBNAME, - dnl 4. if it doesn't exist as a directory. - if test "X$additional_libdir" != "X/usr/lib"; then - haveit= - if test "X$additional_libdir" = "X/usr/local/lib"; then - if test -n "$GCC"; then - case $host_os in - linux* | gnu* | k*bsd*-gnu) haveit=yes;; - esac - fi - fi - if test -z "$haveit"; then - haveit= - for x in $LDFLAGS $LIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LIBNAME. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" - fi - fi - haveit= - for x in $LDFLAGS $LTLIB[]NAME; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X-L$additional_libdir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - if test -d "$additional_libdir"; then - dnl Really add $additional_libdir to $LTLIBNAME. - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" - fi - fi - fi - fi - ;; - -R*) - dir=`echo "X$dep" | sed -e 's/^X-R//'` - if test "$enable_rpath" != no; then - dnl Potentially add DIR to rpathdirs. - dnl The rpathdirs will be appended to $LIBNAME at the end. - haveit= - for x in $rpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - rpathdirs="$rpathdirs $dir" - fi - dnl Potentially add DIR to ltrpathdirs. - dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. - haveit= - for x in $ltrpathdirs; do - if test "X$x" = "X$dir"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - ltrpathdirs="$ltrpathdirs $dir" - fi - fi - ;; - -l*) - dnl Handle this in the next round. - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` - ;; - *.la) - dnl Handle this in the next round. Throw away the .la's - dnl directory; it is already contained in a preceding -L - dnl option. - names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` - ;; - *) - dnl Most likely an immediate library name. - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" - ;; - esac - done - fi - else - dnl Didn't find the library; assume it is in the system directories - dnl known to the linker and runtime loader. (All the system - dnl directories known to the linker should also be known to the - dnl runtime loader, otherwise the system is severely misconfigured.) - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" - fi - fi - fi - done - done - if test "X$rpathdirs" != "X"; then - if test -n "$hardcode_libdir_separator"; then - dnl Weird platform: only the last -rpath option counts, the user must - dnl pass all path elements in one option. We can arrange that for a - dnl single library, but not when more than one $LIBNAMEs are used. - alldirs= - for found_dir in $rpathdirs; do - alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" - done - dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. - acl_save_libdir="$libdir" - libdir="$alldirs" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" - else - dnl The -rpath options are cumulative. - for found_dir in $rpathdirs; do - acl_save_libdir="$libdir" - libdir="$found_dir" - eval flag=\"$hardcode_libdir_flag_spec\" - libdir="$acl_save_libdir" - LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" - done - fi - fi - if test "X$ltrpathdirs" != "X"; then - dnl When using libtool, the option that works for both libraries and - dnl executables is -R. The -R options are cumulative. - for found_dir in $ltrpathdirs; do - LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" - done - fi -]) - -dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, -dnl unless already present in VAR. -dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes -dnl contains two or three consecutive elements that belong together. -AC_DEFUN([AC_LIB_APPENDTOVAR], -[ - for element in [$2]; do - haveit= - for x in $[$1]; do - AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) - if test "X$x" = "X$element"; then - haveit=yes - break - fi - done - if test -z "$haveit"; then - [$1]="${[$1]}${[$1]:+ }$element" - fi - done -]) - -# lib-ld.m4 serial 3 (gettext-0.13) -dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl Subroutines of libtool.m4, -dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision -dnl with libtool.m4. - -dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. -AC_DEFUN([AC_LIB_PROG_LD_GNU], -[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, -[# I'd rather use --version here, but apparently some GNU ld's only accept -v. -case `$LD -v 2>&1 </dev/null` in -*GNU* | *'with BFD'*) - acl_cv_prog_gnu_ld=yes ;; -*) - acl_cv_prog_gnu_ld=no ;; -esac]) -with_gnu_ld=$acl_cv_prog_gnu_ld -]) - -dnl From libtool-1.4. Sets the variable LD. -AC_DEFUN([AC_LIB_PROG_LD], -[AC_ARG_WITH(gnu-ld, -[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], -test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -# Prepare PATH_SEPARATOR. -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by GCC]) - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]* | [A-Za-z]:[\\/]*)] - [re_direlt='/[^/][^/]*/\.\./'] - # Canonicalize the path of ld - ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(acl_cv_path_LD, -[if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - acl_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in - *GNU* | *'with BFD'*) - test "$with_gnu_ld" != no && break ;; - *) - test "$with_gnu_ld" != yes && break ;; - esac - fi - done - IFS="$ac_save_ifs" -else - acl_cv_path_LD="$LD" # Let the user override the test with a path. -fi]) -LD="$acl_cv_path_LD" -if test -n "$LD"; then - AC_MSG_RESULT($LD) -else - AC_MSG_RESULT(no) -fi -test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) -AC_LIB_PROG_LD_GNU -]) - diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..a569614 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +autoreconf -fi; +rm -Rf autom4te.cache; diff --git a/configure.in b/configure.in index f99292e..18d2716 100644 --- a/configure.in +++ b/configure.in @@ -6,74 +6,37 @@ # License as published by the Free Software Foundation version 2.1 # of the License. # -# Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> +# Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch> # -AC_INIT(libnl, 1.1, tgraf@suug.ch) -AC_CONFIG_HEADER(lib/defs.h) - -save_CFLAGS="${CFLAGS}" -save_LDFLAGS="${LDFLAGS}" -save_CPPFLAGS="${CPPFLAGS}" +AC_INIT(libnl, 2.0, tgraf@suug.ch) +AC_CONFIG_HEADERS([lib/defs.h]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) AC_PROG_CC +AM_PROG_CC_C_O AC_PROG_INSTALL +AM_PROG_LIBTOOL +AM_PROG_LEX +AC_PROG_YACC AC_C_CONST AC_C_INLINE -##################################################################### -## -## libm check -## -##################################################################### -M="No " -AC_CHECK_LIB(m, pow, -[ - LIBM="-lm" - M="Yes" -],[ - echo - echo "*** Error: libm required ***" - echo - exit -]) - -##################################################################### -## -## verbose error strings -## -##################################################################### -AC_ARG_ENABLE(verbose-errors, -[ --enable-verbose-errors enable verbose errors (debugging)],[ - if test x$enableval = xyes; then - AC_DEFINE_UNQUOTED(VERBOSE_ERRORS,"1",[verbose errors]) - fi -]) - -##################################################################### -## -## compile decisions -## -##################################################################### -COMPILE_LIBNL="Yes " -LIBNL_LIB="$LIBM" - -AC_SUBST(LIBNL_LIB) - -AC_OUTPUT([Makefile.opts libnl-1.pc doc/Doxyfile]) +AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH], + [Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]), + [pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig']) +AC_SUBST([pkgconfigdir]) -##################################################################### -## -## status report -## -##################################################################### -echo " ----------------------------------------------------------------------- -SUMMARY: +AC_ARG_ENABLE([cli], + AS_HELP_STRING([--disable-cli], [Do not build command line interface utils]), + [enable_cli="$enableval"], [enable_cli="yes"]) +AM_CONDITIONAL([ENABLE_CLI], [test "$enable_cli" = "yes"]) -Included in Compilation: - libnl: $COMPILE_LIBNL $LIBNL_LIB +AC_CHECK_LIB([m], [pow], [], AC_MSG_ERROR([libm is required])) -Dependencies: - libm $M (required)" +AC_CONFIG_FILES([Makefile doc/Doxyfile doc/Makefile lib/Makefile + include/Makefile src/Makefile src/lib/Makefile \ + libnl-2.0.pc include/netlink/version.h]) +AC_OUTPUT diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 7e00f51..8e311e3 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -463,6 +463,7 @@ WARN_LOGFILE = # with spaces. INPUT = ../lib \ + ../src/lib \ ../include/netlink # This tag can be used to specify the character encoding of the source files that diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 9c34e0f..0000000 --- a/doc/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# -# doc/Makefile -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),) - include ../Makefile.opts -endif - -export - -.PHONY: all gendoc clean distclean install - -all: - @true - -gendoc: - doxygen Doxyfile - -clean: - @true - -distclean: - $(RM) -f html/* - -install: - @true - -$(DEPS): ../Makefile.opts diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..040ff87 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,9 @@ +# -*- Makefile -*- + +.PHONY: gendoc + +gendoc: + doxygen Doxyfile; + +distclean-local: + rm -f html/*; diff --git a/doc/libnl.css b/doc/libnl.css index 42e3e27..22c4843 100644 --- a/doc/libnl.css +++ b/doc/libnl.css @@ -2,40 +2,42 @@ BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { font-family: Geneva, Arial, Helvetica, sans-serif; } BODY,TD { - font-size: 90%; + font-size: 90%; } H1 { text-align: center; - font-size: 160%; + font-size: 160%; } H2 { - font-size: 120%; + font-size: 120%; } H3 { - font-size: 100%; + font-size: 100%; +} +CAPTION { + font-weight: bold } -CAPTION { font-weight: bold } DIV.qindex { width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; + background-color: #e8eef2; + border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } -DIV.nav { +DIV.navpath { width: 100%; - background-color: #eeeeff; - border: 1px solid #b0b0b0; + background-color: #e8eef2; + border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } DIV.navtab { - background-color: #eeeeff; - border: 1px solid #b0b0b0; + background-color: #e8eef2; + border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; @@ -70,17 +72,45 @@ A.qindexHL:hover { background-color: #6666cc; color: #ffffff; } -A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } -A.el { text-decoration: none; font-weight: bold } -A.elRef { font-weight: bold } -A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} -A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} -A.codeRef:link { font-weight: normal; color: #0000FF} -A.codeRef:visited { font-weight: normal; color: #0000FF} -A:hover { text-decoration: none; background-color: #f2f2ff } -DL.el { margin-left: -1cm } +A.qindexHL:visited { + text-decoration: none; + background-color: #6666cc; + color: #ffffff +} +A.el { + text-decoration: none; + font-weight: bold +} +A.elRef { + font-weight: bold +} +A.code:link { + text-decoration: none; + font-weight: normal; + color: #0000FF +} +A.code:visited { + text-decoration: none; + font-weight: normal; + color: #0000FF +} +A.codeRef:link { + font-weight: normal; + color: #0000FF +} +A.codeRef:visited { + font-weight: normal; + color: #0000FF +} +A:hover { + text-decoration: none; + background-color: #f2f2ff +} +DL.el { + margin-left: -1cm +} .fragment { - font-family: Fixed, monospace; + font-family: monospace, fixed; font-size: 95%; } PRE.fragment { @@ -95,22 +125,25 @@ PRE.fragment { padding-top: 4px; padding-bottom: 4px; } -DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } -TD.md { background-color: #F4F4FB; font-weight: bold; } -TD.mdPrefix { - background-color: #F4F4FB; - color: #606060; - font-size: 80%; +DIV.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px } -TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; } -TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; } + DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold; } -DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +DIV.groupText { + margin-left: 16px; + font-style: italic; + font-size: 90% +} BODY { background: white; color: black; @@ -118,7 +151,7 @@ BODY { margin-left: 20px; } TD.indexkey { - background-color: #eeeeff; + background-color: #e8eef2; font-weight: bold; padding-right : 10px; padding-top : 2px; @@ -131,7 +164,7 @@ TD.indexkey { border: 1px solid #CCCCCC; } TD.indexvalue { - background-color: #eeeeff; + background-color: #e8eef2; font-style: italic; padding-right : 10px; padding-top : 2px; @@ -144,11 +177,16 @@ TD.indexvalue { border: 1px solid #CCCCCC; } TR.memlist { - background-color: #f0f0f0; + background-color: #f0f0f0; +} +P.formulaDsp { + text-align: center; +} +IMG.formulaDsp { +} +IMG.formulaInl { + vertical-align: middle; } -P.formulaDsp { text-align: center; } -IMG.formulaDsp { } -IMG.formulaInl { vertical-align: middle; } SPAN.keyword { color: #008000 } SPAN.keywordtype { color: #604020 } SPAN.keywordflow { color: #e08000 } @@ -156,16 +194,13 @@ SPAN.comment { color: #800000 } SPAN.preprocessor { color: #806020 } SPAN.stringliteral { color: #002080 } SPAN.charliteral { color: #008080 } -.mdTable { - border: 1px solid #868686; - background-color: #F4F4FB; - width: 100%; -} -.mdRow { - padding: 8px 10px; -} +SPAN.vhdldigit { color: #ff00ff } +SPAN.vhdlchar { color: #000000 } +SPAN.vhdlkeyword { color: #700070 } +SPAN.vhdllogic { color: #ff0000 } + .mdescLeft { - padding: 0px 8px 4px 8px; + padding: 0px 8px 4px 8px; font-size: 80%; font-style: italic; background-color: #FAFAFA; @@ -176,7 +211,7 @@ SPAN.charliteral { color: #008080 } margin: 0px; } .mdescRight { - padding: 0px 8px 4px 8px; + padding: 0px 8px 4px 8px; font-size: 80%; font-style: italic; background-color: #FAFAFA; @@ -273,38 +308,166 @@ SPAN.charliteral { color: #008080 } border-right-style: none; border-bottom-style: none; border-left-style: none; - color: #606060; + color: #606060; background-color: #FAFAFA; font-size: 80%; } -.search { color: #003399; - font-weight: bold; +.search { + color: #003399; + font-weight: bold; } FORM.search { - margin-bottom: 0px; - margin-top: 0px; + margin-bottom: 0px; + margin-top: 0px; } -INPUT.search { font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #eeeeff; +INPUT.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; } -TD.tiny { font-size: 75%; +TD.tiny { + font-size: 75%; } a { - color: #252E78; + color: #1A41A8; } a:visited { - color: #3D2185; + color: #2A3798; } -.dirtab { padding: 4px; - border-collapse: collapse; - border: 1px solid #b0b0b0; +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; } -TH.dirtab { background: #eeeeff; - font-weight: bold; +TH.dirtab { + background: #e8eef2; + font-weight: bold; } -HR { height: 1px; - border: none; - border-top: 1px solid black; +HR { + height: 1px; + border: none; + border-top: 1px solid black; } + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; + margin-left: 3px; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; + white-space: nowrap; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +/* these are for tree view when used as main index */ +.directory { + font-size: 9pt; + font-weight: bold; +} +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* The following two styles can be used to replace the root node title */ +/* with an image of your choice. Simply uncomment the next two styles, */ +/* specify the name of your image and be sure to set 'height' to the */ +/* proper pixel height of your image. */ + +/* .directory h3.swap { */ +/* height: 61px; */ +/* background-repeat: no-repeat; */ +/* background-image: url("yourimage.gif"); */ +/* } */ +/* .directory h3.swap span { */ +/* display: none; */ +/* } */ + +.directory > h3 { + margin-top: 0; +} +.directory p { + margin: 0px; + white-space: nowrap; +} +.directory div { + display: none; + margin: 0px; +} +.directory img { + vertical-align: -30%; +} +/* these are for tree view when not used as main index */ +.directory-alt { + font-size: 100%; + font-weight: bold; +} +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} +.directory-alt > h3 { + margin-top: 0; +} +.directory-alt p { + margin: 0px; + white-space: nowrap; +} +.directory-alt div { + display: none; + margin: 0px; +} +.directory-alt img { + vertical-align: -30%; +} + diff --git a/etc/pktloc b/etc/pktloc new file mode 100644 index 0000000..db36d40 --- /dev/null +++ b/etc/pktloc @@ -0,0 +1,44 @@ +# +# Location definitions for packet matching +# + +# name alignment offset mask +ip.version u8 net+0 0xF0 +ip.hdrlen u8 net+0 0x0F +ip.diffserv u8 net+1 +ip.length u16 net+2 +ip.id u16 net+4 +ip.df u8 net+6 0x40 +ip.mf u8 net+6 0x20 +ip.offset u16 net+6 0x1FFF +ip.ttl u8 net+8 +ip.proto u8 net+9 +ip.chksum u16 net+10 +ip.src u32 net+12 +ip.dst u32 net+16 + + +# +# Transmission Control Protocol (TCP) +# +# name alignment offset mask +tcp.sport u16 tcp+0 +tcp.dport u16 tcp+2 +tcp.seq u32 tcp+4 +tcp.ack u32 tcp+8 +tcp.off u8 tcp+12 0xF0 +tcp.reserved u8 tcp+12 0x0F +# FLAGS +tcp.win u16 tcp+14 +tcp.csum u16 tcp+16 +tcp.urg u16 tcp+18 +tcp.opts u32 tcp+20 + +# +# User Datagram Protocol (UDP) +# +# name alignment offset mask +udp.sport u16 tcp+0 +udp.dport u16 tcp+2 +udp.length u16 tcp+4 +udp.csum u16 tcp+6 diff --git a/include/Makefile b/include/Makefile deleted file mode 100644 index a2b23e0..0000000 --- a/include/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# include/Makefile -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),) - include ../Makefile.opts -endif - -.PHONY: all clean install - -all: - @true - -clean: - @true - -distclean: - @true - -install: - mkdir -p $(DESTDIR)$(includedir)/netlink/route/sch/ - mkdir -p $(DESTDIR)$(includedir)/netlink/route/cls/ - mkdir -p $(DESTDIR)$(includedir)/netlink/genl/ - mkdir -p $(DESTDIR)$(includedir)/netlink/fib_lookup/ - install -m 0644 netlink/*.h $(DESTDIR)$(includedir)/netlink/ - install -m 0644 netlink/route/*.h $(DESTDIR)$(includedir)/netlink/route/ - install -m 0644 netlink/route/sch/*.h $(DESTDIR)$(includedir)/netlink/route/sch/ - install -m 0644 netlink/route/cls/*.h $(DESTDIR)$(includedir)/netlink/route/cls/ - install -m 0644 netlink/genl/*.h $(DESTDIR)$(includedir)/netlink/genl/ - install -m 0644 netlink/fib_lookup/*.h $(DESTDIR)$(includedir)/netlink/fib_lookup/ - diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..8815a6e --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,63 @@ +# -*- Makefile -*- + +nobase_include_HEADERS = \ + netlink/fib_lookup/lookup.h \ + netlink/fib_lookup/request.h \ + netlink/genl/ctrl.h \ + netlink/genl/family.h \ + netlink/genl/genl.h \ + netlink/genl/mngt.h \ + netlink/netfilter/ct.h \ + netlink/netfilter/log.h \ + netlink/netfilter/log_msg.h \ + netlink/netfilter/netfilter.h \ + netlink/netfilter/nfnl.h \ + netlink/netfilter/queue.h \ + netlink/netfilter/queue_msg.h \ + netlink/addr.h \ + netlink/attr.h \ + netlink/cache-api.h \ + netlink/cache.h \ + netlink/data.h \ + netlink/errno.h \ + netlink/handlers.h \ + netlink/list.h \ + netlink/msg.h \ + netlink/netlink-compat.h \ + netlink/netlink-kernel.h \ + netlink/netlink.h \ + netlink/object-api.h \ + netlink/object.h \ + netlink/route/cls/fw.h \ + netlink/route/cls/police.h \ + netlink/route/cls/u32.h \ + netlink/route/link/info-api.h \ + netlink/route/link/vlan.h \ + netlink/route/sch/cbq.h \ + netlink/route/sch/dsmark.h \ + netlink/route/sch/fifo.h \ + netlink/route/sch/htb.h \ + netlink/route/sch/netem.h \ + netlink/route/sch/prio.h \ + netlink/route/sch/red.h \ + netlink/route/sch/sfq.h \ + netlink/route/sch/tbf.h \ + netlink/route/addr.h \ + netlink/route/class-modules.h \ + netlink/route/class.h \ + netlink/route/classifier-modules.h \ + netlink/route/classifier.h \ + netlink/route/link.h \ + netlink/route/neighbour.h \ + netlink/route/neightbl.h \ + netlink/route/nexthop.h \ + netlink/route/qdisc-modules.h \ + netlink/route/qdisc.h \ + netlink/route/route.h \ + netlink/route/rtnl.h \ + netlink/route/rule.h \ + netlink/route/tc.h \ + netlink/socket.h \ + netlink/types.h \ + netlink/utils.h \ + netlink/version.h diff --git a/include/linux/if_bad.h b/include/linux/if_bad.h index 4c1bcfe..857ce1e 100644 --- a/include/linux/if_bad.h +++ b/include/linux/if_bad.h @@ -107,7 +107,7 @@ enum { }; /* - * Device mapping structure. I'd just gone off and designed a + * Device mapping structure. I'd just gone off and designed a * beautiful scheme using only loadable modules with arguments * for driver options and along come the PCMCIA people 8) * @@ -116,11 +116,11 @@ enum { * being very small might be worth keeping for clean configuration. */ -struct ifmap +struct ifmap { unsigned long mem_start; unsigned long mem_end; - unsigned short base_addr; + unsigned short base_addr; unsigned char irq; unsigned char dma; unsigned char port; diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h new file mode 100644 index 0000000..068cd7b --- /dev/null +++ b/include/linux/if_vlan.h @@ -0,0 +1,61 @@ +/* + * VLAN An implementation of 802.1Q VLAN tagging. + * + * Authors: Ben Greear <greearb@candelatech.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. + * + */ + +#ifndef _LINUX_IF_VLAN_H_ +#define _LINUX_IF_VLAN_H_ + + +/* VLAN IOCTLs are found in sockios.h */ + +/* Passed in vlan_ioctl_args structure to determine behaviour. */ +enum vlan_ioctl_cmds { + ADD_VLAN_CMD, + DEL_VLAN_CMD, + SET_VLAN_INGRESS_PRIORITY_CMD, + SET_VLAN_EGRESS_PRIORITY_CMD, + GET_VLAN_INGRESS_PRIORITY_CMD, + GET_VLAN_EGRESS_PRIORITY_CMD, + SET_VLAN_NAME_TYPE_CMD, + SET_VLAN_FLAG_CMD, + GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */ + GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */ +}; + +enum vlan_flags { + VLAN_FLAG_REORDER_HDR = 0x1, +}; + +enum vlan_name_types { + VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */ + VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */ + VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */ + VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */ + VLAN_NAME_TYPE_HIGHEST +}; + +struct vlan_ioctl_args { + int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */ + char device1[24]; + + union { + char device2[24]; + int VID; + unsigned int skb_priority; + unsigned int name_type; + unsigned int bind_type; + unsigned int flag; /* Matches vlan_dev_info flags */ + } u; + + short vlan_qos; +}; + +#endif /* !(_LINUX_IF_VLAN_H_) */ diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h new file mode 100644 index 0000000..0750ca6 --- /dev/null +++ b/include/linux/netfilter.h @@ -0,0 +1,39 @@ +#ifndef __LINUX_NETFILTER_H +#define __LINUX_NETFILTER_H + + +/* Responses from hook functions. */ +#define NF_DROP 0 +#define NF_ACCEPT 1 +#define NF_STOLEN 2 +#define NF_QUEUE 3 +#define NF_REPEAT 4 +#define NF_STOP 5 +#define NF_MAX_VERDICT NF_STOP + +/* we overload the higher bits for encoding auxiliary data such as the queue + * number. Not nice, but better than additional function arguments. */ +#define NF_VERDICT_MASK 0x0000ffff +#define NF_VERDICT_BITS 16 + +#define NF_VERDICT_QMASK 0xffff0000 +#define NF_VERDICT_QBITS 16 + +#define NF_QUEUE_NR(x) (((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK) | NF_QUEUE) + +/* only for userspace compatibility */ +/* Generic cache responses from hook functions. + <= 0x2000 is used for protocol-flags. */ +#define NFC_UNKNOWN 0x4000 +#define NFC_ALTERED 0x8000 + +enum nf_inet_hooks { + NF_INET_PRE_ROUTING, + NF_INET_LOCAL_IN, + NF_INET_FORWARD, + NF_INET_LOCAL_OUT, + NF_INET_POST_ROUTING, + NF_INET_NUMHOOKS, +}; + +#endif /*__LINUX_NETFILTER_H*/ diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 20835a1..4bb4c44 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -10,7 +10,7 @@ #define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008 #define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010 #define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020 -#define NF_NETLINK_CONNTRACK_QUOTA 0x00000040 +#define NF_NETLINK_ACCT_QUOTA 0x00000040 #endif enum nfnetlink_groups { @@ -28,8 +28,10 @@ enum nfnetlink_groups { #define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_DESTROY, #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY - NFNLGRP_CONNTRACK_QUOTA, -#define NFNLGRP_CONNTRACK_QUOTA NFNLGRP_CONNTRACK_QUOTA + NFNLGRP_NFTABLES, +#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES + NFNLGRP_ACCT_QUOTA, +#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA __NFNLGRP_MAX, }; #define NFNLGRP_MAX (__NFNLGRP_MAX - 1) diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h index 2de5df9..38fafc1 100644 --- a/include/linux/netfilter/nfnetlink_log.h +++ b/include/linux/netfilter/nfnetlink_log.h @@ -51,6 +51,7 @@ enum nfulnl_attr_type { NFULA_UID, /* user id of socket */ NFULA_SEQ, /* instance-local sequence number */ NFULA_SEQ_GLOBAL, /* global sequence number */ + NFULA_GID, /* group id of socket */ __NFULA_MAX }; diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h new file mode 100644 index 0000000..bf7cfb6 --- /dev/null +++ b/include/linux/netfilter/nfnetlink_queue.h @@ -0,0 +1,94 @@ +#ifndef _NFNETLINK_QUEUE_H +#define _NFNETLINK_QUEUE_H + +#include <linux/types.h> +#include <linux/netfilter/nfnetlink.h> + +#ifndef aligned_be64 +#define aligned_be64 u_int64_t __attribute__((aligned(8))) +#endif + +enum nfqnl_msg_types { + NFQNL_MSG_PACKET, /* packet from kernel to userspace */ + NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */ + NFQNL_MSG_CONFIG, /* connect to a particular queue */ + + NFQNL_MSG_MAX +}; + +struct nfqnl_msg_packet_hdr { + __be32 packet_id; /* unique ID of packet in queue */ + __be16 hw_protocol; /* hw protocol (network order) */ + u_int8_t hook; /* netfilter hook */ +} __attribute__ ((packed)); + +struct nfqnl_msg_packet_hw { + __be16 hw_addrlen; + u_int16_t _pad; + u_int8_t hw_addr[8]; +}; + +struct nfqnl_msg_packet_timestamp { + aligned_be64 sec; + aligned_be64 usec; +}; + +enum nfqnl_attr_type { + NFQA_UNSPEC, + NFQA_PACKET_HDR, + NFQA_VERDICT_HDR, /* nfqnl_msg_verdict_hrd */ + NFQA_MARK, /* u_int32_t nfmark */ + NFQA_TIMESTAMP, /* nfqnl_msg_packet_timestamp */ + NFQA_IFINDEX_INDEV, /* u_int32_t ifindex */ + NFQA_IFINDEX_OUTDEV, /* u_int32_t ifindex */ + NFQA_IFINDEX_PHYSINDEV, /* u_int32_t ifindex */ + NFQA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */ + NFQA_HWADDR, /* nfqnl_msg_packet_hw */ + NFQA_PAYLOAD, /* opaque data payload */ + + __NFQA_MAX +}; +#define NFQA_MAX (__NFQA_MAX - 1) + +struct nfqnl_msg_verdict_hdr { + __be32 verdict; + __be32 id; +}; + + +enum nfqnl_msg_config_cmds { + NFQNL_CFG_CMD_NONE, + NFQNL_CFG_CMD_BIND, + NFQNL_CFG_CMD_UNBIND, + NFQNL_CFG_CMD_PF_BIND, + NFQNL_CFG_CMD_PF_UNBIND, +}; + +struct nfqnl_msg_config_cmd { + u_int8_t command; /* nfqnl_msg_config_cmds */ + u_int8_t _pad; + __be16 pf; /* AF_xxx for PF_[UN]BIND */ +}; + +enum nfqnl_config_mode { + NFQNL_COPY_NONE, + NFQNL_COPY_META, + NFQNL_COPY_PACKET, +}; + +struct nfqnl_msg_config_params { + __be32 copy_range; + u_int8_t copy_mode; /* enum nfqnl_config_mode */ +} __attribute__ ((packed)); + + +enum nfqnl_attr_config { + NFQA_CFG_UNSPEC, + NFQA_CFG_CMD, /* nfqnl_msg_config_cmd */ + NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ + NFQA_CFG_QUEUE_MAXLEN, /* u_int32_t */ + __NFQA_CFG_MAX +}; +#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1) + +#endif /* _NFNETLINK_QUEUE_H */ diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 30b8571..3c842ed 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -1,6 +1,7 @@ #ifndef __LINUX_PKT_CLS_H #define __LINUX_PKT_CLS_H +#include <linux/types.h> #include <linux/pkt_sched.h> /* I think i could have done better macros ; for now this is stolen from @@ -201,8 +202,8 @@ enum struct tc_u32_key { - __u32 mask; - __u32 val; + __be32 mask; + __be32 val; int off; int offmask; }; @@ -213,12 +214,12 @@ struct tc_u32_sel unsigned char offshift; unsigned char nkeys; - __u16 offmask; + __be16 offmask; __u16 off; short offoff; short hoff; - __u32 hmask; + __be32 hmask; struct tc_u32_key keys[0]; }; @@ -328,6 +329,58 @@ enum #define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) +/* Flow filter */ + +enum +{ + FLOW_KEY_SRC, + FLOW_KEY_DST, + FLOW_KEY_PROTO, + FLOW_KEY_PROTO_SRC, + FLOW_KEY_PROTO_DST, + FLOW_KEY_IIF, + FLOW_KEY_PRIORITY, + FLOW_KEY_MARK, + FLOW_KEY_NFCT, + FLOW_KEY_NFCT_SRC, + FLOW_KEY_NFCT_DST, + FLOW_KEY_NFCT_PROTO_SRC, + FLOW_KEY_NFCT_PROTO_DST, + FLOW_KEY_RTCLASSID, + FLOW_KEY_SKUID, + FLOW_KEY_SKGID, + FLOW_KEY_VLAN_TAG, + __FLOW_KEY_MAX, +}; + +#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1) + +enum +{ + FLOW_MODE_MAP, + FLOW_MODE_HASH, +}; + +enum +{ + TCA_FLOW_UNSPEC, + TCA_FLOW_KEYS, + TCA_FLOW_MODE, + TCA_FLOW_BASECLASS, + TCA_FLOW_RSHIFT, + TCA_FLOW_ADDEND, + TCA_FLOW_MASK, + TCA_FLOW_XOR, + TCA_FLOW_DIVISOR, + TCA_FLOW_ACT, + TCA_FLOW_POLICE, + TCA_FLOW_EMATCHES, + TCA_FLOW_PERTURB, + __TCA_FLOW_MAX +}; + +#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1) + /* Basic filter */ enum @@ -342,6 +395,20 @@ enum #define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1) + +/* Cgroup classifier */ + +enum +{ + TCA_CGROUP_UNSPEC, + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, + TCA_CGROUP_EMATCHES, + __TCA_CGROUP_MAX, +}; + +#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1) + /* Extended Matches */ struct tcf_ematch_tree_hdr @@ -409,7 +476,8 @@ enum #define TCF_EM_U32 3 #define TCF_EM_META 4 #define TCF_EM_TEXT 5 -#define TCF_EM_MAX 5 +#define TCF_EM_VLAN 6 +#define TCF_EM_MAX 6 enum { diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 29d358c..2473dbe 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -97,6 +97,16 @@ enum { RTM_SETNEIGHTBL, #define RTM_SETNEIGHTBL RTM_SETNEIGHTBL + RTM_NEWNDUSEROPT = 68, +#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT + + RTM_NEWADDRLABEL = 72, +#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL + RTM_DELADDRLABEL, +#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL + RTM_GETADDRLABEL, +#define RTM_GETADDRLABEL RTM_GETADDRLABEL + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -257,12 +267,13 @@ enum rtattr_type_t RTA_PREFSRC, RTA_METRICS, RTA_MULTIPATH, - RTA_PROTOINFO, + RTA_PROTOINFO, /* no longer used */ RTA_FLOW, RTA_CACHEINFO, - RTA_SESSION, - RTA_MP_ALGO, + RTA_SESSION, /* no longer used */ + RTA_MP_ALGO, /* no longer used */ RTA_TABLE, + RTA_GENERATION, __RTA_MAX }; @@ -351,6 +362,8 @@ enum #define RTAX_INITCWND RTAX_INITCWND RTAX_FEATURES, #define RTAX_FEATURES RTAX_FEATURES + RTAX_RTO_MIN, +#define RTAX_RTO_MIN RTAX_RTO_MIN __RTAX_MAX }; @@ -477,6 +490,32 @@ enum #define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg)))) #define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg)) +/******************************************************************** + * Neighbor Discovery userland options + ****/ + +struct nduseroptmsg +{ + unsigned char nduseropt_family; + unsigned char nduseropt_pad1; + unsigned short nduseropt_opts_len; /* Total length of options */ + int nduseropt_ifindex; + __u8 nduseropt_icmp_type; + __u8 nduseropt_icmp_code; + unsigned short nduseropt_pad2; + unsigned int nduseropt_pad3; + /* Followed by one or more ND options */ +}; + +enum +{ + NDUSEROPT_UNSPEC, + NDUSEROPT_SRCADDR, + __NDUSEROPT_MAX +}; + +#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) + #ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 @@ -540,6 +579,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_RULE, #define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE + RTNLGRP_ND_USEROPT, +#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) @@ -556,4 +597,6 @@ struct tcamsg #define TCA_ACT_TAB 1 /* attr type must be >=1 */ #define TCAA_MAX 1 +/* End of information exported to user level */ + #endif /* __LINUX_RTNETLINK_H */ diff --git a/include/netlink-local.h b/include/netlink-local.h index 05b4093..7e33119 100644 --- a/include/netlink-local.h +++ b/include/netlink-local.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_LOCAL_H_ @@ -23,9 +23,11 @@ #include <stdarg.h> #include <ctype.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/socket.h> #include <inttypes.h> #include <assert.h> +#include <limits.h> #include <arpa/inet.h> #include <netdb.h> @@ -81,247 +83,22 @@ struct trans_list { assert(0); \ } while (0) -#define RET_ERR(R, E) \ - do { \ - errno = E; \ - return -R; \ - } while (0) - -extern int __nl_error(int, const char *, unsigned int, - const char *, const char *, ...); - extern int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)); -#ifdef NL_ERROR_ASSERT -#include <assert.h> -static inline int __assert_error(const char *file, int line, char *func, - const char *fmt, ...) -{ - va_list args; - fprintf(stderr, "%s:%d:%s: ", file, line, func); - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - assert(0); - return 0; -} -#define nl_error(E, FMT,ARG...) \ - __assert_error(__FILE__, __LINE__, __FUNCTION__, FMT, ##ARG) - -#else -#define nl_error(E, FMT,ARG...) \ - __nl_error(E, __FILE__, __LINE__, __FUNCTION__, FMT, ##ARG) - -#endif - -#define nl_errno(E) nl_error(E, NULL) - -/* backwards compat */ -#define dp_new_line(params, line) nl_new_line(params, line) -#define dp_dump(params, fmt, arg...) nl_dump(params, fmt, ##arg) - -static inline int __trans_list_add(int i, const char *a, - struct nl_list_head *head) -{ - struct trans_list *tl; - - tl = calloc(1, sizeof(*tl)); - if (!tl) - return nl_errno(ENOMEM); - - tl->i = i; - tl->a = strdup(a); - - nl_list_add_tail(&tl->list, head); - - return 0; -} - -static inline void __trans_list_clear(struct nl_list_head *head) -{ - struct trans_list *tl, *next; - - nl_list_for_each_entry_safe(tl, next, head, list) { - free(tl->a); - free(tl); - } -} - -static inline char *__type2str(int type, char *buf, size_t len, - struct trans_tbl *tbl, size_t tbl_len) -{ - int i; - for (i = 0; i < tbl_len; i++) { - if (tbl[i].i == type) { - snprintf(buf, len, "%s", tbl[i].a); - return buf; - } - } - - snprintf(buf, len, "0x%x", type); - return buf; -} - -static inline char *__list_type2str(int type, char *buf, size_t len, - struct nl_list_head *head) -{ - struct trans_list *tl; +extern int __trans_list_add(int, const char *, struct nl_list_head *); +extern void __trans_list_clear(struct nl_list_head *); - nl_list_for_each_entry(tl, head, list) { - if (tl->i == type) { - snprintf(buf, len, "%s", tl->a); - return buf; - } - } +extern char *__type2str(int, char *, size_t, struct trans_tbl *, size_t); +extern int __str2type(const char *, struct trans_tbl *, size_t); - snprintf(buf, len, "0x%x", type); - return buf; -} - -static inline char *__flags2str(int flags, char *buf, size_t len, - struct trans_tbl *tbl, size_t tbl_len) -{ - int i; - int tmp = flags; - - memset(buf, 0, len); - - for (i = 0; i < tbl_len; i++) { - if (tbl[i].i & tmp) { - tmp &= ~tbl[i].i; - strncat(buf, tbl[i].a, len - strlen(buf) - 1); - if ((tmp & flags)) - strncat(buf, ",", len - strlen(buf) - 1); - } - } +extern char *__list_type2str(int, char *, size_t, struct nl_list_head *); +extern int __list_str2type(const char *, struct nl_list_head *); - return buf; -} +extern char *__flags2str(int, char *, size_t, struct trans_tbl *, size_t); +extern int __str2flags(const char *, struct trans_tbl *, size_t); -static inline int __str2type(const char *buf, struct trans_tbl *tbl, - size_t tbl_len) -{ - unsigned long l; - char *end; - int i; - - if (*buf == '\0') - return -1; - - for (i = 0; i < tbl_len; i++) - if (!strcasecmp(tbl[i].a, buf)) - return tbl[i].i; - - l = strtoul(buf, &end, 0); - if (l == ULONG_MAX || *end != '\0') - return -1; - - return (int) l; -} - -static inline int __list_str2type(const char *buf, struct nl_list_head *head) -{ - struct trans_list *tl; - unsigned long l; - char *end; - - if (*buf == '\0') - return -1; - - nl_list_for_each_entry(tl, head, list) { - if (!strcasecmp(tl->a, buf)) - return tl->i; - } - - l = strtoul(buf, &end, 0); - if (l == ULONG_MAX || *end != '\0') - return -1; - - return (int) l; -} - -static inline int __str2flags(const char *buf, struct trans_tbl *tbl, - size_t tbl_len) -{ - int i, flags = 0, len; - char *p = (char *) buf, *t; - - for (;;) { - if (*p == ' ') - p++; - - t = strchr(p, ','); - len = t ? t - p : strlen(p); - for (i = 0; i < tbl_len; i++) - if (!strncasecmp(tbl[i].a, p, len)) - flags |= tbl[i].i; - - if (!t) - return flags; - - p = ++t; - } - - return 0; -} - -static inline void __dp_dump(struct nl_dump_params *parms, const char *fmt, - va_list args) -{ - if (parms->dp_fd) - vfprintf(parms->dp_fd, fmt, args); - else if (parms->dp_buf || parms->dp_cb) { - char *buf = NULL; - vasprintf(&buf, fmt, args); - if (parms->dp_cb) - parms->dp_cb(parms, buf); - else - strncat(parms->dp_buf, buf, - parms->dp_buflen - strlen(parms->dp_buf) - 1); - free(buf); - } -} - -static inline void dp_dump_line(struct nl_dump_params *parms, int line, - const char *fmt, ...) -{ - va_list args; - - nl_new_line(parms, line); - - va_start(args, fmt); - __dp_dump(parms, fmt, args); - va_end(args); -} - -static inline void dump_from_ops(struct nl_object *obj, - struct nl_dump_params *params) -{ - int type = params->dp_type; - - if (type < 0 || type > NL_DUMP_MAX) - BUG(); - - if (params->dp_dump_msgtype) { -#if 0 - /* XXX */ - char buf[64]; - - dp_dump_line(params, 0, "%s ", - nl_cache_mngt_type2name(obj->ce_ops, - obj->ce_ops->co_protocol, - obj->ce_msgtype, - buf, sizeof(buf))); -#endif - params->dp_pre_dump = 1; - } else - dp_new_line(params, 0); - - if (obj->ce_ops->oo_dump[type]) - obj->ce_ops->oo_dump[type](obj, params); -} +extern void dump_from_ops(struct nl_object *, struct nl_dump_params *); static inline struct nl_cache *dp_cache(struct nl_object *obj) { @@ -340,9 +117,8 @@ static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg) #define __init __attribute__ ((constructor)) #define __exit __attribute__ ((destructor)) - -#define P_ACCEPT 0 -#define P_IGNORE 0 +#undef __deprecated +#define __deprecated __attribute__ ((deprecated)) #define min(x,y) ({ \ typeof(x) _x = (x); \ @@ -396,4 +172,12 @@ static inline char *nl_cache_name(struct nl_cache *cache) END_OF_MSGTYPES_LIST, \ } +static inline int wait_for_ack(struct nl_sock *sk) +{ + if (sk->s_flags & NL_NO_AUTO_ACK) + return 0; + else + return nl_wait_for_ack(sk); +} + #endif diff --git a/include/netlink-tc.h b/include/netlink-tc.h index 65be588..71a20ff 100644 --- a/include/netlink-tc.h +++ b/include/netlink-tc.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_TC_PRIV_H_ @@ -34,11 +34,10 @@ extern int tca_parse(struct nlattr **, int, struct rtnl_tca *, extern int tca_msg_parser(struct nlmsghdr *, struct rtnl_tca *); extern void tca_free_data(struct rtnl_tca *); extern int tca_clone(struct rtnl_tca *, struct rtnl_tca *); -extern int tca_dump_brief(struct rtnl_tca *, const char *, - struct nl_dump_params *, int); -extern int tca_dump_full(struct rtnl_tca *, struct nl_dump_params *, int); -extern int tca_dump_stats(struct rtnl_tca *, - struct nl_dump_params *, int); +extern void tca_dump_line(struct rtnl_tca *, const char *, + struct nl_dump_params *); +extern void tca_dump_details(struct rtnl_tca *, struct nl_dump_params *); +extern void tca_dump_stats(struct rtnl_tca *, struct nl_dump_params *); extern int tca_compare(struct nl_object *, struct nl_object *, uint32_t, int); extern void tca_set_ifindex(struct rtnl_tca *, int); @@ -51,7 +50,7 @@ extern void tca_set_kind(struct rtnl_tca *, const char *); extern char *tca_get_kind(struct rtnl_tca *); extern uint64_t tca_get_stat(struct rtnl_tca *, int ); -extern struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags); +extern int tca_build_msg(struct rtnl_tca *, int, int, struct nl_msg **); static inline void *tca_priv(struct rtnl_tca *tca) { diff --git a/include/netlink-types.h b/include/netlink-types.h index f7c6437..ff699bb 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_LOCAL_TYPES_H_ @@ -22,11 +22,12 @@ #define NL_SOCK_PASSCRED (1<<1) #define NL_OWN_PORT (1<<2) #define NL_MSG_PEEK (1<<3) +#define NL_NO_AUTO_ACK (1<<4) #define NL_MSG_CRED_PRESENT 1 struct nl_cache_ops; -struct nl_handle; +struct nl_sock; struct nl_object; struct nl_cb @@ -39,34 +40,34 @@ struct nl_cb /** May be used to replace nl_recvmsgs with your own implementation * in all internal calls to nl_recvmsgs. */ - int (*cb_recvmsgs_ow)(struct nl_handle *, + int (*cb_recvmsgs_ow)(struct nl_sock *, struct nl_cb *); /** Overwrite internal calls to nl_recv, must return the number of * octets read and allocate a buffer for the received data. */ - int (*cb_recv_ow)(struct nl_handle *, + int (*cb_recv_ow)(struct nl_sock *, struct sockaddr_nl *, unsigned char **, struct ucred **); /** Overwrites internal calls to nl_send, must send the netlink * message. */ - int (*cb_send_ow)(struct nl_handle *, + int (*cb_send_ow)(struct nl_sock *, struct nl_msg *); int cb_refcnt; }; -struct nl_handle +struct nl_sock { - struct sockaddr_nl h_local; - struct sockaddr_nl h_peer; - int h_fd; - int h_proto; - unsigned int h_seq_next; - unsigned int h_seq_expect; - int h_flags; - struct nl_cb * h_cb; + struct sockaddr_nl s_local; + struct sockaddr_nl s_peer; + int s_fd; + int s_proto; + unsigned int s_seq_next; + unsigned int s_seq_expect; + int s_flags; + struct nl_cb * s_cb; }; struct nl_cache @@ -82,6 +83,7 @@ struct nl_cache_assoc { struct nl_cache * ca_cache; change_func_t ca_change; + void * ca_change_data; }; struct nl_cache_mngr @@ -89,22 +91,13 @@ struct nl_cache_mngr int cm_protocol; int cm_flags; int cm_nassocs; - struct nl_handle * cm_handle; + struct nl_sock * cm_handle; struct nl_cache_assoc * cm_assocs; }; struct nl_parser_param; -struct genl_info -{ - struct sockaddr_nl * who; - struct nlmsghdr * nlh; - struct genlmsghdr * genlhdr; - void * userhdr; - struct nlattr ** attrs; -}; - -#define LOOSE_FLAG_COMPARISON 1 +#define LOOSE_COMPARISON 1 #define NL_OBJ_MARK 1 @@ -138,6 +131,7 @@ struct nl_msg struct ucred nm_creds; struct nlmsghdr * nm_nlh; size_t nm_size; + int nm_refcnt; }; struct rtnl_link_map @@ -244,11 +238,6 @@ struct rtnl_addr uint32_t a_flag_mask; }; -#define NEXTHOP_HAS_FLAGS 0x000001 -#define NEXTHOP_HAS_WEIGHT 0x000002 -#define NEXTHOP_HAS_IFINDEX 0x000004 -#define NEXTHOP_HAS_GATEWAY 0x000008 - struct rtnl_nexthop { uint8_t rtnh_flags; @@ -257,9 +246,9 @@ struct rtnl_nexthop /* 1 byte spare */ uint32_t rtnh_ifindex; struct nl_addr * rtnh_gateway; - uint32_t rtnh_mask; - + uint32_t ce_mask; /* HACK to support attr macros */ struct nl_list_head rtnh_list; + uint32_t rtnh_realms; }; struct rtnl_route @@ -270,24 +259,22 @@ struct rtnl_route uint8_t rt_dst_len; uint8_t rt_src_len; uint8_t rt_tos; - uint8_t rt_table; uint8_t rt_protocol; uint8_t rt_scope; uint8_t rt_type; + uint8_t rt_nmetrics; uint32_t rt_flags; struct nl_addr * rt_dst; struct nl_addr * rt_src; - char rt_iif[IFNAMSIZ]; - uint32_t rt_oif; - struct nl_addr * rt_gateway; + uint32_t rt_table; + uint32_t rt_iif; uint32_t rt_prio; uint32_t rt_metrics[RTAX_MAX]; uint32_t rt_metrics_mask; + uint32_t rt_nr_nh; struct nl_addr * rt_pref_src; struct nl_list_head rt_nexthops; - realm_t rt_realms; struct rtnl_rtcacheinfo rt_cacheinfo; - uint32_t rt_mp_algo; uint32_t rt_flag_mask; }; @@ -467,7 +454,7 @@ struct rtnl_tstats struct nl_data * pre ##_opts; \ uint64_t pre ##_stats[RTNL_TC_STATS_MAX+1]; \ struct nl_data * pre ##_xstats; \ - void * pre ##_subdata; \ + struct nl_data * pre ##_subdata; \ struct rtnl_tca @@ -490,8 +477,8 @@ struct rtnl_class struct rtnl_cls { NL_TCA_GENERIC(c); - uint32_t c_prio; - uint32_t c_protocol; + uint16_t c_prio; + uint16_t c_protocol; struct rtnl_cls_ops *c_ops; }; @@ -509,6 +496,12 @@ struct rtnl_u32 int cu_mask; }; +struct rtnl_cgroup +{ + struct rtnl_ematch_tree *cg_ematch; + int cg_mask; +}; + struct rtnl_fw { uint32_t cf_classid; @@ -518,6 +511,26 @@ struct rtnl_fw int cf_mask; }; +struct rtnl_ematch +{ + uint16_t e_id; + uint16_t e_kind; + uint16_t e_flags; + + struct nl_list_head e_childs; + struct nl_list_head e_list; + struct rtnl_ematch_ops *e_ops; + + char e_data[0]; +}; + +struct rtnl_ematch_tree +{ + uint16_t et_progid; + struct nl_list_head et_list; + +}; + struct rtnl_dsmark_qdisc { uint16_t qdm_indices; @@ -582,6 +595,18 @@ struct rtnl_netem_reo uint32_t nmro_correlation; }; +struct rtnl_netem_crpt +{ + uint32_t nmcr_probability; + uint32_t nmcr_correlation; +}; + +struct rtnl_netem_dist +{ + int16_t * dist_data; + size_t dist_size; +}; + struct rtnl_netem { uint32_t qnm_latency; @@ -593,6 +618,8 @@ struct rtnl_netem uint32_t qnm_mask; struct rtnl_netem_corr qnm_corr; struct rtnl_netem_reo qnm_ro; + struct rtnl_netem_crpt qnm_crpt; + struct rtnl_netem_dist qnm_dist; }; struct rtnl_htb_qdisc @@ -736,23 +763,67 @@ struct nfnl_ct { struct nfnl_log { NLHDR_COMMON - uint8_t log_family; - uint8_t log_hook; - uint16_t log_hwproto; - uint32_t log_mark; - struct timeval log_timestamp; - uint32_t log_indev; - uint32_t log_outdev; - uint32_t log_physindev; - uint32_t log_physoutdev; - uint8_t log_hwaddr[8]; - int log_hwaddr_len; - void * log_payload; - int log_payload_len; - char * log_prefix; - uint32_t log_uid; - uint32_t log_seq; - uint32_t log_seq_global; + uint16_t log_group; + uint8_t log_copy_mode; + uint32_t log_copy_range; + uint32_t log_flush_timeout; + uint32_t log_alloc_size; + uint32_t log_queue_threshold; + uint32_t log_flags; + uint32_t log_flag_mask; +}; + +struct nfnl_log_msg { + NLHDR_COMMON + + uint8_t log_msg_family; + uint8_t log_msg_hook; + uint16_t log_msg_hwproto; + uint32_t log_msg_mark; + struct timeval log_msg_timestamp; + uint32_t log_msg_indev; + uint32_t log_msg_outdev; + uint32_t log_msg_physindev; + uint32_t log_msg_physoutdev; + uint8_t log_msg_hwaddr[8]; + int log_msg_hwaddr_len; + void * log_msg_payload; + int log_msg_payload_len; + char * log_msg_prefix; + uint32_t log_msg_uid; + uint32_t log_msg_gid; + uint32_t log_msg_seq; + uint32_t log_msg_seq_global; +}; + +struct nfnl_queue { + NLHDR_COMMON + + uint16_t queue_group; + uint32_t queue_maxlen; + uint32_t queue_copy_range; + uint8_t queue_copy_mode; +}; + +struct nfnl_queue_msg { + NLHDR_COMMON + + uint16_t queue_msg_group; + uint8_t queue_msg_family; + uint8_t queue_msg_hook; + uint16_t queue_msg_hwproto; + uint32_t queue_msg_packetid; + uint32_t queue_msg_mark; + struct timeval queue_msg_timestamp; + uint32_t queue_msg_indev; + uint32_t queue_msg_outdev; + uint32_t queue_msg_physindev; + uint32_t queue_msg_physoutdev; + uint8_t queue_msg_hwaddr[8]; + int queue_msg_hwaddr_len; + void * queue_msg_payload; + int queue_msg_payload_len; + uint32_t queue_msg_verdict; }; #endif diff --git a/include/netlink/.gitignore b/include/netlink/.gitignore new file mode 100644 index 0000000..6702033 --- /dev/null +++ b/include/netlink/.gitignore @@ -0,0 +1 @@ +version.h diff --git a/include/netlink/addr.h b/include/netlink/addr.h index 25fce7e..cc3d201 100644 --- a/include/netlink/addr.h +++ b/include/netlink/addr.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_ADDR_H_ @@ -22,8 +22,9 @@ struct nl_addr; /* Creation */ 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_parse(const char *, int); +extern int nl_addr_parse(const char *, int, struct nl_addr **); extern struct nl_addr * nl_addr_clone(struct nl_addr *); /* Destroyage */ @@ -41,7 +42,7 @@ 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 struct addrinfo *nl_addr_info(struct nl_addr *addr); +extern int nl_addr_info(struct nl_addr *, struct addrinfo **); extern int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen); /* Access Functions */ diff --git a/include/netlink/attr.h b/include/netlink/attr.h index 6160f5f..8479c23 100644 --- a/include/netlink/attr.h +++ b/include/netlink/attr.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_ATTR_H_ @@ -24,228 +24,224 @@ extern "C" { struct nl_msg; /** - * @name Validation Policy Types + * @name Basic Attribute Data Types * @{ */ /** * @ingroup attr - * Standard attribute types to specify validation policy + * Basic attribute data types + * + * See \ref attr_datatypes for more details. */ enum { - NLA_UNSPEC, /**< Unspecified type */ - NLA_U8, /**< 8bit integer */ - NLA_U16, /**< 16bit integer */ - NLA_U32, /**< 32bit integer */ - NLA_U64, /**< 64bit integer */ - NLA_STRING, /**< character string */ - NLA_FLAG, /**< flag */ - NLA_MSECS, /**< micro seconds (64bit) */ - NLA_NESTED, /**< nested attributes */ + NLA_UNSPEC, /**< Unspecified type, binary data chunk */ + NLA_U8, /**< 8 bit integer */ + NLA_U16, /**< 16 bit integer */ + NLA_U32, /**< 32 bit integer */ + NLA_U64, /**< 64 bit integer */ + NLA_STRING, /**< NUL terminated character string */ + NLA_FLAG, /**< Flag */ + NLA_MSECS, /**< Micro seconds (64bit) */ + NLA_NESTED, /**< Nested attributes */ __NLA_TYPE_MAX, }; -/** - * @ingroup attr - * Maximum netlink validation policy type - */ #define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) /** @} */ /** * @ingroup attr - * attribute validation policy + * Attribute validation policy. * - * Policies are defined as arrays of this struct, the array must - * be accessible by attribute type up to the highest identifier - * to be expected. - * - * Example: - * @code - * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = { - * [ATTR_FOO] = { .type = NLA_U16 }, - * [ATTR_BAR] = { .type = NLA_STRING }, - * [ATTR_BAZ] = { .minlen = sizeof(struct mystruct) }, - * }; - * @endcode + * See \ref attr_datatypes for more details. */ struct nla_policy { /** Type of attribute or NLA_UNSPEC */ uint16_t type; - /** Minimal length of payload required to be available */ + /** Minimal length of payload required */ uint16_t minlen; - /** Maximal length of payload required to be available */ + /** Maximal length of payload allowed */ uint16_t maxlen; }; -/* size calculations */ +/* Size calculations */ extern int nla_attr_size(int payload); extern int nla_total_size(int payload); extern int nla_padlen(int payload); -/* payload access */ +/* Attribute parsing */ extern int nla_type(const struct nlattr *); extern void * nla_data(const struct nlattr *); extern int nla_len(const struct nlattr *); - -/* attribute parsing */ extern int nla_ok(const struct nlattr *, int); extern struct nlattr * nla_next(const struct nlattr *, int *); extern int nla_parse(struct nlattr **, int, struct nlattr *, int, struct nla_policy *); -extern int nla_parse_nested(struct nlattr **, int, struct nlattr *, - struct nla_policy *); extern int nla_validate(struct nlattr *, int, int, struct nla_policy *); extern struct nlattr * nla_find(struct nlattr *, int, int); -/* utilities */ +/* Helper Functions */ extern int nla_memcpy(void *, struct nlattr *, int); extern size_t nla_strlcpy(char *, const struct nlattr *, size_t); extern int nla_memcmp(const struct nlattr *, const void *, size_t); extern int nla_strcmp(const struct nlattr *, const char *); -/* attribute construction */ +/* Unspecific attribute */ extern struct nlattr * nla_reserve(struct nl_msg *, int, int); extern int nla_put(struct nl_msg *, int, int, const void *); -extern int nla_put_nested(struct nl_msg *, int, struct nl_msg *); -extern int nla_put_u8(struct nl_msg *, int, uint8_t); -extern int nla_put_u16(struct nl_msg *, int, uint16_t); -extern int nla_put_u32(struct nl_msg *, int, uint32_t); -extern int nla_put_u64(struct nl_msg *, int, uint64_t); -extern int nla_put_string(struct nl_msg *, int, const char *); -extern int nla_put_flag(struct nl_msg *, int); -extern int nla_put_msecs(struct nl_msg *, int, unsigned long); extern int nla_put_data(struct nl_msg *, int, struct nl_data *); extern int nla_put_addr(struct nl_msg *, int, struct nl_addr *); -/* attribute nesting */ -extern struct nlattr * nla_nest_start(struct nl_msg *, int); -extern int nla_nest_end(struct nl_msg *, struct nlattr *); - -/* attribute reading */ +/* Integer attribute */ extern uint8_t nla_get_u8(struct nlattr *); +extern int nla_put_u8(struct nl_msg *, int, uint8_t); extern uint16_t nla_get_u16(struct nlattr *); +extern int nla_put_u16(struct nl_msg *, int, uint16_t); extern uint32_t nla_get_u32(struct nlattr *); +extern int nla_put_u32(struct nl_msg *, int, uint32_t); extern uint64_t nla_get_u64(struct nlattr *); +extern int nla_put_u64(struct nl_msg *, int, uint64_t); + +/* String attribute */ extern char * nla_get_string(struct nlattr *); +extern char * nla_strdup(struct nlattr *); +extern int nla_put_string(struct nl_msg *, int, const char *); + +/* Flag attribute */ extern int nla_get_flag(struct nlattr *); +extern int nla_put_flag(struct nl_msg *, int); + +/* Msec attribute */ extern unsigned long nla_get_msecs(struct nlattr *); -extern struct nl_data * nla_get_data(struct nlattr *); -extern struct nl_addr * nla_get_addr(struct nlattr *, int); +extern int nla_put_msecs(struct nl_msg *, int, unsigned long); + +/* Attribute nesting */ +extern int nla_put_nested(struct nl_msg *, int, struct nl_msg *); +extern struct nlattr * nla_nest_start(struct nl_msg *, int); +extern int nla_nest_end(struct nl_msg *, struct nlattr *); +extern int nla_parse_nested(struct nlattr **, int, struct nlattr *, + struct nla_policy *); /** * @name Attribute Construction (Exception Based) - * - * All these functions jump to nla_put_failure in case of a failure - * instead of returning an error code. - * * @{ */ /** * @ingroup attr - * Add a netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg attrlen length of attribute payload - * @arg data head of attribute payload + * Add unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg attrlen Length of attribute payload. + * @arg data Head of attribute payload. */ -#define NLA_PUT(n, attrtype, attrlen, data) \ +#define NLA_PUT(msg, attrtype, attrlen, data) \ do { \ - if (nla_put(n, attrtype, attrlen, data) < 0) \ + if (nla_put(msg, attrtype, attrlen, data) < 0) \ goto nla_put_failure; \ } while(0) /** * @ingroup attr - * Add a basic netlink attribute to a netlink message - * @arg n netlink message - * @arg type atomic type - * @arg attrtype attribute type - * @arg value head of attribute payload + * Add atomic type attribute to netlink message. + * @arg msg Netlink message. + * @arg type Atomic type. + * @arg attrtype Attribute type. + * @arg value Head of attribute payload. */ -#define NLA_PUT_TYPE(n, type, attrtype, value) \ +#define NLA_PUT_TYPE(msg, type, attrtype, value) \ do { \ type __tmp = value; \ - NLA_PUT(n, attrtype, sizeof(type), &__tmp); \ + NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \ } while(0) /** - * Add a u8 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Add 8 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. */ -#define NLA_PUT_U8(n, attrtype, value) \ - NLA_PUT_TYPE(n, uint8_t, attrtype, value) +#define NLA_PUT_U8(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint8_t, attrtype, value) /** - * Add a u16 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Add 16 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. */ -#define NLA_PUT_U16(n, attrtype, value) \ - NLA_PUT_TYPE(n, uint16_t, attrtype, value) +#define NLA_PUT_U16(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint16_t, attrtype, value) /** - * Add a u32 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Add 32 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. */ -#define NLA_PUT_U32(n, attrtype, value) \ - NLA_PUT_TYPE(n, uint32_t, attrtype, value) +#define NLA_PUT_U32(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint32_t, attrtype, value) /** - * Add a u64 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Add 64 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value. */ -#define NLA_PUT_U64(n, attrtype, value) \ - NLA_PUT_TYPE(n, uint64_t, attrtype, value) +#define NLA_PUT_U64(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, uint64_t, attrtype, value) /** - * Add a character string netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value character string + * Add string attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value NUL terminated character string. */ -#define NLA_PUT_STRING(n, attrtype, value) \ - NLA_PUT(n, attrtype, strlen(value) + 1, value) +#define NLA_PUT_STRING(msg, attrtype, value) \ + NLA_PUT(msg, attrtype, strlen(value) + 1, value) /** - * Add a flag netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type + * Add flag attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. */ -#define NLA_PUT_FLAG(n, attrtype) \ - NLA_PUT(n, attrtype, 0, NULL) +#define NLA_PUT_FLAG(msg, attrtype) \ + NLA_PUT(msg, attrtype, 0, NULL) /** - * Add a msecs netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg msecs numeric value in micro seconds + * Add msecs attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg msecs Numeric value in micro seconds. */ -#define NLA_PUT_MSECS(n, attrtype, msecs) \ - NLA_PUT_U64(n, attrtype, msecs) +#define NLA_PUT_MSECS(msg, attrtype, msecs) \ + NLA_PUT_U64(msg, attrtype, msecs) /** - * Add a address attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg addr abstract address object + * Add address attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg addr Abstract address object. */ -#define NLA_PUT_ADDR(n, attrtype, addr) \ - NLA_PUT(n, attrtype, nl_addr_get_len(addr), \ +#define NLA_PUT_ADDR(msg, attrtype, addr) \ + NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \ nl_addr_get_binary_addr(addr)) +/** + * Add abstract data attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg data Abstract data object. + */ +#define NLA_PUT_DATA(msg, attrtype, data) \ + NLA_PUT(msg, attrtype, nl_data_get_size(data), \ + nl_data_get(data)) + /** @} */ /** @@ -255,7 +251,7 @@ extern struct nl_addr * nla_get_addr(struct nlattr *, int); /** * @ingroup attr - * iterate over a stream of attributes + * Iterate over a stream of attributes * @arg pos loop counter, set to current attribute * @arg head head of attribute stream * @arg len length of attribute stream @@ -268,7 +264,7 @@ extern struct nl_addr * nla_get_addr(struct nlattr *, int); /** * @ingroup attr - * iterate over a stream of nested attributes + * Iterate over a stream of nested attributes * @arg pos loop counter, set to current attribute * @arg nla attribute containing the nested attributes * @arg rem initialized to len, holds bytes currently remaining in stream diff --git a/include/netlink/cache-api.h b/include/netlink/cache-api.h index 96699ed..22fc449 100644 --- a/include/netlink/cache-api.h +++ b/include/netlink/cache-api.h @@ -39,7 +39,7 @@ extern "C" { * // function which must trigger a complete dump on the kernel-side of * // whatever the cache covers. * static int my_request_update(struct nl_cache *cache, - * struct nl_handle *socket) + * struct nl_sock *socket) * { * // In this example, we request a full dump of the interface table * return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); @@ -172,7 +172,7 @@ struct nl_cache_ops * Called whenever an update of the cache is required. Must send * a request message to the kernel requesting a complete dump. */ - int (*co_request_update)(struct nl_cache *, struct nl_handle *); + int (*co_request_update)(struct nl_cache *, struct nl_sock *); /** * Called whenever a message was received that needs to be parsed. diff --git a/include/netlink/cache.h b/include/netlink/cache.h index cb7741b..c752920 100644 --- a/include/netlink/cache.h +++ b/include/netlink/cache.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_CACHE_H_ @@ -24,7 +24,7 @@ extern "C" { struct nl_cache; -typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int); +typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *); /* Access Functions */ extern int nl_cache_nitems(struct nl_cache *); @@ -36,10 +36,12 @@ 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 *); -/* Cache creation/deletion */ -#define nl_cache_alloc_from_ops(ptr) nl_cache_alloc(ptr) extern struct nl_cache * nl_cache_alloc(struct nl_cache_ops *); -extern struct nl_cache * nl_cache_alloc_name(const char *); +extern int nl_cache_alloc_and_fill(struct nl_cache_ops *, + struct nl_sock *, + struct nl_cache **); +extern int nl_cache_alloc_name(const char *, + struct nl_cache **); extern struct nl_cache * nl_cache_subset(struct nl_cache *, struct nl_object *); extern void nl_cache_clear(struct nl_cache *); @@ -50,19 +52,19 @@ extern int nl_cache_add(struct nl_cache *, struct nl_object *); extern int nl_cache_parse_and_add(struct nl_cache *, struct nl_msg *); -#define nl_cache_delete(a, b) nl_cache_remove(b) extern void nl_cache_remove(struct nl_object *); -#define nl_cache_update(a, b) nl_cache_refill(a, b) -extern int nl_cache_refill(struct nl_handle *, +extern int nl_cache_refill(struct nl_sock *, struct nl_cache *); -extern int nl_cache_pickup(struct nl_handle *, +extern int nl_cache_pickup(struct nl_sock *, struct nl_cache *); -extern int nl_cache_resync(struct nl_handle *, +extern int nl_cache_resync(struct nl_sock *, struct nl_cache *, - change_func_t); + change_func_t, + void *); extern int nl_cache_include(struct nl_cache *, struct nl_object *, - change_func_t); + change_func_t, + void *); /* General */ extern int nl_cache_is_empty(struct nl_cache *); @@ -106,11 +108,14 @@ struct nl_cache_mngr; #define NL_AUTO_PROVIDE 1 -extern struct nl_cache_mngr * nl_cache_mngr_alloc(struct nl_handle *, - int, int); -extern struct nl_cache * nl_cache_mngr_add(struct nl_cache_mngr *, +extern int nl_cache_mngr_alloc(struct nl_sock *, + int, int, + struct nl_cache_mngr **); +extern int nl_cache_mngr_add(struct nl_cache_mngr *, const char *, - change_func_t); + change_func_t, + void *, + struct nl_cache **); extern int nl_cache_mngr_get_fd(struct nl_cache_mngr *); extern int nl_cache_mngr_poll(struct nl_cache_mngr *, int); diff --git a/include/netlink/cli/addr.h b/include/netlink/cli/addr.h new file mode 100644 index 0000000..d0fd055 --- /dev/null +++ b/include/netlink/cli/addr.h @@ -0,0 +1,32 @@ +/* + * netlink/cli/addr.h CLI Address Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_ADDR_H_ +#define __NETLINK_CLI_ADDR_H_ + +#include <netlink/route/addr.h> + +#define nl_cli_addr_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "address", rtnl_addr_alloc_cache) + +extern struct rtnl_addr *nl_cli_addr_alloc(void); + +extern void nl_cli_addr_parse_family(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_local(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_dev(struct rtnl_addr *, struct nl_cache *,char *); +extern void nl_cli_addr_parse_label(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_peer(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_scope(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_broadcast(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_preferred(struct rtnl_addr *, char *); +extern void nl_cli_addr_parse_valid(struct rtnl_addr *, char *); + +#endif diff --git a/include/netlink/cli/ct.h b/include/netlink/cli/ct.h new file mode 100644 index 0000000..bed776b --- /dev/null +++ b/include/netlink/cli/ct.h @@ -0,0 +1,34 @@ +/* + * netlink/cli/ct.h CLI Conntrack Helper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_CT_H_ +#define __NETLINK_CLI_CT_H_ + +#include <netlink/netfilter/ct.h> +#include <linux/netfilter/nf_conntrack_common.h> + +extern struct nfnl_ct *nl_cli_ct_alloc(void); +extern struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *); + +extern void nl_cli_ct_parse_family(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_protocol(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_mark(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_timeout(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_id(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_use(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_src(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_dst(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_src_port(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_dst_port(struct nfnl_ct *, int, char *); +extern void nl_cli_ct_parse_tcp_state(struct nfnl_ct *, char *); +extern void nl_cli_ct_parse_status(struct nfnl_ct *, char *); + +#endif diff --git a/include/netlink/cli/link.h b/include/netlink/cli/link.h new file mode 100644 index 0000000..c404019 --- /dev/null +++ b/include/netlink/cli/link.h @@ -0,0 +1,30 @@ +/* + * netlink/cli/link.h CLI Link Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_LINK_H_ +#define __NETLINK_CLI_LINK_H_ + +#include <netlink/route/link.h> +#include <netlink/cli/utils.h> + +#define nl_cli_link_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "link", rtnl_link_alloc_cache) + +extern struct rtnl_link *nl_cli_link_alloc(void); + +extern void nl_cli_link_parse_family(struct rtnl_link *, char *); +extern void nl_cli_link_parse_name(struct rtnl_link *, char *); +extern void nl_cli_link_parse_mtu(struct rtnl_link *, char *); +extern void nl_cli_link_parse_ifindex(struct rtnl_link *, char *); +extern void nl_cli_link_parse_txqlen(struct rtnl_link *, char *); +extern void nl_cli_link_parse_weight(struct rtnl_link *, char *); + +#endif diff --git a/include/netlink/cli/neigh.h b/include/netlink/cli/neigh.h new file mode 100644 index 0000000..5440012 --- /dev/null +++ b/include/netlink/cli/neigh.h @@ -0,0 +1,27 @@ +/* + * netlink/cli/neighbour.h CLI Neighbour Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_NEIGH_H_ +#define __NETLINK_CLI_NEIGH_H_ + +#include <netlink/route/neighbour.h> + +#define nl_cli_neigh_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "neighbour", rtnl_neigh_alloc_cache) + +extern struct rtnl_neigh *nl_cli_neigh_alloc(void); +extern void nl_cli_neigh_parse_dst(struct rtnl_neigh *, char *); +extern void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *, char *); +extern void nl_cli_neigh_parse_dev(struct rtnl_neigh *, struct nl_cache *, char *); +extern void nl_cli_neigh_parse_family(struct rtnl_neigh *, char *); +extern void nl_cli_neigh_parse_state(struct rtnl_neigh *, char *); + +#endif diff --git a/include/netlink/cli/qdisc.h b/include/netlink/cli/qdisc.h new file mode 100644 index 0000000..9fc4506 --- /dev/null +++ b/include/netlink/cli/qdisc.h @@ -0,0 +1,28 @@ +/* + * netlink/cli/qdisc.h CLI QDisc Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_QDISC_H_ +#define __NETLINK_CLI_QDISC_H_ + +#include <netlink/route/qdisc.h> + +#define nl_cli_qdisc_alloc_cache(sk) \ + nl_cli_alloc_cache((sk), "queueing disciplines", \ + rtnl_qdisc_alloc_cache) + +extern struct rtnl_qdisc *nl_cli_qdisc_alloc(void); + +extern void nl_cli_qdisc_parse_dev(struct rtnl_qdisc *, struct nl_cache *, char *); +extern void nl_cli_qdisc_parse_parent(struct rtnl_qdisc *, char *); +extern void nl_cli_qdisc_parse_handle(struct rtnl_qdisc *, char *); +extern void nl_cli_qdisc_parse_kind(struct rtnl_qdisc *, char *); + +#endif diff --git a/include/netlink/cli/route.h b/include/netlink/cli/route.h new file mode 100644 index 0000000..089c658 --- /dev/null +++ b/include/netlink/cli/route.h @@ -0,0 +1,34 @@ +/* + * netlink/cli//route.h CLI Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_ROUTE_H_ +#define __NETLINK_CLI_ROUTE_H_ + +#include <netlink/route/route.h> + +extern struct rtnl_route *nl_cli_route_alloc(void); + +extern struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *, int); + +extern void nl_cli_route_parse_family(struct rtnl_route *, char *); +extern void nl_cli_route_parse_dst(struct rtnl_route *, char *); +extern void nl_cli_route_parse_src(struct rtnl_route *, char *); +extern void nl_cli_route_parse_pref_src(struct rtnl_route *, char *); +extern void nl_cli_route_parse_metric(struct rtnl_route *, char *); +extern void nl_cli_route_parse_nexthop(struct rtnl_route *, char *, struct nl_cache *); +extern void nl_cli_route_parse_table(struct rtnl_route *, char *); +extern void nl_cli_route_parse_prio(struct rtnl_route *, char *); +extern void nl_cli_route_parse_scope(struct rtnl_route *, char *); +extern void nl_cli_route_parse_protocol(struct rtnl_route *, char *); +extern void nl_cli_route_parse_type(struct rtnl_route *, char *); +extern void nl_cli_route_parse_iif(struct rtnl_route *, char *, struct nl_cache *); + +#endif diff --git a/include/netlink/cli/rule.h b/include/netlink/cli/rule.h new file mode 100644 index 0000000..61cd63e --- /dev/null +++ b/include/netlink/cli/rule.h @@ -0,0 +1,21 @@ +/* + * netlink/cli/rule.h CLI Routing Rule Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __NETLINK_CLI_RULE_H_ +#define __NETLINK_CLI_RULE_H_ + +#include <netlink/route/rule.h> + +extern struct rtnl_rule *nl_cli_rule_alloc(void); +extern struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *); +extern void nl_cli_rule_parse_family(struct rtnl_rule *, char *); + +#endif diff --git a/src/utils.h b/include/netlink/cli/utils.h index d738ce7..2a23208 100644 --- a/src/utils.h +++ b/include/netlink/cli/utils.h @@ -6,26 +6,30 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#ifndef __SRC_UTILS_H_ -#define __SRC_UTILS_H_ +#ifndef __NETLINK_CLI_UTILS_H_ +#define __NETLINK_CLI_UTILS_H_ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <stdarg.h> +#include <limits.h> #include <inttypes.h> #include <errno.h> #include <stdint.h> +#include <ctype.h> #include <getopt.h> +#include <dlfcn.h> #include <sys/types.h> #include <sys/socket.h> -#include <netlink-local.h> #include <netlink/netlink.h> #include <netlink/utils.h> #include <netlink/addr.h> +#include <netlink/list.h> #include <netlink/route/rtnl.h> #include <netlink/route/link.h> #include <netlink/route/addr.h> @@ -36,6 +40,7 @@ #include <netlink/route/qdisc.h> #include <netlink/route/class.h> #include <netlink/route/classifier.h> +#include <netlink/route/cls/ematch.h> #include <netlink/fib_lookup/lookup.h> #include <netlink/fib_lookup/request.h> #include <netlink/genl/genl.h> @@ -43,21 +48,33 @@ #include <netlink/genl/mngt.h> #include <netlink/netfilter/ct.h> -extern int nltool_init(int argc, char *argv[]); -extern int nltool_connect(struct nl_handle *nlh, int protocol); -extern struct nl_addr *nltool_addr_parse(const char *str); -extern int nltool_parse_dumptype(const char *str); -extern struct nl_handle *nltool_alloc_handle(void); - -extern struct nl_cache *nltool_alloc_link_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_addr_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_neigh_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_neightbl_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_route_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_rule_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_qdisc_cache(struct nl_handle *nlh); -extern struct nl_cache *nltool_alloc_genl_family_cache(struct nl_handle *nlh); - -#define arg_match(str) !strcasecmp(argv[idx], str) +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __init +#define __init __attribute__((constructor)) +#endif + +#ifndef __exit +#define __exit __attribute__((destructor)) +#endif + +extern uint32_t nl_cli_parse_u32(const char *); +extern void nl_cli_print_version(void); +extern void nl_cli_fatal(int, const char *, ...); +extern struct nl_addr * nl_cli_addr_parse(const char *, int); +extern int nl_cli_connect(struct nl_sock *, int); +extern struct nl_sock * nl_cli_alloc_socket(void); +extern int nl_cli_parse_dumptype(const char *); +extern int nl_cli_confirm(struct nl_object *, + struct nl_dump_params *, int); + +extern struct nl_cache *nl_cli_alloc_cache(struct nl_sock *, const char *, + int (*ac)(struct nl_sock *, struct nl_cache **)); + +#ifdef __cplusplus +} +#endif #endif diff --git a/include/netlink/data.h b/include/netlink/data.h index bb28d13..071159e 100644 --- a/include/netlink/data.h +++ b/include/netlink/data.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_DATA_H_ @@ -22,6 +22,7 @@ struct nl_data; /* General */ extern struct nl_data * nl_data_alloc(void *, size_t); +extern struct nl_data * nl_data_alloc_attr(struct nlattr *); extern struct nl_data * nl_data_clone(struct nl_data *); extern int nl_data_append(struct nl_data *, void *, size_t); extern void nl_data_free(struct nl_data *); diff --git a/include/netlink/errno.h b/include/netlink/errno.h new file mode 100644 index 0000000..c8a376e --- /dev/null +++ b/include/netlink/errno.h @@ -0,0 +1,60 @@ +/* + * netlink/errno.h Error Numbers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_ERRNO_H_ +#define NETLINK_ERRNO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NLE_SUCCESS 0 +#define NLE_FAILURE 1 +#define NLE_INTR 2 +#define NLE_BAD_SOCK 3 +#define NLE_AGAIN 4 +#define NLE_NOMEM 5 +#define NLE_EXIST 6 +#define NLE_INVAL 7 +#define NLE_RANGE 8 +#define NLE_MSGSIZE 9 +#define NLE_OPNOTSUPP 10 +#define NLE_AF_NOSUPPORT 11 +#define NLE_OBJ_NOTFOUND 12 +#define NLE_NOATTR 13 +#define NLE_MISSING_ATTR 14 +#define NLE_AF_MISMATCH 15 +#define NLE_SEQ_MISMATCH 16 +#define NLE_MSG_OVERFLOW 17 +#define NLE_MSG_TRUNC 18 +#define NLE_NOADDR 19 +#define NLE_SRCRT_NOSUPPORT 20 +#define NLE_MSG_TOOSHORT 21 +#define NLE_MSGTYPE_NOSUPPORT 22 +#define NLE_OBJ_MISMATCH 23 +#define NLE_NOCACHE 24 +#define NLE_BUSY 25 +#define NLE_PROTO_MISMATCH 26 +#define NLE_NOACCESS 27 +#define NLE_PERM 28 +#define NLE_PKTLOC_FILE 29 + +#define NLE_MAX NLE_PKTLOC_FILE + +extern const char * nl_geterror(int); +extern void nl_perror(int, const char *); +extern int nl_syserr2nlerr(int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/fib_lookup/lookup.h b/include/netlink/fib_lookup/lookup.h index 29c7ee8..8bf27b8 100644 --- a/include/netlink/fib_lookup/lookup.h +++ b/include/netlink/fib_lookup/lookup.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_FIB_LOOKUP_H_ @@ -28,9 +28,10 @@ extern void flnl_result_put(struct flnl_result *); extern struct nl_cache * flnl_result_alloc_cache(void); -extern struct nl_msg * flnl_lookup_build_request(struct flnl_request *, - int); -extern int flnl_lookup(struct nl_handle *, +extern int flnl_lookup_build_request(struct flnl_request *, + int, + struct nl_msg **); +extern int flnl_lookup(struct nl_sock *, struct flnl_request *, struct nl_cache *); diff --git a/include/netlink/genl/ctrl.h b/include/netlink/genl/ctrl.h index 5d65c68..1ae62f4 100644 --- a/include/netlink/genl/ctrl.h +++ b/include/netlink/genl/ctrl.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_GENL_CTRL_H_ @@ -22,11 +22,12 @@ extern "C" { struct genl_family; -extern struct nl_cache * genl_ctrl_alloc_cache(struct nl_handle *); +extern int genl_ctrl_alloc_cache(struct nl_sock *, + struct nl_cache **); extern struct genl_family * genl_ctrl_search(struct nl_cache *, int); extern struct genl_family * genl_ctrl_search_by_name(struct nl_cache *, const char *); -extern int genl_ctrl_resolve(struct nl_handle *, +extern int genl_ctrl_resolve(struct nl_sock *, const char *); #ifdef __cplusplus diff --git a/include/netlink/genl/genl.h b/include/netlink/genl/genl.h index de142d0..3f3340c 100644 --- a/include/netlink/genl/genl.h +++ b/include/netlink/genl/genl.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_GENL_H_ @@ -20,9 +20,9 @@ extern "C" { #endif -extern int genl_connect(struct nl_handle *); +extern int genl_connect(struct nl_sock *); -extern int genl_send_simple(struct nl_handle *, int, int, +extern int genl_send_simple(struct nl_sock *, int, int, int, int); extern void * genlmsg_put(struct nl_msg *, uint32_t, uint32_t, diff --git a/include/netlink/genl/mngt.h b/include/netlink/genl/mngt.h index 467922a..8b0244f 100644 --- a/include/netlink/genl/mngt.h +++ b/include/netlink/genl/mngt.h @@ -22,6 +22,15 @@ extern "C" { struct nl_cache_ops; +struct genl_info +{ + struct sockaddr_nl * who; + struct nlmsghdr * nlh; + struct genlmsghdr * genlhdr; + void * userhdr; + struct nlattr ** attrs; +}; + /** * @ingroup genl_mngt * Generic Netlink Command diff --git a/include/netlink/handlers.h b/include/netlink/handlers.h index fcd3e48..f373f58 100644 --- a/include/netlink/handlers.h +++ b/include/netlink/handlers.h @@ -23,8 +23,9 @@ extern "C" { #endif struct nl_cb; -struct nl_handle; +struct nl_sock; struct nl_msg; +struct ucred; /** * @name Callback Typedefs @@ -64,10 +65,6 @@ enum nl_cb_action { NL_STOP, }; -/* backwards compatibility */ -#define NL_PROCEED NL_OK -#define NL_EXIT NL_STOP - /** * Callback kinds * @ingroup cb @@ -129,15 +126,15 @@ extern int nl_cb_err(struct nl_cb *, enum nl_cb_kind, nl_recvmsg_err_cb_t, void *); extern void nl_cb_overwrite_recvmsgs(struct nl_cb *, - int (*func)(struct nl_handle *, + int (*func)(struct nl_sock *, struct nl_cb *)); extern void nl_cb_overwrite_recv(struct nl_cb *, - int (*func)(struct nl_handle *, + int (*func)(struct nl_sock *, struct sockaddr_nl *, unsigned char **, struct ucred **)); extern void nl_cb_overwrite_send(struct nl_cb *, - int (*func)(struct nl_handle *, + int (*func)(struct nl_sock *, struct nl_msg *)); #ifdef __cplusplus diff --git a/include/netlink/list.h b/include/netlink/list.h index e7a2646..28712ed 100644 --- a/include/netlink/list.h +++ b/include/netlink/list.h @@ -18,6 +18,11 @@ struct nl_list_head struct nl_list_head * prev; }; +static inline void NL_INIT_LIST_HEAD(struct nl_list_head *list) +{ + list->next = list; + list->prev = list; +} static inline void __nl_list_add(struct nl_list_head *obj, struct nl_list_head *prev, @@ -68,6 +73,9 @@ static inline int nl_list_empty(struct nl_list_head *head) #define NL_LIST_HEAD(name) \ struct nl_list_head name = { &(name), &(name) } +#define nl_list_first_entry(head, type, member) \ + nl_list_entry((head)->next, type, member) + #define nl_list_for_each_entry(pos, head, member) \ for (pos = nl_list_entry((head)->next, typeof(*pos), member); \ &(pos)->member != (head); \ diff --git a/include/netlink/msg.h b/include/netlink/msg.h index 732e66f..e331f42 100644 --- a/include/netlink/msg.h +++ b/include/netlink/msg.h @@ -68,11 +68,6 @@ extern struct nlattr * nlmsg_find_attr(struct nlmsghdr *, int, int); extern int nlmsg_validate(struct nlmsghdr *, int, int, struct nla_policy *); -/* Backward compatibility */ -#define nlmsg_new() nlmsg_alloc() -#define nlmsg_build_simple(a, b) nlmsg_alloc_simple(a, b) -#define nlmsg_build(ptr) nlmsg_inherit(ptr) - 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); @@ -86,6 +81,7 @@ 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 */ diff --git a/include/netlink/netfilter/ct.h b/include/netlink/netfilter/ct.h index 965b869..c4402b3 100644 --- a/include/netlink/netfilter/ct.h +++ b/include/netlink/netfilter/ct.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ @@ -27,86 +27,97 @@ struct nfnl_ct; extern struct nl_object_ops ct_obj_ops; -/* General */ extern struct nfnl_ct * nfnl_ct_alloc(void); -extern struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *); +extern int nfnl_ct_alloc_cache(struct nl_sock *, struct nl_cache **); -extern int nfnlmsg_ct_group(struct nlmsghdr *); -extern struct nfnl_ct * nfnlmsg_ct_parse(struct nlmsghdr *); +extern int nfnlmsg_ct_group(struct nlmsghdr *); +extern int nfnlmsg_ct_parse(struct nlmsghdr *, struct nfnl_ct **); -extern void nfnl_ct_get(struct nfnl_ct *); -extern void nfnl_ct_put(struct nfnl_ct *); +extern void nfnl_ct_get(struct nfnl_ct *); +extern void nfnl_ct_put(struct nfnl_ct *); -extern int nfnl_ct_dump_request(struct nl_handle *); +extern int nfnl_ct_dump_request(struct nl_sock *); -extern void nfnl_ct_set_family(struct nfnl_ct *, uint8_t); -extern uint8_t nfnl_ct_get_family(const struct nfnl_ct *); +extern int nfnl_ct_build_add_request(const struct nfnl_ct *, int, + struct nl_msg **); +extern int nfnl_ct_add(struct nl_sock *, const struct nfnl_ct *, int); -extern void nfnl_ct_set_proto(struct nfnl_ct *, uint8_t); -extern int nfnl_ct_test_proto(const struct nfnl_ct *); -extern uint8_t nfnl_ct_get_proto(const struct nfnl_ct *); +extern int nfnl_ct_build_delete_request(const struct nfnl_ct *, int, + struct nl_msg **); +extern int nfnl_ct_delete(struct nl_sock *, const struct nfnl_ct *, int); -extern void nfnl_ct_set_tcp_state(struct nfnl_ct *, uint8_t); -extern int nfnl_ct_test_tcp_state(const struct nfnl_ct *); -extern uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *); -extern char * nfnl_ct_tcp_state2str(uint8_t, char *, size_t); -extern int nfnl_ct_str2tcp_state(const char *name); +extern int nfnl_ct_build_query_request(const struct nfnl_ct *, int, + struct nl_msg **); +extern int nfnl_ct_query(struct nl_sock *, const struct nfnl_ct *, int); -extern void nfnl_ct_set_status(struct nfnl_ct *, uint32_t); -extern void nfnl_ct_unset_status(struct nfnl_ct *, uint32_t); -extern uint32_t nfnl_ct_get_status(const struct nfnl_ct *); +extern void nfnl_ct_set_family(struct nfnl_ct *, uint8_t); +extern uint8_t nfnl_ct_get_family(const struct nfnl_ct *); -extern void nfnl_ct_set_timeout(struct nfnl_ct *, uint32_t); -extern int nfnl_ct_test_timeout(const struct nfnl_ct *); -extern uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *); +extern void nfnl_ct_set_proto(struct nfnl_ct *, uint8_t); +extern int nfnl_ct_test_proto(const struct nfnl_ct *); +extern uint8_t nfnl_ct_get_proto(const struct nfnl_ct *); -extern void nfnl_ct_set_mark(struct nfnl_ct *, uint32_t); -extern int nfnl_ct_test_mark(const struct nfnl_ct *); -extern uint32_t nfnl_ct_get_mark(const struct nfnl_ct *); +extern void nfnl_ct_set_tcp_state(struct nfnl_ct *, uint8_t); +extern int nfnl_ct_test_tcp_state(const struct nfnl_ct *); +extern uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *); +extern char * nfnl_ct_tcp_state2str(uint8_t, char *, size_t); +extern int nfnl_ct_str2tcp_state(const char *name); -extern void nfnl_ct_set_use(struct nfnl_ct *, uint32_t); -extern int nfnl_ct_test_use(const struct nfnl_ct *); -extern uint32_t nfnl_ct_get_use(const struct nfnl_ct *); +extern void nfnl_ct_set_status(struct nfnl_ct *, uint32_t); +extern void nfnl_ct_unset_status(struct nfnl_ct *, uint32_t); +extern uint32_t nfnl_ct_get_status(const struct nfnl_ct *); +extern char * nfnl_ct_status2str(int, char *, size_t); +extern int nfnl_ct_str2status(const char *); -extern void nfnl_ct_set_id(struct nfnl_ct *, uint32_t); -extern int nfnl_ct_test_id(const struct nfnl_ct *); -extern uint32_t nfnl_ct_get_id(const struct nfnl_ct *); +extern void nfnl_ct_set_timeout(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_timeout(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *); -extern int nfnl_ct_set_src(struct nfnl_ct *, int, - struct nl_addr *); +extern void nfnl_ct_set_mark(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_mark(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_mark(const struct nfnl_ct *); + +extern void nfnl_ct_set_use(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_use(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_use(const struct nfnl_ct *); + +extern void nfnl_ct_set_id(struct nfnl_ct *, uint32_t); +extern int nfnl_ct_test_id(const struct nfnl_ct *); +extern uint32_t nfnl_ct_get_id(const struct nfnl_ct *); + +extern int nfnl_ct_set_src(struct nfnl_ct *, int, struct nl_addr *); extern struct nl_addr * nfnl_ct_get_src(const struct nfnl_ct *, int); -extern int nfnl_ct_set_dst(struct nfnl_ct *, int, - struct nl_addr *); +extern int nfnl_ct_set_dst(struct nfnl_ct *, int, struct nl_addr *); extern struct nl_addr * nfnl_ct_get_dst(const struct nfnl_ct *, int); -extern void nfnl_ct_set_src_port(struct nfnl_ct *, int, uint16_t); -extern int nfnl_ct_test_src_port(const struct nfnl_ct *, int); -extern uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *, int); +extern void nfnl_ct_set_src_port(struct nfnl_ct *, int, uint16_t); +extern int nfnl_ct_test_src_port(const struct nfnl_ct *, int); +extern uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *, int); -extern void nfnl_ct_set_dst_port(struct nfnl_ct *, int, uint16_t); -extern int nfnl_ct_test_dst_port(const struct nfnl_ct *, int); -extern uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *, int); +extern void nfnl_ct_set_dst_port(struct nfnl_ct *, int, uint16_t); +extern int nfnl_ct_test_dst_port(const struct nfnl_ct *, int); +extern uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *, int); -extern void nfnl_ct_set_icmp_id(struct nfnl_ct *, int, uint16_t); -extern int nfnl_ct_test_icmp_id(const struct nfnl_ct *, int); -extern uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *, int); +extern void nfnl_ct_set_icmp_id(struct nfnl_ct *, int, uint16_t); +extern int nfnl_ct_test_icmp_id(const struct nfnl_ct *, int); +extern uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *, int); -extern void nfnl_ct_set_icmp_type(struct nfnl_ct *, int, uint8_t); -extern int nfnl_ct_test_icmp_type(const struct nfnl_ct *, int); -extern uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *, int); +extern void nfnl_ct_set_icmp_type(struct nfnl_ct *, int, uint8_t); +extern int nfnl_ct_test_icmp_type(const struct nfnl_ct *, int); +extern uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *, int); -extern void nfnl_ct_set_icmp_code(struct nfnl_ct *, int, uint8_t); -extern int nfnl_ct_test_icmp_code(const struct nfnl_ct *, int); -extern uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *, int); +extern void nfnl_ct_set_icmp_code(struct nfnl_ct *, int, uint8_t); +extern int nfnl_ct_test_icmp_code(const struct nfnl_ct *, int); +extern uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *, int); -extern void nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t); -extern int nfnl_ct_test_packets(const struct nfnl_ct *, int); -extern uint64_t nfnl_ct_get_packets(const struct nfnl_ct *,int); +extern void nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t); +extern int nfnl_ct_test_packets(const struct nfnl_ct *, int); +extern uint64_t nfnl_ct_get_packets(const struct nfnl_ct *,int); -extern void nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t); -extern int nfnl_ct_test_bytes(const struct nfnl_ct *, int); -extern uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *, int); +extern void nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t); +extern int nfnl_ct_test_bytes(const struct nfnl_ct *, int); +extern uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *, int); #ifdef __cplusplus } diff --git a/include/netlink/netfilter/log.h b/include/netlink/netfilter/log.h index e65cc58..2002fa8 100644 --- a/include/netlink/netfilter/log.h +++ b/include/netlink/netfilter/log.h @@ -9,6 +9,7 @@ * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> */ #ifndef NETLINK_LOG_H_ @@ -20,82 +21,85 @@ extern "C" { #endif -struct nl_handle; +struct nl_sock; struct nlmsghdr; struct nfnl_log; extern struct nl_object_ops log_obj_ops; -/* General */ -extern struct nfnl_log *nfnl_log_alloc(void); -extern struct nfnl_log *nfnlmsg_log_parse(struct nlmsghdr *); +enum nfnl_log_copy_mode { + NFNL_LOG_COPY_NONE, + NFNL_LOG_COPY_META, + NFNL_LOG_COPY_PACKET, +}; -extern void nfnl_log_get(struct nfnl_log *); -extern void nfnl_log_put(struct nfnl_log *); +enum nfnl_log_flags { + NFNL_LOG_FLAG_SEQ = 0x1, + NFNL_LOG_FLAG_SEQ_GLOBAL = 0x2, +}; -extern struct nl_msg * nfnl_log_build_bind(uint16_t);; -extern int nfnl_log_bind(struct nl_handle *, uint16_t); -extern struct nl_msg * nfnl_log_build_unbind(uint16_t); -extern int nfnl_log_unbind(struct nl_handle *, uint16_t); -extern struct nl_msg * nfnl_log_build_pf_bind(uint8_t); -extern int nfnl_log_pf_bind(struct nl_handle *, uint8_t); -extern struct nl_msg * nfnl_log_build_pf_unbind(uint8_t); -extern int nfnl_log_pf_unbind(struct nl_handle *, uint8_t); -extern struct nl_msg * nfnl_log_build_mode(uint16_t, uint8_t, uint32_t); -extern int nfnl_log_set_mode(struct nl_handle *, uint16_t, - uint8_t, uint32_t); +/* General */ +extern struct nfnl_log * nfnl_log_alloc(void); +extern int nfnlmsg_log_parse(struct nlmsghdr *, + struct nfnl_log **); -extern void nfnl_log_set_family(struct nfnl_log *, uint8_t); -extern uint8_t nfnl_log_get_family(const struct nfnl_log *); +extern void nfnl_log_get(struct nfnl_log *); +extern void nfnl_log_put(struct nfnl_log *); -extern void nfnl_log_set_hwproto(struct nfnl_log *, uint16_t); -extern int nfnl_log_test_hwproto(const struct nfnl_log *); -extern uint16_t nfnl_log_get_hwproto(const struct nfnl_log *); +/* Attributes */ +extern void nfnl_log_set_group(struct nfnl_log *, uint16_t); +extern int nfnl_log_test_group(const struct nfnl_log *); +extern uint16_t nfnl_log_get_group(const struct nfnl_log *); -extern void nfnl_log_set_hook(struct nfnl_log *, uint8_t); -extern int nfnl_log_test_hook(const struct nfnl_log *); -extern uint8_t nfnl_log_get_hook(const struct nfnl_log *); +extern void nfnl_log_set_copy_mode(struct nfnl_log *, + enum nfnl_log_copy_mode); +extern int nfnl_log_test_copy_mode(const struct nfnl_log *); +extern enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *); -extern void nfnl_log_set_mark(struct nfnl_log *, uint32_t); -extern int nfnl_log_test_mark(const struct nfnl_log *); -extern uint32_t nfnl_log_get_mark(const struct nfnl_log *); +extern char * nfnl_log_copy_mode2str(enum nfnl_log_copy_mode, + char *, size_t); +extern enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *); -extern void nfnl_log_set_timestamp(struct nfnl_log *, - struct timeval *); -extern const struct timeval *nfnl_log_get_timestamp(const struct nfnl_log *); +extern void nfnl_log_set_copy_range(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_copy_range(const struct nfnl_log *); +extern uint32_t nfnl_log_get_copy_range(const struct nfnl_log *); -extern void nfnl_log_set_indev(struct nfnl_log *, uint32_t); -extern uint32_t nfnl_log_get_indev(const struct nfnl_log *); +extern void nfnl_log_set_flush_timeout(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_flush_timeout(const struct nfnl_log *); +extern uint32_t nfnl_log_get_flush_timeout(const struct nfnl_log *); -extern void nfnl_log_set_outdev(struct nfnl_log *, uint32_t); -extern uint32_t nfnl_log_get_outdev(const struct nfnl_log *); +extern void nfnl_log_set_alloc_size(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_alloc_size(const struct nfnl_log *); +extern uint32_t nfnl_log_get_alloc_size(const struct nfnl_log *); -extern void nfnl_log_set_physindev(struct nfnl_log *, uint32_t); -extern uint32_t nfnl_log_get_physindev(const struct nfnl_log *); +extern void nfnl_log_set_queue_threshold(struct nfnl_log *, uint32_t); +extern int nfnl_log_test_queue_threshold(const struct nfnl_log *); +extern uint32_t nfnl_log_get_queue_threshold(const struct nfnl_log *); -extern void nfnl_log_set_physoutdev(struct nfnl_log *, uint32_t); -extern uint32_t nfnl_log_get_physoutdev(const struct nfnl_log *); +extern void nfnl_log_set_flags(struct nfnl_log *, unsigned int); +extern void nfnl_log_unset_flags(struct nfnl_log *, unsigned int); +extern unsigned int nfnl_log_get_flags(const struct nfnl_log *); -extern void nfnl_log_set_hwaddr(struct nfnl_log *, uint8_t *, int); -extern const uint8_t * nfnl_log_get_hwaddr(const struct nfnl_log *, int *); +extern char * nfnl_log_flags2str(unsigned int, char *, size_t); +extern unsigned int nfnl_log_str2flags(const char *); -extern int nfnl_log_set_payload(struct nfnl_log *, uint8_t *, int); -extern const void * nfnl_log_get_payload(const struct nfnl_log *, int *); +extern int nfnl_log_build_pf_bind(uint8_t, struct nl_msg **); +extern int nfnl_log_pf_bind(struct nl_sock *, uint8_t); -extern int nfnl_log_set_prefix(struct nfnl_log *, void *); -extern const char * nfnl_log_get_prefix(const struct nfnl_log *); +extern int nfnl_log_build_pf_unbind(uint8_t, struct nl_msg **); +extern int nfnl_log_pf_unbind(struct nl_sock *, uint8_t); -extern void nfnl_log_set_uid(struct nfnl_log *, uint32_t); -extern int nfnl_log_test_uid(const struct nfnl_log *); -extern uint32_t nfnl_log_get_uid(const struct nfnl_log *); +extern int nfnl_log_build_create_request(const struct nfnl_log *, + struct nl_msg **); +extern int nfnl_log_create(struct nl_sock *, const struct nfnl_log *); -extern void nfnl_log_set_seq(struct nfnl_log *, uint32_t); -extern int nfnl_log_test_seq(const struct nfnl_log *); -extern uint32_t nfnl_log_get_seq(const struct nfnl_log *); +extern int nfnl_log_build_change_request(const struct nfnl_log *, + struct nl_msg **); +extern int nfnl_log_change(struct nl_sock *, const struct nfnl_log *); -extern void nfnl_log_set_seq_global(struct nfnl_log *, uint32_t); -extern int nfnl_log_test_seq_global(const struct nfnl_log *); -extern uint32_t nfnl_log_get_seq_global(const struct nfnl_log *); +extern int nfnl_log_build_delete_request(const struct nfnl_log *, + struct nl_msg **); +extern int nfnl_log_delete(struct nl_sock *, const struct nfnl_log *); #ifdef __cplusplus } diff --git a/include/netlink/netfilter/log_msg.h b/include/netlink/netfilter/log_msg.h new file mode 100644 index 0000000..63b0f64 --- /dev/null +++ b/include/netlink/netfilter/log_msg.h @@ -0,0 +1,98 @@ +/* + * netlink/netfilter/log_msg.h Netfilter Log Message + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + */ + +#ifndef NETLINK_LOG_MSG_H_ +#define NETLINK_LOG_MSG_H_ + +#include <netlink/netlink.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct nlmsghdr; +struct nfnl_log_msg; + +extern struct nl_object_ops log_msg_obj_ops; + +/* General */ +extern struct nfnl_log_msg *nfnl_log_msg_alloc(void); +extern int nfnlmsg_log_msg_parse(struct nlmsghdr *, + struct nfnl_log_msg **); + +extern void nfnl_log_msg_get(struct nfnl_log_msg *); +extern void nfnl_log_msg_put(struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_family(struct nfnl_log_msg *, uint8_t); +extern uint8_t nfnl_log_msg_get_family(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_hwproto(struct nfnl_log_msg *, uint16_t); +extern int nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *); +extern uint16_t nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_hook(struct nfnl_log_msg *, uint8_t); +extern int nfnl_log_msg_test_hook(const struct nfnl_log_msg *); +extern uint8_t nfnl_log_msg_get_hook(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_mark(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_mark(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_mark(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_timestamp(struct nfnl_log_msg *, + struct timeval *); +extern const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_indev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_indev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_outdev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_outdev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_physindev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_physindev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *, uint32_t); +extern uint32_t nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *, uint8_t *, int); +extern const uint8_t * nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *, int *); + +extern int nfnl_log_msg_set_payload(struct nfnl_log_msg *, uint8_t *, int); +extern const void * nfnl_log_msg_get_payload(const struct nfnl_log_msg *, int *); + +extern int nfnl_log_msg_set_prefix(struct nfnl_log_msg *, void *); +extern const char * nfnl_log_msg_get_prefix(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_uid(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_uid(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_uid(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_gid(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_gid(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_gid(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_seq(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_seq(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_seq(const struct nfnl_log_msg *); + +extern void nfnl_log_msg_set_seq_global(struct nfnl_log_msg *, uint32_t); +extern int nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *); +extern uint32_t nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/netlink/netfilter/netfilter.h b/include/netlink/netfilter/netfilter.h new file mode 100644 index 0000000..dd3589c --- /dev/null +++ b/include/netlink/netfilter/netfilter.h @@ -0,0 +1,31 @@ +/* + * netlink/netfilter/netfilter.h Netfilter generic functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + */ + +#ifndef NETLINK_NETFILTER_H_ +#define NETLINK_NETFILTER_H_ + +#include <netlink/netlink.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern char * nfnl_verdict2str(unsigned int, char *, size_t); +extern unsigned int nfnl_str2verdict(const char *); + +extern char * nfnl_inet_hook2str(unsigned int, char *, size_t); +extern unsigned int nfnl_str2inet_hook(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/netfilter/nfnl.h b/include/netlink/netfilter/nfnl.h index 123d93e..8da4ba1 100644 --- a/include/netlink/netfilter/nfnl.h +++ b/include/netlink/netfilter/nfnl.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ @@ -23,14 +23,14 @@ extern "C" { #define NFNL_HDRLEN NLMSG_ALIGN(sizeof(struct nfgenmsg)) #define NFNLMSG_TYPE(subsys, subtype) (((subsys) << 8) | (subtype)) -extern int nfnl_connect(struct nl_handle *); +extern int nfnl_connect(struct nl_sock *); extern uint8_t nfnlmsg_subsys(struct nlmsghdr *); extern uint8_t nfnlmsg_subtype(struct nlmsghdr *); extern uint8_t nfnlmsg_family(struct nlmsghdr *); extern uint16_t nfnlmsg_res_id(struct nlmsghdr *); -extern int nfnl_send_simple(struct nl_handle *, uint8_t, uint8_t, +extern int nfnl_send_simple(struct nl_sock *, uint8_t, uint8_t, int, uint8_t, uint16_t); extern struct nl_msg * nfnlmsg_alloc_simple(uint8_t, uint8_t, int, uint8_t, uint16_t); diff --git a/include/netlink/netfilter/queue.h b/include/netlink/netfilter/queue.h new file mode 100644 index 0000000..664610d --- /dev/null +++ b/include/netlink/netfilter/queue.h @@ -0,0 +1,90 @@ +/* + * netlink/netfilter/queue.h Netfilter Queue + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + */ + +#ifndef NETLINK_QUEUE_H_ +#define NETLINK_QUEUE_H_ + +#include <netlink/netlink.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_sock; +struct nlmsghdr; +struct nfnl_queue; + +extern struct nl_object_ops queue_obj_ops; + +enum nfnl_queue_copy_mode { + NFNL_QUEUE_COPY_NONE, + NFNL_QUEUE_COPY_META, + NFNL_QUEUE_COPY_PACKET, +}; + +/* General */ +extern struct nl_sock * nfnl_queue_socket_alloc(void); + +extern struct nfnl_queue * nfnl_queue_alloc(void); + +extern void nfnl_queue_get(struct nfnl_queue *); +extern void nfnl_queue_put(struct nfnl_queue *); + +/* Attributes */ +extern void nfnl_queue_set_group(struct nfnl_queue *, uint16_t); +extern int nfnl_queue_test_group(const struct nfnl_queue *); +extern uint16_t nfnl_queue_get_group(const struct nfnl_queue *); + +extern void nfnl_queue_set_maxlen(struct nfnl_queue *, uint32_t); +extern int nfnl_queue_test_maxlen(const struct nfnl_queue *); +extern uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *); + +extern void nfnl_queue_set_copy_mode(struct nfnl_queue *, + enum nfnl_queue_copy_mode); +extern int nfnl_queue_test_copy_mode(const struct nfnl_queue *); +extern enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *); + +extern char * nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode, + char *, size_t); +extern enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *); + +extern void nfnl_queue_set_copy_range(struct nfnl_queue *, + uint32_t); +extern int nfnl_queue_test_copy_range(const struct nfnl_queue *); +extern uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *); + +extern int nfnl_queue_build_pf_bind(uint8_t, struct nl_msg **); +extern int nfnl_queue_pf_bind(struct nl_sock *, uint8_t); + +extern int nfnl_queue_build_pf_unbind(uint8_t, struct nl_msg **); +extern int nfnl_queue_pf_unbind(struct nl_sock *, uint8_t); + +extern int nfnl_queue_build_create_request(const struct nfnl_queue *, + struct nl_msg **); +extern int nfnl_queue_create(struct nl_sock *, + const struct nfnl_queue *); + +extern int nfnl_queue_build_change_request(const struct nfnl_queue *, + struct nl_msg **); +extern int nfnl_queue_change(struct nl_sock *, + const struct nfnl_queue *); + +extern int nfnl_queue_build_delete_request(const struct nfnl_queue *, + struct nl_msg **); +extern int nfnl_queue_delete(struct nl_sock *, + const struct nfnl_queue *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/netlink/netfilter/queue_msg.h b/include/netlink/netfilter/queue_msg.h new file mode 100644 index 0000000..24ed081 --- /dev/null +++ b/include/netlink/netfilter/queue_msg.h @@ -0,0 +1,104 @@ +/* + * netlink/netfilter/queue_msg.h Netfilter Queue Messages + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + */ + +#ifndef NETLINK_QUEUE_MSG_H_ +#define NETLINK_QUEUE_MSG_H_ + +#include <netlink/netlink.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct nl_sock; +struct nlmsghdr; +struct nfnl_queue_msg; + +extern struct nl_object_ops queue_msg_obj_ops; + +/* General */ +extern struct nfnl_queue_msg * nfnl_queue_msg_alloc(void); +extern int nfnlmsg_queue_msg_parse(struct nlmsghdr *, + struct nfnl_queue_msg **); + +extern void nfnl_queue_msg_get(struct nfnl_queue_msg *); +extern void nfnl_queue_msg_put(struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_group(struct nfnl_queue_msg *, uint16_t); +extern int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *); +extern uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_family(struct nfnl_queue_msg *, uint8_t); +extern int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *); +extern uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *, uint16_t); +extern int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *); +extern uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *, uint8_t); +extern int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *); +extern uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *, + struct timeval *); +extern int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *); +extern const struct timeval * nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *, uint32_t); +extern int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *); +extern uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *); + +extern void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *, uint8_t *, int); +extern int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *); +extern const uint8_t * nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *, int *); + +extern int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *, uint8_t *, int); +extern int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *); +extern const void * nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *, int *); + +extern void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *, + unsigned int); +extern int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *); +extern unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *); + +extern struct nl_msg * nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *); +extern int nfnl_queue_msg_send_verdict(struct nl_sock *, + const struct nfnl_queue_msg *); +extern int nfnl_queue_msg_send_verdict_payload(struct nl_sock *, + const struct nfnl_queue_msg *, + const void *, unsigned ); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h index 2cdf345..1cfe220 100644 --- a/include/netlink/netlink.h +++ b/include/netlink/netlink.h @@ -20,11 +20,14 @@ #include <sys/socket.h> #include <sys/types.h> #include <sys/time.h> +#include <netdb.h> #include <netlink/netlink-compat.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <linux/genetlink.h> #include <linux/netfilter/nfnetlink.h> +#include <netlink/version.h> +#include <netlink/errno.h> #include <netlink/types.h> #include <netlink/handlers.h> #include <netlink/socket.h> @@ -33,34 +36,39 @@ extern "C" { #endif +struct ucred; + extern int nl_debug; extern struct nl_dump_params nl_debug_dp; /* Connection Management */ -extern int nl_connect(struct nl_handle *, int); -extern void nl_close(struct nl_handle *); +extern int nl_connect(struct nl_sock *, int); +extern void nl_close(struct nl_sock *); /* Send */ -extern int nl_sendto(struct nl_handle *, void *, size_t); -extern int nl_sendmsg(struct nl_handle *, struct nl_msg *, +extern int nl_sendto(struct nl_sock *, void *, size_t); +extern int nl_sendmsg(struct nl_sock *, struct nl_msg *, struct msghdr *); -extern int nl_send(struct nl_handle *, struct nl_msg *); -extern int nl_send_auto_complete(struct nl_handle *, +extern int nl_send(struct nl_sock *, struct nl_msg *); +extern int nl_send_iovec(struct nl_sock *, struct nl_msg *, + struct iovec *, unsigned); +extern void nl_auto_complete(struct nl_sock *, + struct nl_msg *); +extern int nl_send_auto_complete(struct nl_sock *, struct nl_msg *); -extern int nl_send_simple(struct nl_handle *, int, int, +extern int nl_send_simple(struct nl_sock *, int, int, void *, size_t); /* Receive */ -extern int nl_recv(struct nl_handle *, +extern int nl_recv(struct nl_sock *, struct sockaddr_nl *, unsigned char **, struct ucred **); -extern int nl_recvmsgs(struct nl_handle *, struct nl_cb *); +extern int nl_recvmsgs(struct nl_sock *, struct nl_cb *); -#define nl_recvmsgs_def(handle) nl_recvmsgs_default(handle) -extern int nl_recvmsgs_default(struct nl_handle *); +extern int nl_recvmsgs_default(struct nl_sock *); -extern int nl_wait_for_ack(struct nl_handle *); +extern int nl_wait_for_ack(struct nl_sock *); /* Netlink Family Translations */ extern char * nl_nlfamily2str(int, char *, size_t); diff --git a/include/netlink/object-api.h b/include/netlink/object-api.h index 2a32f2c..b3337f0 100644 --- a/include/netlink/object-api.h +++ b/include/netlink/object-api.h @@ -94,7 +94,6 @@ extern "C" { * struct nl_dump_params *params) * { * struct my_obj *my_obj = nl_object_priv(obj); - * int line = 1; // We will print at least one line for sure * * // It is absolutely essential to use nl_dump() when printing * // any text to make sure the dumping parameters are respected. @@ -102,14 +101,11 @@ extern "C" { * * // Before we can dump the next line, make sure to prefix * // this line correctly. - * nl_new_line(params, line++); + * nl_new_line(params); * * // You may also split a line into multiple nl_dump() calls. * nl_dump(params, "String: %s ", my_obj->my_string); * nl_dump(params, "String-2: %s\n", my_obj->another_string); - * - * // Return the number of lines dumped - * return line; * } * * struct nl_object_ops my_ops = { @@ -202,7 +198,18 @@ extern "C" { * * @return True if the attribute is available, otherwise false is returned. */ -#define AVAILABLE(A, B, ATTR) (((A)->ce_mask & (B)->ce_mask) & (ATTR)) +#define AVAILABLE(A, B, ATTR) (((A)->ce_mask & (B)->ce_mask) & (ATTR)) + +/** + * Return true if attribute is available in only one of both objects + * @arg A an object + * @arg B another object + * @arg ATTR attribute bit + * + * @return True if the attribute is available in only one of both objects, + * otherwise false is returned. + */ +#define AVAILABLE_MISMATCH(A, B, ATTR) (((A)->ce_mask ^ (B)->ce_mask) & (ATTR)) /** * Return true if attributes mismatch @@ -219,7 +226,8 @@ extern "C" { * * @return True if the attribute mismatch, or false if they match. */ -#define ATTR_MISMATCH(A, B, ATTR, EXPR) (!AVAILABLE(A, B, ATTR) || (EXPR)) +#define ATTR_MISMATCH(A, B, ATTR, EXPR) (AVAILABLE_MISMATCH(A, B, ATTR) || \ + (AVAILABLE(A, B, ATTR) && (EXPR))) /** * Return attribute bit if attribute does not match @@ -304,8 +312,8 @@ struct nl_object_ops * * The functions must return the number of lines printed. */ - int (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *, - struct nl_dump_params *); + void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *, + struct nl_dump_params *); /** * Comparison function diff --git a/include/netlink/object.h b/include/netlink/object.h index 751a1b3..ef1ed9f 100644 --- a/include/netlink/object.h +++ b/include/netlink/object.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_OBJECT_H_ @@ -27,7 +27,8 @@ struct nl_object_ops; /* General */ extern struct nl_object * nl_object_alloc(struct nl_object_ops *); -extern struct nl_object * nl_object_alloc_name(const char *); +extern int nl_object_alloc_name(const char *, + struct nl_object **); extern void nl_object_free(struct nl_object *); extern struct nl_object * nl_object_clone(struct nl_object *obj); extern void nl_object_get(struct nl_object *); @@ -55,7 +56,11 @@ extern int nl_object_is_marked(struct nl_object *); /* Access Functions */ extern int nl_object_get_refcnt(struct nl_object *); extern struct nl_cache * nl_object_get_cache(struct nl_object *); -extern inline void * nl_object_priv(struct nl_object *); +static inline void * nl_object_priv(struct nl_object *obj) +{ + return obj; +} + #ifdef __cplusplus } diff --git a/include/netlink/route/addr.h b/include/netlink/route/addr.h index 71a90e0..1381486 100644 --- a/include/netlink/route/addr.h +++ b/include/netlink/route/addr.h @@ -6,8 +6,8 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - * Baruch Even <baruch@ev-en.org>, + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>, * Mediatrix Telecom, inc. <ericb@mediatrix.com> */ @@ -26,63 +26,63 @@ struct rtnl_addr; /* General */ extern struct rtnl_addr *rtnl_addr_alloc(void); -extern void rtnl_addr_put(struct rtnl_addr *); +extern void rtnl_addr_put(struct rtnl_addr *); -extern struct nl_cache *rtnl_addr_alloc_cache(struct nl_handle *); +extern int rtnl_addr_alloc_cache(struct nl_sock *, struct nl_cache **); -/* Address Addition */ -extern struct nl_msg * rtnl_addr_build_add_request(struct rtnl_addr *, int); -extern int rtnl_addr_add(struct nl_handle *, struct rtnl_addr *, - int); +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); -/* Address Deletion */ -extern struct nl_msg * rtnl_addr_build_delete_request(struct rtnl_addr *, int); -extern int rtnl_addr_delete(struct nl_handle *, - 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); -/* Address Flags Translations */ -extern char * rtnl_addr_flags2str(int, char *, size_t); -extern int rtnl_addr_str2flags(const char *); +extern char * rtnl_addr_flags2str(int, char *, size_t); +extern int rtnl_addr_str2flags(const char *); -/* Attribute Access */ -extern void rtnl_addr_set_label(struct rtnl_addr *, const char *); -extern char * rtnl_addr_get_label(struct rtnl_addr *); +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_ifindex(struct rtnl_addr *, int); +extern int rtnl_addr_get_ifindex(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_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_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_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 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 *, +extern int rtnl_addr_set_local(struct rtnl_addr *, struct nl_addr *); -extern struct nl_addr * rtnl_addr_get_local(struct rtnl_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_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_broadcast(struct rtnl_addr *, struct nl_addr *); +extern struct nl_addr *rtnl_addr_get_broadcast(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 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_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 *); #ifdef __cplusplus } diff --git a/include/netlink/route/class-modules.h b/include/netlink/route/class-modules.h index 2400a60..74a25c9 100644 --- a/include/netlink/route/class-modules.h +++ b/include/netlink/route/class-modules.h @@ -32,8 +32,8 @@ struct rtnl_class_ops /** * Dump callbacks */ - int (*co_dump[NL_DUMP_MAX+1])(struct rtnl_class *, - struct nl_dump_params *, int); + void (*co_dump[NL_DUMP_MAX+1])(struct rtnl_class *, + struct nl_dump_params *); /** * Must return the contents supposed to be in TCA_OPTIONS diff --git a/include/netlink/route/class.h b/include/netlink/route/class.h index a624ef6..480095e 100644 --- a/include/netlink/route/class.h +++ b/include/netlink/route/class.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_CLASS_H_ @@ -24,20 +24,25 @@ struct rtnl_class; extern struct nl_object_ops class_obj_ops; -/* General */ extern struct rtnl_class * rtnl_class_alloc(void); -extern void rtnl_class_put(struct rtnl_class *); -extern struct nl_cache * rtnl_class_alloc_cache(struct nl_handle *, int); +extern void rtnl_class_put(struct rtnl_class *); +extern int rtnl_class_alloc_cache(struct nl_sock *, int, + struct nl_cache **); +extern struct rtnl_class *rtnl_class_get(struct nl_cache *, int, uint32_t); /* leaf qdisc access */ extern struct rtnl_qdisc * rtnl_class_leaf_qdisc(struct rtnl_class *, struct nl_cache *); -/* class addition */ -extern struct nl_msg * rtnl_class_build_add_request(struct rtnl_class *, int); -extern int rtnl_class_add(struct nl_handle *, struct rtnl_class *, int); +extern int rtnl_class_build_add_request(struct rtnl_class *, int, + struct nl_msg **); +extern int rtnl_class_add(struct nl_sock *, struct rtnl_class *, + int); + +extern int rtnl_class_build_delete_request(struct rtnl_class *, + struct nl_msg **); +extern int rtnl_class_delete(struct nl_sock *, struct rtnl_class *); -/* attribute modification */ extern void rtnl_class_set_ifindex(struct rtnl_class *, int); extern int rtnl_class_get_ifindex(struct rtnl_class *); extern void rtnl_class_set_handle(struct rtnl_class *, uint32_t); diff --git a/include/netlink/route/classifier-modules.h b/include/netlink/route/classifier-modules.h index 8c31e67..35cb06e 100644 --- a/include/netlink/route/classifier-modules.h +++ b/include/netlink/route/classifier-modules.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_CLASS_MODULES_H_ @@ -25,19 +25,25 @@ extern "C" { struct rtnl_cls_ops { /** - * Kind/Name of classifier + * Name of classifier module */ char co_kind[32]; + + /** + * Size of private classifier data + */ + size_t co_size; + /** * Dump callbacks */ - int (*co_dump[NL_DUMP_MAX+1])(struct rtnl_cls *, - struct nl_dump_params *, int); + void (*co_dump[NL_DUMP_MAX+1])(struct rtnl_cls *, + struct nl_dump_params *); /** * Must return the contents supposed to be in TCA_OPTIONS */ - struct nl_msg *(*co_get_opts)(struct rtnl_cls *); + int (*co_get_opts)(struct rtnl_cls *, struct nl_msg *); /** * TCA_OPTIONS message parser diff --git a/include/netlink/route/classifier.h b/include/netlink/route/classifier.h index 7ef0da4..d9c3d21 100644 --- a/include/netlink/route/classifier.h +++ b/include/netlink/route/classifier.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_CLASSIFIER_H_ @@ -23,31 +23,37 @@ extern "C" { extern struct nl_object_ops cls_obj_ops; -extern struct rtnl_cls *rtnl_cls_alloc(void); -extern void rtnl_cls_put(struct rtnl_cls *); +extern struct rtnl_cls *rtnl_cls_alloc(void); +extern void rtnl_cls_put(struct rtnl_cls *); -extern struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *, int, uint32_t); +extern int rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t, + struct nl_cache **); -/* classifier addition */ -extern int rtnl_cls_add(struct nl_handle *, struct rtnl_cls *, - int); -extern struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *, int); +extern int rtnl_cls_build_add_request(struct rtnl_cls *, int, + struct nl_msg **); +extern int rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int); -extern struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *, int); -extern struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *, int); -extern int rtnl_cls_delete(struct nl_handle *, struct rtnl_cls *, int); +extern int rtnl_cls_build_change_request(struct rtnl_cls *, int, + struct nl_msg **); +extern int rtnl_cls_build_delete_request(struct rtnl_cls *, int, + struct nl_msg **); +extern int rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *, int); -/* attribute modification */ extern void rtnl_cls_set_ifindex(struct rtnl_cls *, int); +extern int rtnl_cls_get_ifindex(struct rtnl_cls *); extern void rtnl_cls_set_handle(struct rtnl_cls *, uint32_t); extern void rtnl_cls_set_parent(struct rtnl_cls *, uint32_t); -extern void rtnl_cls_set_kind(struct rtnl_cls *, const char *); +extern uint32_t rtnl_cls_get_parent(struct rtnl_cls *); +extern int rtnl_cls_set_kind(struct rtnl_cls *, const char *); +extern struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *); -extern void rtnl_cls_set_prio(struct rtnl_cls *, int); -extern int rtnl_cls_get_prio(struct rtnl_cls *); +extern void rtnl_cls_set_prio(struct rtnl_cls *, uint16_t); +extern uint16_t rtnl_cls_get_prio(struct rtnl_cls *); -extern void rtnl_cls_set_protocol(struct rtnl_cls *, int); -extern int rtnl_cls_get_protocol(struct rtnl_cls *); +extern void rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t); +extern uint16_t rtnl_cls_get_protocol(struct rtnl_cls *); + +extern void *rtnl_cls_data(struct rtnl_cls *); #ifdef __cplusplus } diff --git a/include/netlink/route/cls/basic.h b/include/netlink/route/cls/basic.h new file mode 100644 index 0000000..7003124 --- /dev/null +++ b/include/netlink/route/cls/basic.h @@ -0,0 +1,33 @@ +/* + * netlink/route/cls/basic.h Basic Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_BASIC_H_ +#define NETLINK_BASIC_H_ + +#include <netlink/netlink.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct rtnl_cls_ops *rtnl_basic_get_ops(void); +extern int rtnl_basic_set_classid(struct rtnl_cls *, uint32_t); +extern uint32_t rtnl_basic_get_classid(struct rtnl_cls *); +extern int rtnl_basic_set_ematch(struct rtnl_cls *, + struct rtnl_ematch_tree *); +extern struct rtnl_ematch_tree * + rtnl_basic_get_ematch(struct rtnl_cls *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/cls/cgroup.h b/include/netlink/route/cls/cgroup.h new file mode 100644 index 0000000..7b0e3d3 --- /dev/null +++ b/include/netlink/route/cls/cgroup.h @@ -0,0 +1,31 @@ +/* + * netlink/route/cls/cgroup.h Control Groups Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_CLS_CGROUP_H_ +#define NETLINK_CLS_CGROUP_H_ + +#include <netlink/netlink.h> +#include <netlink/cache.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_cgroup_set_ematch(struct rtnl_cls *, + struct rtnl_ematch_tree *); +extern struct rtnl_ematch_tree * + rtnl_cgroup_get_ematch(struct rtnl_cls *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/cls/ematch.h b/include/netlink/route/cls/ematch.h new file mode 100644 index 0000000..c4292bf --- /dev/null +++ b/include/netlink/route/cls/ematch.h @@ -0,0 +1,73 @@ +/* + * netlink/route/cls/ematch.h Extended Matches + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_CLS_EMATCH_H_ +#define NETLINK_CLS_EMATCH_H_ + +#include <netlink/netlink.h> +#include <netlink/route/classifier.h> +#include <linux/pkt_cls.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_ematch; +struct rtnl_ematch_tree; + +struct rtnl_ematch_ops +{ + int eo_kind; + const char * eo_name; + size_t eo_datalen; + + int (*eo_parse)(struct rtnl_ematch *, + void *, size_t); + void (*eo_dump)(struct rtnl_ematch *, + struct nl_dump_params *); + struct nl_list_head eo_list; +}; + +extern int rtnl_ematch_register(struct rtnl_ematch_ops *); +extern int rtnl_ematch_unregister(struct rtnl_ematch_ops *); + +extern struct rtnl_ematch_ops * + rtnl_ematch_lookup_ops(int); +extern struct rtnl_ematch_ops * + rtnl_ematch_lookup_ops_name(const char *); + +extern struct rtnl_ematch * + rtnl_ematch_alloc(struct rtnl_ematch_ops *); +extern void rtnl_ematch_add_child(struct rtnl_ematch *, + struct rtnl_ematch *); +extern void rtnl_ematch_unlink(struct rtnl_ematch *); +extern void rtnl_ematch_free(struct rtnl_ematch *); + +extern void * rtnl_ematch_data(struct rtnl_ematch *); +extern void rtnl_ematch_set_flags(struct rtnl_ematch *, uint16_t); +extern void rtnl_ematch_unset_flags(struct rtnl_ematch *, uint16_t); +extern uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *); + +extern struct rtnl_ematch_tree * + rtnl_ematch_tree_alloc(uint16_t); +extern void rtnl_ematch_tree_free(struct rtnl_ematch_tree *); + +extern int rtnl_ematch_parse(struct nlattr *, struct rtnl_ematch_tree **); +extern void rtnl_ematch_tree_add_tail(struct rtnl_ematch_tree *, + struct rtnl_ematch *); +extern void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *, + struct nl_dump_params *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/cls/ematch/cmp.h b/include/netlink/route/cls/ematch/cmp.h new file mode 100644 index 0000000..b4ad03a --- /dev/null +++ b/include/netlink/route/cls/ematch/cmp.h @@ -0,0 +1,31 @@ +/* + * netlink/route/cls/ematch/cmp.h Simple Comparison + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_CLS_EMATCH_CMP_H_ +#define NETLINK_CLS_EMATCH_CMP_H_ + +#include <netlink/netlink.h> +#include <netlink/route/cls/ematch.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_ematch_cmp_set(struct rtnl_ematch *, + struct tcf_em_cmp *); +extern struct tcf_em_cmp * + rtnl_ematch_cmp_get(struct rtnl_ematch *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h index caaa792..4b630f7 100644 --- a/include/netlink/route/link.h +++ b/include/netlink/route/link.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_LINK_H_ @@ -51,116 +51,92 @@ enum rtnl_link_st { #define RTNL_LINK_STATS_MAX (__RTNL_LINK_STATS_MAX - 1) -/** - * Special interface index stating the link was not found. - * @ingroup link - */ -#define RTNL_LINK_NOT_FOUND -1 - /* link object allocation/freeage */ -extern struct rtnl_link * rtnl_link_alloc(void); -extern void rtnl_link_put(struct rtnl_link *); -extern void rtnl_link_free(struct rtnl_link *); +extern struct rtnl_link *rtnl_link_alloc(void); +extern void rtnl_link_put(struct rtnl_link *); +extern void rtnl_link_free(struct rtnl_link *); /* link cache management */ -extern struct nl_cache * rtnl_link_alloc_cache(struct nl_handle *); -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_alloc_cache(struct nl_sock *, struct nl_cache **); +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 *); -/* Link Modifications */ -extern struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *, - struct rtnl_link *, - int); -extern int rtnl_link_change(struct nl_handle *, - struct rtnl_link *, - 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); /* Name <-> Index Translations */ -extern char * rtnl_link_i2name(struct nl_cache *, int, - char *, size_t); -extern int rtnl_link_name2i(struct nl_cache *, - const char *); +extern char * rtnl_link_i2name(struct nl_cache *, int, char *, size_t); +extern int rtnl_link_name2i(struct nl_cache *, const char *); /* Name <-> Statistic Translations */ -extern char * rtnl_link_stat2str(int, char *, size_t); -extern int rtnl_link_str2stat(const char *); +extern char * rtnl_link_stat2str(int, char *, size_t); +extern int rtnl_link_str2stat(const char *); /* Link Flags Translations */ -extern char * rtnl_link_flags2str(int, char *, size_t); -extern int rtnl_link_str2flags(const char *); +extern char * rtnl_link_flags2str(int, char *, size_t); +extern int rtnl_link_str2flags(const char *); -extern char * rtnl_link_operstate2str(int, char *, size_t); -extern int rtnl_link_str2operstate(const char *); +extern char * rtnl_link_operstate2str(int, char *, size_t); +extern int rtnl_link_str2operstate(const char *); -extern char * rtnl_link_mode2str(int, char *, size_t); -extern int rtnl_link_str2mode(const char *); +extern char * rtnl_link_mode2str(int, char *, size_t); +extern int rtnl_link_str2mode(const char *); /* Access Functions */ -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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 void rtnl_link_set_linkmode(struct rtnl_link *, uint8_t); +extern uint8_t rtnl_link_get_linkmode(struct rtnl_link *); -extern uint64_t rtnl_link_get_stat(struct rtnl_link *, int); +extern uint64_t rtnl_link_get_stat(struct rtnl_link *, int); -extern int rtnl_link_set_info_type(struct rtnl_link *, - const char *); -extern char * rtnl_link_get_info_type(struct rtnl_link *); +extern int rtnl_link_set_info_type(struct rtnl_link *, const char *); +extern char * rtnl_link_get_info_type(struct rtnl_link *); #ifdef __cplusplus } diff --git a/include/netlink/route/link/info-api.h b/include/netlink/route/link/info-api.h index 2ccce9d..7e18e31 100644 --- a/include/netlink/route/link/info-api.h +++ b/include/netlink/route/link/info-api.h @@ -45,8 +45,8 @@ struct rtnl_link_info_ops /** Called when the link object is dumped. * Must dump the info type specific attributes. */ - int (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, - struct nl_dump_params *, int); + void (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, + struct nl_dump_params *); /** Called when a link object is cloned. * Must clone all info type specific attributes. */ diff --git a/include/netlink/route/neighbour.h b/include/netlink/route/neighbour.h index 078c3f4..698539a 100644 --- a/include/netlink/route/neighbour.h +++ b/include/netlink/route/neighbour.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_NEIGHBOUR_H_ @@ -22,39 +22,27 @@ extern "C" { struct rtnl_neigh; -/* neighbour object allocation/freeage */ -extern struct rtnl_neigh * rtnl_neigh_alloc(void); -extern void rtnl_neigh_put(struct rtnl_neigh *); +extern struct rtnl_neigh *rtnl_neigh_alloc(void); +extern void rtnl_neigh_put(struct rtnl_neigh *); -/* neighbour cache management */ -extern struct nl_cache * rtnl_neigh_alloc_cache(struct nl_handle *); -extern struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *, int, +extern int rtnl_neigh_alloc_cache(struct nl_sock *, struct nl_cache **); +extern struct rtnl_neigh *rtnl_neigh_get(struct nl_cache *, int, struct nl_addr *); -/* Neigbour state translations */ -extern char * rtnl_neigh_state2str(int, char *, size_t); -extern int rtnl_neigh_str2state(const char *); +extern char * rtnl_neigh_state2str(int, char *, size_t); +extern int rtnl_neigh_str2state(const char *); -/* Neighbour flags translations */ -extern char * rtnl_neigh_flags2str(int, char *, size_t); -extern int rtnl_neigh_str2flag(const char *); +extern char * rtnl_neigh_flags2str(int, char *, size_t); +extern int rtnl_neigh_str2flag(const char *); -/* Neighbour Addition */ -extern int rtnl_neigh_add(struct nl_handle *, - struct rtnl_neigh *, int); -extern struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *, int); +extern int rtnl_neigh_add(struct nl_sock *, struct rtnl_neigh *, int); +extern int rtnl_neigh_build_add_request(struct rtnl_neigh *, int, + struct nl_msg **); -/* Neighbour Modification */ -extern int rtnl_neigh_change(struct nl_handle *, - struct rtnl_neigh *, int); -extern struct nl_msg * rtnl_neigh_build_change_request(struct rtnl_neigh *, int); +extern int rtnl_neigh_delete(struct nl_sock *, struct rtnl_neigh *, int); +extern int rtnl_neigh_build_delete_request(struct rtnl_neigh *, int, + struct nl_msg **); -/* Neighbour Deletion */ -extern int rtnl_neigh_delete(struct nl_handle *, - struct rtnl_neigh *, int); -extern struct nl_msg * rtnl_neigh_build_delete_request(struct rtnl_neigh *, int); - -/* Access functions */ extern void rtnl_neigh_set_state(struct rtnl_neigh *, int); extern int rtnl_neigh_get_state(struct rtnl_neigh *); extern void rtnl_neigh_unset_state(struct rtnl_neigh *, diff --git a/include/netlink/route/neightbl.h b/include/netlink/route/neightbl.h index 20285ee..412c3e9 100644 --- a/include/netlink/route/neightbl.h +++ b/include/netlink/route/neightbl.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_NEIGHTBL_H_ @@ -25,15 +25,16 @@ struct rtnl_neightbl; extern struct rtnl_neightbl *rtnl_neightbl_alloc(void); extern void rtnl_neightbl_put(struct rtnl_neightbl *); extern void rtnl_neightbl_free(struct rtnl_neightbl *); -extern struct nl_cache *rtnl_neightbl_alloc_cache(struct nl_handle *); +extern int rtnl_neightbl_alloc_cache(struct nl_sock *, struct nl_cache **); extern struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *, const char *, int); extern void rtnl_neightbl_dump(struct rtnl_neightbl *, FILE *, struct nl_dump_params *); -extern struct nl_msg *rtnl_neightbl_build_change_request(struct rtnl_neightbl *, - struct rtnl_neightbl *); -extern int rtnl_neightbl_change(struct nl_handle *, struct rtnl_neightbl *, +extern int rtnl_neightbl_build_change_request(struct rtnl_neightbl *, + struct rtnl_neightbl *, + struct nl_msg **); +extern int rtnl_neightbl_change(struct nl_sock *, struct rtnl_neightbl *, struct rtnl_neightbl *); extern void rtnl_neightbl_set_family(struct rtnl_neightbl *, int); diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h index 984f4b5..2aa44dc 100644 --- a/include/netlink/route/nexthop.h +++ b/include/netlink/route/nexthop.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_ROUTE_NEXTHOP_H_ @@ -21,18 +21,42 @@ extern "C" { struct rtnl_nexthop; -extern struct rtnl_nexthop * rtnl_route_nh_alloc(void); -extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *); +enum { + NH_DUMP_FROM_ONELINE = -2, + NH_DUMP_FROM_DETAILS = -1, + NH_DUMP_FROM_ENV = 0, + /* > 0 reserved for nexthop index */ +}; + +extern struct rtnl_nexthop * rtnl_route_nh_alloc(void); +extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *); extern void rtnl_route_nh_free(struct rtnl_nexthop *); -extern void rtnl_route_nh_set_weight(struct rtnl_nexthop *, int); + +extern int rtnl_route_nh_compare(struct rtnl_nexthop *, + struct rtnl_nexthop *, + uint32_t, int); + +extern void rtnl_route_nh_dump(struct rtnl_nexthop *, + struct nl_dump_params *); + +extern void rtnl_route_nh_set_weight(struct rtnl_nexthop *, uint8_t); +extern uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *); extern void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *, int); +extern int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *); extern void rtnl_route_nh_set_gateway(struct rtnl_nexthop *, struct nl_addr *); +extern struct nl_addr * rtnl_route_nh_get_gateway(struct rtnl_nexthop *); extern void rtnl_route_nh_set_flags(struct rtnl_nexthop *, unsigned int); extern void rtnl_route_nh_unset_flags(struct rtnl_nexthop *, unsigned int); extern unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *); +extern void rtnl_route_nh_set_realms(struct rtnl_nexthop *, + uint32_t); +extern uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *); + +extern char * rtnl_route_nh_flags2str(int, char *, size_t); +extern int rtnl_route_nh_str2flags(const char *); #ifdef __cplusplus } diff --git a/include/netlink/route/pktloc.h b/include/netlink/route/pktloc.h new file mode 100644 index 0000000..28e1dc2 --- /dev/null +++ b/include/netlink/route/pktloc.h @@ -0,0 +1,44 @@ +/* + * netlink/route/pktloc.h Packet Location Aliasing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_PKTLOC_H_ +#define NETLINK_PKTLOC_H_ + +#include <netlink/netlink.h> +#include <netlink/cache.h> +#include <netlink/route/tc.h> + +#include <linux/tc_ematch/tc_em_cmp.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_pktloc +{ + char * name; + uint8_t align:4; + uint8_t layer:4; + uint8_t flags; + uint16_t offset; + uint32_t mask; + + struct nl_list_head list; +}; + +extern int rtnl_pktloc_lookup(const char *, struct rtnl_pktloc **); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc-modules.h b/include/netlink/route/qdisc-modules.h index 802eac4..769625e 100644 --- a/include/netlink/route/qdisc-modules.h +++ b/include/netlink/route/qdisc-modules.h @@ -32,14 +32,16 @@ struct rtnl_qdisc_ops /** * Dump callbacks */ - int (*qo_dump[NL_DUMP_MAX+1])(struct rtnl_qdisc *, - struct nl_dump_params *, int); + void (*qo_dump[NL_DUMP_MAX+1])(struct rtnl_qdisc *, + struct nl_dump_params *); /** * Must return the contents supposed to be in TCA_OPTIONS */ struct nl_msg *(*qo_get_opts)(struct rtnl_qdisc *); + int (*qo_build_msg)(struct rtnl_qdisc *, struct nl_msg *); + /** * TCA_OPTIONS message parser */ diff --git a/include/netlink/route/qdisc.h b/include/netlink/route/qdisc.h index ee71304..5acd6e1 100644 --- a/include/netlink/route/qdisc.h +++ b/include/netlink/route/qdisc.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_QDISC_H_ @@ -24,60 +24,46 @@ struct rtnl_qdisc; extern struct nl_object_ops qdisc_obj_ops; -/* General */ -extern struct rtnl_qdisc * rtnl_qdisc_alloc(void); -extern void rtnl_qdisc_put(struct rtnl_qdisc *); - -/* Cache Management */ -extern struct nl_cache * rtnl_qdisc_alloc_cache(struct nl_handle *); -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); - -/* qdisc addition */ -extern struct nl_msg * rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int); -extern int rtnl_qdisc_add(struct nl_handle *, struct rtnl_qdisc *, - int); - -/* qdisc modification */ -extern struct nl_msg * rtnl_qdisc_build_change_request(struct rtnl_qdisc *, - struct rtnl_qdisc *); -extern int rtnl_qdisc_change(struct nl_handle *, - struct rtnl_qdisc *, - struct rtnl_qdisc *); - -/* qdisc deletion */ -extern struct nl_msg * rtnl_qdisc_build_delete_request(struct rtnl_qdisc *); -extern int rtnl_qdisc_delete(struct nl_handle *, - struct rtnl_qdisc *); - -/* attribute modifications */ -extern void rtnl_qdisc_set_ifindex(struct rtnl_qdisc *, int); -extern int rtnl_qdisc_get_ifindex(struct rtnl_qdisc *); -extern void rtnl_qdisc_set_handle(struct rtnl_qdisc *, uint32_t); -extern uint32_t rtnl_qdisc_get_handle(struct rtnl_qdisc *); -extern void rtnl_qdisc_set_parent(struct rtnl_qdisc *, uint32_t); -extern uint32_t rtnl_qdisc_get_parent(struct rtnl_qdisc *); -extern void rtnl_qdisc_set_kind(struct rtnl_qdisc *, const char *); -extern char * rtnl_qdisc_get_kind(struct rtnl_qdisc *); -extern uint64_t rtnl_qdisc_get_stat(struct rtnl_qdisc *, - enum rtnl_tc_stats_id); - -/* iterators */ -extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, - struct nl_cache *, - void (*cb)(struct nl_object *, - void *), - void *); - -extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, - struct nl_cache *, - void (*cb)(struct nl_object *, - void *), - void *); - -/* qdisc specific options */ +extern struct rtnl_qdisc *rtnl_qdisc_alloc(void); +extern void rtnl_qdisc_put(struct rtnl_qdisc *); + +extern int rtnl_qdisc_alloc_cache(struct nl_sock *, struct nl_cache **); +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_change_request(struct rtnl_qdisc *, + struct rtnl_qdisc *, + struct nl_msg **); +extern int rtnl_qdisc_change(struct nl_sock *, struct rtnl_qdisc *, + struct rtnl_qdisc *); + +extern int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *, + struct nl_msg **); +extern int rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *); + +extern void rtnl_qdisc_set_ifindex(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_get_ifindex(struct rtnl_qdisc *); +extern void rtnl_qdisc_set_handle(struct rtnl_qdisc *, uint32_t); +extern uint32_t rtnl_qdisc_get_handle(struct rtnl_qdisc *); +extern void rtnl_qdisc_set_parent(struct rtnl_qdisc *, uint32_t); +extern uint32_t rtnl_qdisc_get_parent(struct rtnl_qdisc *); +extern void rtnl_qdisc_set_kind(struct rtnl_qdisc *, const char *); +extern char * rtnl_qdisc_get_kind(struct rtnl_qdisc *); +extern uint64_t rtnl_qdisc_get_stat(struct rtnl_qdisc *, enum rtnl_tc_stats_id); + +extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *, + void (*cb)(struct nl_object *, void *), + void *); + +extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *, + void (*cb)(struct nl_object *, void *), + void *); + extern struct nl_msg * rtnl_qdisc_get_opts(struct rtnl_qdisc *); #ifdef __cplusplus diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h index f59f36b..5729cd7 100644 --- a/include/netlink/route/route.h +++ b/include/netlink/route/route.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_ROUTE_H_ @@ -17,11 +17,16 @@ #include <netlink/addr.h> #include <netlink/data.h> #include <netlink/route/nexthop.h> +#include <netlink/route/rtnl.h> +#include <linux/in_route.h> #ifdef __cplusplus extern "C" { #endif +/* flags */ +#define ROUTE_CACHE_CONTENT 1 + struct rtnl_route; struct rtnl_rtcacheinfo @@ -38,85 +43,79 @@ struct rtnl_rtcacheinfo extern struct nl_object_ops route_obj_ops; -/* General */ extern struct rtnl_route * rtnl_route_alloc(void); -extern void rtnl_route_put(struct rtnl_route *); -extern struct nl_cache * rtnl_route_alloc_cache(struct nl_handle *); - -extern void rtnl_route_get(struct rtnl_route *); -extern void rtnl_route_put(struct rtnl_route *); - -extern struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *, int); -extern int rtnl_route_add(struct nl_handle *, struct rtnl_route *, int); -extern struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *, int); -extern int rtnl_route_del(struct nl_handle *, struct rtnl_route *, int); - -extern void rtnl_route_set_table(struct rtnl_route *, int); -extern int rtnl_route_get_table(struct rtnl_route *); -extern void rtnl_route_set_scope(struct rtnl_route *, int); -extern int rtnl_route_get_scope(struct rtnl_route *); -extern void rtnl_route_set_tos(struct rtnl_route *, int); -extern int rtnl_route_get_tos(struct rtnl_route *); -extern void rtnl_route_set_realms(struct rtnl_route *, realm_t); -extern realm_t rtnl_route_get_realms(struct rtnl_route *); -extern void rtnl_route_set_protocol(struct rtnl_route *, int); -extern int rtnl_route_get_protocol(struct rtnl_route *); -extern void rtnl_route_set_prio(struct rtnl_route *, int); -extern int rtnl_route_get_prio(struct rtnl_route *); -extern void rtnl_route_set_family(struct rtnl_route *, int); -extern int rtnl_route_get_family(struct rtnl_route *); -extern void rtnl_route_set_type(struct rtnl_route *, int); -extern int rtnl_route_get_type(struct rtnl_route *); -extern void rtnl_route_set_flags(struct rtnl_route *, - unsigned int); -extern void rtnl_route_unset_flags(struct rtnl_route *, - unsigned int); -extern unsigned int rtnl_route_get_flags(struct rtnl_route *); -extern int rtnl_route_set_metric(struct rtnl_route *, int, - unsigned int); -extern int rtnl_route_unset_metric(struct rtnl_route *, int); -extern unsigned int rtnl_route_get_metric(struct rtnl_route *, int); -extern int rtnl_route_set_dst(struct rtnl_route *, - struct nl_addr *); -extern struct nl_addr * rtnl_route_get_dst(struct rtnl_route *); -extern int rtnl_route_set_src(struct rtnl_route *, - struct nl_addr *); -extern struct nl_addr * rtnl_route_get_src(struct rtnl_route *); -extern int rtnl_route_set_gateway(struct rtnl_route *, - struct nl_addr *); -extern struct nl_addr * rtnl_route_get_gateway(struct rtnl_route *); -extern int rtnl_route_set_pref_src(struct rtnl_route *, - struct nl_addr *); -extern struct nl_addr * rtnl_route_get_pref_src(struct rtnl_route *); -extern void rtnl_route_set_oif(struct rtnl_route *, int); -extern int rtnl_route_get_oif(struct rtnl_route *); -extern void rtnl_route_set_iif(struct rtnl_route *, const char *); -extern char * rtnl_route_get_iif(struct rtnl_route *); -extern int rtnl_route_get_dst_len(struct rtnl_route *); -extern int rtnl_route_get_src_len(struct rtnl_route *); - -extern void rtnl_route_add_nexthop(struct rtnl_route *, - struct rtnl_nexthop *); -extern void rtnl_route_remove_nexthop(struct rtnl_nexthop *); -extern struct nl_list_head * rtnl_route_get_nexthops(struct rtnl_route *); -extern void rtnl_route_set_cacheinfo(struct rtnl_route *, - struct rtnl_rtcacheinfo *); -extern uint32_t rtnl_route_get_mp_algo(struct rtnl_route *); -extern void rtnl_route_set_mp_algo(struct rtnl_route *, uint32_t); - -extern char * rtnl_route_table2str(int, char *, size_t); -extern int rtnl_route_str2table(const char *); -extern int rtnl_route_read_table_names(const char *); - -extern char * rtnl_route_proto2str(int, char *, size_t); -extern int rtnl_route_str2proto(const char *); -extern int rtnl_route_read_protocol_names(const char *); - -extern char * rtnl_route_metric2str(int, char *, size_t); -extern int rtnl_route_str2metric(const char *); - -extern char * rtnl_route_nh_flags2str(int, char *, size_t); -extern int rtnl_route_nh_str2flags(const char *); +extern void rtnl_route_put(struct rtnl_route *); +extern int rtnl_route_alloc_cache(struct nl_sock *, int, int, + struct nl_cache **); + +extern void rtnl_route_get(struct rtnl_route *); +extern void rtnl_route_put(struct rtnl_route *); + +extern int rtnl_route_parse(struct nlmsghdr *, struct rtnl_route **); +extern int rtnl_route_build_msg(struct nl_msg *, struct rtnl_route *); + +extern int rtnl_route_build_add_request(struct rtnl_route *, int, + struct nl_msg **); +extern int rtnl_route_add(struct nl_sock *, struct rtnl_route *, int); +extern int rtnl_route_build_del_request(struct rtnl_route *, int, + struct nl_msg **); +extern int rtnl_route_delete(struct nl_sock *, struct rtnl_route *, int); + +extern void rtnl_route_set_table(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_table(struct rtnl_route *); +extern void rtnl_route_set_scope(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_scope(struct rtnl_route *); +extern void rtnl_route_set_tos(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_tos(struct rtnl_route *); +extern void rtnl_route_set_protocol(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_protocol(struct rtnl_route *); +extern void rtnl_route_set_priority(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_priority(struct rtnl_route *); +extern int rtnl_route_set_family(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_family(struct rtnl_route *); +extern int rtnl_route_set_type(struct rtnl_route *, uint8_t); +extern uint8_t rtnl_route_get_type(struct rtnl_route *); +extern void rtnl_route_set_flags(struct rtnl_route *, uint32_t); +extern void rtnl_route_unset_flags(struct rtnl_route *, uint32_t); +extern uint32_t rtnl_route_get_flags(struct rtnl_route *); +extern int rtnl_route_set_metric(struct rtnl_route *, int, unsigned int); +extern int rtnl_route_unset_metric(struct rtnl_route *, int); +extern int rtnl_route_get_metric(struct rtnl_route *, int, uint32_t *); +extern int rtnl_route_set_dst(struct rtnl_route *, struct nl_addr *); +extern struct nl_addr *rtnl_route_get_dst(struct rtnl_route *); +extern int rtnl_route_set_src(struct rtnl_route *, struct nl_addr *); +extern struct nl_addr *rtnl_route_get_src(struct rtnl_route *); +extern int rtnl_route_set_pref_src(struct rtnl_route *, struct nl_addr *); +extern struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *); +extern void rtnl_route_set_iif(struct rtnl_route *, int); +extern int rtnl_route_get_iif(struct rtnl_route *); +extern int rtnl_route_get_src_len(struct rtnl_route *); + +extern void rtnl_route_add_nexthop(struct rtnl_route *, + struct rtnl_nexthop *); +extern void rtnl_route_remove_nexthop(struct rtnl_route *, + struct rtnl_nexthop *); +extern struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *); +extern int rtnl_route_get_nnexthops(struct rtnl_route *); + +extern void rtnl_route_foreach_nexthop(struct rtnl_route *r, + void (*cb)(struct rtnl_nexthop *, void *), + void *arg); + +extern struct rtnl_nexthop * rtnl_route_nexthop_n(struct rtnl_route *r, int n); + +extern int rtnl_route_guess_scope(struct rtnl_route *); + +extern char * rtnl_route_table2str(int, char *, size_t); +extern int rtnl_route_str2table(const char *); +extern int rtnl_route_read_table_names(const char *); + +extern char * rtnl_route_proto2str(int, char *, size_t); +extern int rtnl_route_str2proto(const char *); +extern int rtnl_route_read_protocol_names(const char *); + +extern char * rtnl_route_metric2str(int, char *, size_t); +extern int rtnl_route_str2metric(const char *); #ifdef __cplusplus } diff --git a/include/netlink/route/rtnl.h b/include/netlink/route/rtnl.h index 9d116cd..f551a5d 100644 --- a/include/netlink/route/rtnl.h +++ b/include/netlink/route/rtnl.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_RTNL_H_ @@ -23,8 +23,6 @@ extern "C" { * @{ */ -typedef uint32_t realm_t; - /** * Mask specying the size of each realm part * @ingroup rtnl @@ -51,7 +49,7 @@ typedef uint32_t realm_t; /* General */ -extern int nl_rtgen_request(struct nl_handle *, int, int, int); +extern int nl_rtgen_request(struct nl_sock *, int, int, int); /* Routing Type Translations */ extern char * nl_rtntype2str(int, char *, size_t); diff --git a/include/netlink/route/rule.h b/include/netlink/route/rule.h index d295b0d..928dc0f 100644 --- a/include/netlink/route/rule.h +++ b/include/netlink/route/rule.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_RULE_H_ @@ -27,15 +27,16 @@ struct rtnl_rule; extern struct rtnl_rule * rtnl_rule_alloc(void); extern void rtnl_rule_put(struct rtnl_rule *); -extern struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *); -extern struct nl_cache * rtnl_rule_alloc_cache_by_family(struct nl_handle *, - int); +extern int rtnl_rule_alloc_cache(struct nl_sock *, int, + struct nl_cache **); extern void rtnl_rule_dump(struct rtnl_rule *, FILE *, struct nl_dump_params *); -extern struct nl_msg * rtnl_rule_build_add_request(struct rtnl_rule *, int); -extern int rtnl_rule_add(struct nl_handle *, struct rtnl_rule *, int); -extern struct nl_msg * rtnl_rule_build_delete_request(struct rtnl_rule *, int); -extern int rtnl_rule_delete(struct nl_handle *, struct rtnl_rule *, int); +extern int rtnl_rule_build_add_request(struct rtnl_rule *, int, + struct nl_msg **); +extern int rtnl_rule_add(struct nl_sock *, struct rtnl_rule *, int); +extern int rtnl_rule_build_delete_request(struct rtnl_rule *, int, + struct nl_msg **); +extern int rtnl_rule_delete(struct nl_sock *, struct rtnl_rule *, int); /* attribute modification */ @@ -43,9 +44,7 @@ extern void rtnl_rule_set_family(struct rtnl_rule *, int); extern int rtnl_rule_get_family(struct rtnl_rule *); extern void rtnl_rule_set_prio(struct rtnl_rule *, int); extern int rtnl_rule_get_prio(struct rtnl_rule *); -#define rtnl_rule_set_fwmark(ptr, n) rtnl_rule_set_mark(ptr, n) extern void rtnl_rule_set_mark(struct rtnl_rule *, uint64_t); -#define rtnl_rule_get_fwmark(ptr) rtnl_rule_get_mark(ptr) extern uint64_t rtnl_rule_get_mark(struct rtnl_rule *); extern void rtnl_rule_set_table(struct rtnl_rule *, int); extern int rtnl_rule_get_table(struct rtnl_rule *); @@ -69,8 +68,8 @@ extern char * rtnl_rule_get_iif(struct rtnl_rule *); extern void rtnl_rule_set_classid(struct rtnl_rule *, uint32_t); extern uint32_t rtnl_rule_get_classid(struct rtnl_rule *); -extern void rtnl_rule_set_realms(struct rtnl_rule *, realm_t); -extern realm_t rtnl_rule_get_realms(struct rtnl_rule *); +extern void rtnl_rule_set_realms(struct rtnl_rule *, uint32_t); +extern uint32_t rtnl_rule_get_realms(struct rtnl_rule *); #ifdef __cplusplus } diff --git a/include/netlink/route/sch/htb.h b/include/netlink/route/sch/htb.h index 5d4d681..d44f039 100644 --- a/include/netlink/route/sch/htb.h +++ b/include/netlink/route/sch/htb.h @@ -30,9 +30,9 @@ extern void rtnl_htb_set_rate(struct rtnl_class *, uint32_t); extern void rtnl_htb_set_ceil(struct rtnl_class *, uint32_t); extern void rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t); extern void rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t); -extern void rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum); -extern void rtnl_htb_set_overhead(struct rtnl_class *class, uint8_t overhead); -extern void rtnl_htb_set_mpu(struct rtnl_class *class, uint8_t mpu); +extern void rtnl_htb_set_quantum(struct rtnl_class *, uint32_t quantum); +extern void rtnl_htb_set_overhead(struct rtnl_class *, uint8_t overhead); +extern void rtnl_htb_set_mpu(struct rtnl_class *, uint8_t mpu); #ifdef __cplusplus } diff --git a/include/netlink/route/sch/netem.h b/include/netlink/route/sch/netem.h index b100741..c293777 100644 --- a/include/netlink/route/sch/netem.h +++ b/include/netlink/route/sch/netem.h @@ -31,6 +31,13 @@ extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *); extern int rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *); +/* Corruption */ +extern int rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *); + +extern int rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *); + /* Packet Loss */ extern int rtnl_netem_set_loss(struct rtnl_qdisc *, int); extern int rtnl_netem_get_loss(struct rtnl_qdisc *); @@ -55,6 +62,12 @@ extern int rtnl_netem_get_jitter(struct rtnl_qdisc *); extern int rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *); +/* Delay Distribution */ +#define MAXDIST 65536 +extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *); +extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *); +extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **); + #ifdef __cplusplus } #endif diff --git a/include/netlink/socket.h b/include/netlink/socket.h index 038df7a..7e71aed 100644 --- a/include/netlink/socket.h +++ b/include/netlink/socket.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_SOCKET_H_ @@ -19,45 +19,45 @@ extern "C" { #endif -extern struct nl_handle * nl_handle_alloc(void); -extern struct nl_handle * nl_handle_alloc_cb(struct nl_cb *); -extern void nl_handle_destroy(struct nl_handle *); +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(struct nl_handle *); -extern void nl_socket_set_local_port(struct nl_handle *, - uint32_t); +extern uint32_t nl_socket_get_local_port(struct nl_sock *); +extern void nl_socket_set_local_port(struct nl_sock *, uint32_t); -extern int nl_socket_add_membership(struct nl_handle *, - int); -extern int nl_socket_drop_membership(struct nl_handle *, +extern int nl_socket_add_memberships(struct nl_sock *, int, ...); +extern int nl_socket_add_membership(struct nl_sock *, int); +extern int nl_socket_drop_memberships(struct nl_sock *, int, ...); +extern int nl_socket_drop_membership(struct nl_sock *, int); -extern void nl_join_groups(struct nl_handle *, int); +extern void nl_join_groups(struct nl_sock *, int); -extern uint32_t nl_socket_get_peer_port(struct nl_handle *); -extern void nl_socket_set_peer_port(struct nl_handle *, + +extern uint32_t nl_socket_get_peer_port(struct nl_sock *); +extern void nl_socket_set_peer_port(struct nl_sock *, uint32_t); -extern struct nl_cb * nl_socket_get_cb(struct nl_handle *); -extern void nl_socket_set_cb(struct nl_handle *, +extern struct nl_cb * nl_socket_get_cb(struct nl_sock *); +extern void nl_socket_set_cb(struct nl_sock *, struct nl_cb *); -extern int nl_socket_modify_cb(struct nl_handle *, - enum nl_cb_type, - enum nl_cb_kind, - nl_recvmsg_msg_cb_t, - void *); +extern int nl_socket_modify_cb(struct nl_sock *, enum nl_cb_type, + enum nl_cb_kind, + nl_recvmsg_msg_cb_t, void *); -extern int nl_set_buffer_size(struct nl_handle *, - int, int); -extern int nl_set_passcred(struct nl_handle *, int); -extern int nl_socket_recv_pktinfo(struct nl_handle *, int); +extern int nl_socket_set_buffer_size(struct nl_sock *, int, int); +extern int nl_socket_set_passcred(struct nl_sock *, int); +extern int nl_socket_recv_pktinfo(struct nl_sock *, int); -extern void nl_disable_sequence_check(struct nl_handle *); -extern unsigned int nl_socket_use_seq(struct nl_handle *); +extern void nl_socket_disable_seq_check(struct nl_sock *); +extern unsigned int nl_socket_use_seq(struct nl_sock *); +extern void nl_socket_disable_auto_ack(struct nl_sock *); +extern void nl_socket_enable_auto_ack(struct nl_sock *); -extern int nl_socket_get_fd(struct nl_handle *); -extern int nl_socket_set_nonblocking(struct nl_handle *); -extern void nl_socket_enable_msg_peek(struct nl_handle *); -extern void nl_socket_disable_msg_peek(struct nl_handle *); +extern int nl_socket_get_fd(struct nl_sock *); +extern int nl_socket_set_nonblocking(struct nl_sock *); +extern void nl_socket_enable_msg_peek(struct nl_sock *); +extern void nl_socket_disable_msg_peek(struct nl_sock *); #ifdef __cplusplus } diff --git a/include/netlink/types.h b/include/netlink/types.h index 903028e..2e0b9c3 100644 --- a/include/netlink/types.h +++ b/include/netlink/types.h @@ -19,12 +19,10 @@ * @ingroup utils */ enum nl_dump_type { - NL_DUMP_BRIEF, /**< Dump object in a brief one-liner */ - NL_DUMP_FULL, /**< Dump all attributes but no statistics */ + 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_XML, /**< Dump all attribtes in XML format */ NL_DUMP_ENV, /**< Dump all attribtues as env variables */ - NL_DUMP_EVENTS, /**< Dump event */ __NL_DUMP_MAX, }; #define NL_DUMP_MAX (__NL_DUMP_MAX - 1) @@ -100,6 +98,14 @@ struct nl_dump_params * 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; }; #endif diff --git a/include/netlink/utils.h b/include/netlink/utils.h index 0351d38..480bab6 100644 --- a/include/netlink/utils.h +++ b/include/netlink/utils.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #ifndef NETLINK_UTILS_H_ @@ -38,10 +38,6 @@ extern "C" { /** @} */ -extern char * nl_geterror(void); -extern int nl_get_errno(void); -extern void nl_perror(const char *); - /* unit pretty-printing */ extern double nl_cancel_down_bytes(unsigned long long, char **); extern double nl_cancel_down_bits(unsigned long long, char **); @@ -55,6 +51,7 @@ extern long nl_prob2int(const char *); extern int nl_get_hz(void); extern uint32_t nl_us2ticks(uint32_t); extern uint32_t nl_ticks2us(uint32_t); +extern int nl_str2msec(const char *, uint64_t *); extern char * nl_msec2str(uint64_t, char *, size_t); /* link layer protocol translations */ @@ -70,9 +67,9 @@ extern char * nl_ip_proto2str(int, char *, size_t); extern int nl_str2ip_proto(const char *); /* Dumping helpers */ -extern void nl_new_line(struct nl_dump_params *, int); +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 *, int, const char *, ...); +extern void nl_dump_line(struct nl_dump_params *, const char *, ...); #ifdef __cplusplus } diff --git a/include/netlink/version.h b/include/netlink/version.h new file mode 100644 index 0000000..84af8f3 --- /dev/null +++ b/include/netlink/version.h @@ -0,0 +1,18 @@ +/* + * netlink/version.h Compile Time Versioning Information + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_VERSION_H_ +#define NETLINK_VERSION_H_ + +#define LIBNL_STRING "libnl 2.0" +#define LIBNL_VERSION "2.0" + +#endif diff --git a/include/netlink/version.h.in b/include/netlink/version.h.in new file mode 100644 index 0000000..7bd38cc --- /dev/null +++ b/include/netlink/version.h.in @@ -0,0 +1,18 @@ +/* + * netlink/version.h Compile Time Versioning Information + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef NETLINK_VERSION_H_ +#define NETLINK_VERSION_H_ + +#define LIBNL_STRING "@PACKAGE_STRING@" +#define LIBNL_VERSION "@PACKAGE_VERSION@" + +#endif diff --git a/install-sh b/install-sh deleted file mode 100755 index 6ce63b9..0000000 --- a/install-sh +++ /dev/null @@ -1,294 +0,0 @@ -#!/bin/sh -# -# install - install a program, script, or datafile -# -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. It can only install one file at a time, a restriction -# shared with many OS's install programs. - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -transformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd=$cpprog - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd=$stripprog - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "$0: no input file specified" >&2 - exit 1 -else - : -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d "$dst" ]; then - instcmd=: - chmodcmd="" - else - instcmd=$mkdirprog - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f "$src" ] || [ -d "$src" ] - then - : - else - echo "$0: $src does not exist" >&2 - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "$0: no destination specified" >&2 - exit 1 - else - : - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d "$dst" ] - then - dst=$dst/`basename "$src"` - else - : - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' - ' -IFS="${IFS-$defaultIFS}" - -oIFS=$IFS -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS=$oIFS - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp=$pathcomp$1 - shift - - if [ ! -d "$pathcomp" ] ; - then - $mkdirprog "$pathcomp" - else - : - fi - - pathcomp=$pathcomp/ -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd "$dst" && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename "$dst"` - else - dstfile=`basename "$dst" $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename "$dst"` - else - : - fi - -# Make a couple of temp file names in the proper directory. - - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - -# Trap to clean up temp files at exit. - - trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 - trap '(exit $?); exit' 1 2 13 15 - -# Move or copy the file name to the temp name - - $doit $instcmd "$src" "$dsttmp" && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && - -# Now remove or move aside any old file at destination location. We try this -# two ways since rm can't unlink itself on some systems and the destination -# file might be busy for other reasons. In this case, the final cleanup -# might fail but the new file should still install successfully. - -{ - if [ -f "$dstdir/$dstfile" ] - then - $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || - $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || - { - echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 - (exit 1); exit - } - else - : - fi -} && - -# Now rename the file to the real destination. - - $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" - -fi && - -# The final little trick to "correctly" pass the exit status to the exit trap. - -{ - (exit 0); exit -} diff --git a/lib/.gitignore b/lib/.gitignore index f4bf2cd..2a450e8 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1 +1,2 @@ libnl.so* +libnl-*.so* diff --git a/lib/Makefile b/lib/Makefile deleted file mode 100644 index 0bf8af7..0000000 --- a/lib/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -# -# lib/Makefile -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),) - include ../Makefile.opts -endif - -# Core -CIN := $(wildcard *.c) -# NETLINK_ROUTE -CIN += $(wildcard route/*.c) -# Schedulers -CIN += $(wildcard route/sch/*.c) -# Classifiers -CIN += $(wildcard route/cls/*.c) -# Link Info Modules -CIN += $(wildcard route/link/*.c) -# NETLINK_GENERIC -CIN += $(wildcard genl/*.c) -# fib lookup -CIN += $(wildcard fib_lookup/*.c) -# Netfilter -CIN += $(wildcard netfilter/*.c) - -DEPS := $(CIN:%.c=%.d) -OBJ := $(CIN:%.c=%.o) -CFLAGS += -fPIC -OUT_SLIB := $(PACKAGE_NAME).so.$(PACKAGE_VERSION) -LN_SLIB := $(PACKAGE_NAME).so -LN1_SLIB := $(LN_SLIB).1 - -export - -.PHONY: all clean install librtn.a $(OUT_SLIB) - - -all: - @echo " MAKE $(OUT_SLIB)"; \ - $(MAKE) $(OUT_SLIB) - -$(OUT_SLIB): ../Makefile.opts $(OBJ) - @echo " LD $(OUT_SLIB)"; \ - $(CC) -shared -Wl,-soname,libnl.so.1 -o $(OUT_SLIB) $(OBJ) $(LIBNL_LIB) -lc - @echo " LN $(OUT_SLIB) $(LN1_SLIB)"; \ - rm -f $(LN1_SLIB) ; $(LN) -s $(OUT_SLIB) $(LN1_SLIB) - @echo " LN $(LN1_SLIB) $(LN_SLIB)"; \ - rm -f $(LN_SLIB) ; $(LN) -s $(LN1_SLIB) $(LN_SLIB) - -clean: - @echo " CLEAN lib"; \ - $(RM) -f $(OBJ) $(OUT_SLIB) $(LN_SLIB) $(LN1_SLIB); \ - $(RM) -f $(DEPS) $(OUT_SLIB) $(LN_SLIB) $(LN1_SLIB) - -distclean: - @echo " DISTCLEAN lib"; \ - $(RM) -f $(DEPS) - -install: - mkdir -p $(DESTDIR)$(libdir)/ - install -m 0644 $(OUT_SLIB) $(DESTDIR)$(libdir) - rm -f $(DESTDIR)$(libdir)/$(LN1_SLIB) - $(LN) -s $(OUT_SLIB) $(DESTDIR)$(libdir)/$(LN1_SLIB) - rm -f $(DESTDIR)$(libdir)/$(LN_SLIB) - $(LN) -s $(LN1_SLIB) $(DESTDIR)$(libdir)/$(LN_SLIB) - -$(DEPS): ../Makefile.opts - -include ../Makefile.rules diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..92a916e --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,57 @@ +# -*- Makefile -*- + +AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\" + +lib_LTLIBRARIES = \ + libnl.la libnl-genl.la libnl-route.la libnl-nf.la + +libnl_la_LDFLAGS = -version-info 2:0:0 +libnl_la_SOURCES = \ + addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c doc.c \ + error.c handlers.c msg.c nl.c object.c socket.c utils.c + +libnl_genl_la_LDFLAGS = -version-info 2:0:0 +libnl_genl_la_LIBADD = libnl.la +libnl_genl_la_SOURCES = \ + genl/ctrl.c genl/family.c genl/genl.c genl/mngt.c + +libnl_nf_la_LDFLAGS = -version-info 2:0:0 +libnl_nf_la_LIBADD = libnl-route.la +libnl_nf_la_SOURCES = \ + netfilter/ct.c netfilter/ct_obj.c netfilter/log.c \ + netfilter/log_msg.c netfilter/log_msg_obj.c netfilter/log_obj.c \ + netfilter/netfilter.c netfilter/nfnl.c netfilter/queue.c \ + netfilter/queue_msg.c netfilter/queue_msg_obj.c netfilter/queue_obj.c + +CLEANFILES = \ + route/pktloc_grammar.c route/pktloc_grammar.h \ + route/pktloc_syntax.c route/pktloc_syntax.h + +# Hack to avoid using ylwrap. It does not function correctly in combination +# with --header-file= +route/pktloc_grammar.c: route/pktloc_grammar.l + $(LEX) --header-file=route/pktloc_grammar.h $(LFLAGS) -o $@ $^ + +route/pktloc_syntax.c: route/pktloc_syntax.y + $(YACC) -d $(YFLAGS) -o $@ $^ + +libnl_route_la_LDFLAGS = -version-info 2:0:0 +libnl_route_la_LIBADD = libnl.la +libnl_route_la_SOURCES = \ + route/addr.c route/class.c route/class_api.c route/class_obj.c \ + route/cls.c route/cls_api.c route/cls_obj.c route/link.c \ + route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \ + route/qdisc_api.c route/qdisc_obj.c route/route.c route/route_obj.c \ + route/route_utils.c route/rtnl.c route/rule.c route/tc.c \ + \ + route/cls/fw.c route/cls/police.c route/cls/u32.c \ + \ + route/link/api.c route/link/vlan.c \ + \ + route/sch/blackhole.c route/sch/cbq.c route/sch/dsmark.c \ + route/sch/fifo.c route/sch/htb.c route/sch/netem.c route/sch/prio.c \ + route/sch/red.c route/sch/sfq.c route/sch/tbf.c \ + \ + fib_lookup/lookup.c fib_lookup/request.c \ + \ + route/pktloc_syntax.c route/pktloc_grammar.c route/pktloc.c @@ -6,11 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup utils + * @ingroup core * @defgroup addr Abstract Address * * @par 1) Transform character string to abstract address @@ -140,11 +140,11 @@ static inline int dnet_pton(const char *src, char *addrbuf) pos = dnet_num(src, &area); if ((pos == 0) || (area > 63) || ((*(src + pos) != '.') && (*(src + pos) != ','))) - return -EINVAL; + return -NLE_INVAL; pos = dnet_num(src + pos + 1, &node); if ((pos == 0) || (node > 1023)) - return -EINVAL; + return -NLE_INVAL; *(uint16_t *)addrbuf = dn_ntohs((area << 10) | node); @@ -166,10 +166,8 @@ struct nl_addr *nl_addr_alloc(size_t maxsize) struct nl_addr *addr; addr = calloc(1, sizeof(*addr) + maxsize); - if (!addr) { - nl_errno(ENOMEM); + if (!addr) return NULL; - } addr->a_refcnt = 1; addr->a_maxsize = maxsize; @@ -203,9 +201,25 @@ struct nl_addr *nl_addr_build(int family, void *buf, size_t size) } /** + * Allocate abstract address based on netlink attribute. + * @arg nla Netlink attribute of unspecific type. + * @arg family Address family. + * + * Considers the netlink attribute payload a address of the specified + * family and allocates a new abstract address based on it. + * + * @return Newly allocated address handle or NULL. + */ +struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family) +{ + return nl_addr_build(family, nla_data(nla), nla_len(nla)); +} + +/** * Allocate abstract address object based on a character string * @arg addrstr Address represented as character string. * @arg hint Address family hint or AF_UNSPEC. + * @arg result Pointer to store resulting address. * * Regognizes the following address formats: *@code @@ -226,9 +240,9 @@ struct nl_addr *nl_addr_build(int family, void *buf, size_t size) * The prefix length may be appened at the end prefixed with a * slash, e.g. 10.0.0.0/8. * - * @return Newly allocated abstract address object or NULL. + * @return 0 on success or a negative error code. */ -struct nl_addr *nl_addr_parse(const char *addrstr, int hint) +int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result) { int err, copy = 0, len = 0, family = AF_UNSPEC; char *str, *prefix, buf[32]; @@ -236,7 +250,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) str = strdup(addrstr); if (!str) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -274,8 +288,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) goto prefix; default: - err = nl_error(EINVAL, "Unsuported address" \ - "family for default address"); + err = -NLE_AF_NOSUPPORT; goto errout; } } @@ -289,7 +302,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) goto prefix; } if (hint == AF_INET) { - err = nl_error(EINVAL, "Invalid IPv4 address"); + err = -NLE_NOADDR; goto errout; } } @@ -301,7 +314,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) goto prefix; } if (hint == AF_INET6) { - err = nl_error(EINVAL, "Invalid IPv6 address"); + err = -NLE_NOADDR; goto errout; } } @@ -323,7 +336,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) } if (hint == AF_LLC) { - err = nl_error(EINVAL, "Invalid link layer address"); + err = -NLE_NOADDR; goto errout; } } @@ -336,7 +349,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) goto prefix; } if (hint == AF_DECnet) { - err = nl_error(EINVAL, "Invalid DECnet address"); + err = -NLE_NOADDR; goto errout; } } @@ -348,7 +361,7 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) long l = strtol(s, &p, 16); if (s == p || l > 0xff || i >= sizeof(buf)) { - err = -EINVAL; + err = -NLE_INVAL; goto errout; } @@ -363,13 +376,13 @@ struct nl_addr *nl_addr_parse(const char *addrstr, int hint) goto prefix; } - err = nl_error(EINVAL, "Invalid address"); + err = -NLE_NOADDR; goto errout; prefix: addr = nl_addr_alloc(len); if (!addr) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -383,18 +396,19 @@ prefix: long pl = strtol(++prefix, &p, 0); if (p == prefix) { nl_addr_destroy(addr); - err = -EINVAL; + err = -NLE_INVAL; goto errout; } nl_addr_set_prefixlen(addr, pl); } else nl_addr_set_prefixlen(addr, len * 8); + *result = addr; err = 0; errout: free(str); - return err ? NULL : addr; + return err; } /** @@ -619,7 +633,7 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, struct sockaddr_in *sai = (struct sockaddr_in *) sa; if (*salen < sizeof(*sai)) - return -EINVAL; + return -NLE_INVAL; sai->sin_family = addr->a_family; memcpy(&sai->sin_addr, addr->a_addr, 4); @@ -631,7 +645,7 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa; if (*salen < sizeof(*sa6)) - return -EINVAL; + return -NLE_INVAL; sa6->sin6_family = addr->a_family; memcpy(&sa6->sin6_addr, addr->a_addr, 16); @@ -640,7 +654,7 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, break; default: - return -EINVAL; + return -NLE_INVAL; } return 0; @@ -657,6 +671,7 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, /** * Call getaddrinfo() for an abstract address object. * @arg addr Abstract address object. + * @arg result Pointer to store resulting address list. * * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST * mode. @@ -664,13 +679,11 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa, * @note The caller is responsible for freeing the linked list using the * interface provided by getaddrinfo(3). * - * @return A linked list of addrinfo handles or NULL with an error message - * associated. + * @return 0 on success or a negative error code. */ -struct addrinfo *nl_addr_info(struct nl_addr *addr) +int nl_addr_info(struct nl_addr *addr, struct addrinfo **result) { int err; - struct addrinfo *res; char buf[INET6_ADDRSTRLEN+5]; struct addrinfo hint = { .ai_flags = AI_NUMERICHOST, @@ -679,13 +692,24 @@ struct addrinfo *nl_addr_info(struct nl_addr *addr) nl_addr2str(addr, buf, sizeof(buf)); - err = getaddrinfo(buf, NULL, &hint, &res); + err = getaddrinfo(buf, NULL, &hint, result); if (err != 0) { - nl_error(err, gai_strerror(err)); - return NULL; + switch (err) { + case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT; + case EAI_AGAIN: return -NLE_AGAIN; + case EAI_BADFLAGS: return -NLE_INVAL; + case EAI_FAIL: return -NLE_NOADDR; + case EAI_FAMILY: return -NLE_AF_NOSUPPORT; + case EAI_MEMORY: return -NLE_NOMEM; + case EAI_NODATA: return -NLE_NOADDR; + case EAI_NONAME: return -NLE_OBJ_NOTFOUND; + case EAI_SERVICE: return -NLE_OPNOTSUPP; + case EAI_SOCKTYPE: return -NLE_BAD_SOCK; + default: return -NLE_FAILURE; + } } - return res; + return 0; } /** @@ -711,8 +735,12 @@ int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen) if (err < 0) return err; - return getnameinfo((struct sockaddr *) &buf, salen, - host, hostlen, NULL, 0, NI_NAMEREQD); + err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen, + NULL, 0, NI_NAMEREQD); + if (err < 0) + return nl_syserr2nlerr(err); + + return 0; } /** @} */ @@ -741,7 +769,7 @@ int nl_addr_get_family(struct nl_addr *addr) int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len) { if (len > addr->a_maxsize) - return -ERANGE; + return -NLE_RANGE; addr->a_len = len; memcpy(addr->a_addr, buf, len); @@ -804,9 +832,12 @@ char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size) int i; char tmp[16]; - if (!addr->a_len) { + if (!addr || !addr->a_len) { snprintf(buf, size, "none"); - goto prefix; + if (addr) + goto prefix; + else + return buf; } switch (addr->a_family) { @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #include <netlink-local.h> @@ -21,89 +21,376 @@ * @ingroup msg * @defgroup attr Attributes * Netlink Attributes Construction/Parsing Interface - * @par 0) Introduction - * Netlink attributes are chained together following each other: + * + * \section attr_sec Netlink Attributes + * Netlink attributes allow for data chunks of arbitary length to be + * attached to a netlink message. Each attribute is encoded with a + * type and length field, both 16 bits, stored in the attribute header + * preceding the attribute data. The main advantage of using attributes + * over packing everything into the family header is that the interface + * stays extendable as new attributes can supersede old attributes while + * remaining backwards compatible. Also attributes can be defined optional + * thus avoiding the transmission of unnecessary empty data blocks. + * Special nested attributes allow for more complex data structures to + * be transmitted, e.g. trees, lists, etc. + * + * While not required, netlink attributes typically follow the family + * header of a netlink message and must be properly aligned to NLA_ALIGNTO: + * @code + * +----------------+- - -+---------------+- - -+------------+- - -+ + * | Netlink Header | Pad | Family Header | Pad | Attributes | Pad | + * +----------------+- - -+---------------+- - -+------------+- - -+ + * @endcode + * + * The actual attributes are chained together each separately aligned to + * NLA_ALIGNTO. The position of an attribute is defined based on the + * length field of the preceding attributes: + * @code + * +-------------+- - -+-------------+- - -+------ + * | Attribute 1 | Pad | Attribute 2 | Pad | ... + * +-------------+- - -+-------------+- - -+------ + * nla_next(attr1)------^ + * @endcode + * + * The attribute itself consists of the attribute header followed by + * the actual payload also aligned to NLA_ALIGNTO. The function nla_data() + * returns a pointer to the start of the payload while nla_len() returns + * the length of the payload in bytes. + * + * \b Note: Be aware, NLA_ALIGNTO equals to 4 bytes, therefore it is not + * safe to dereference any 64 bit data types directly. + * + * @code + * <----------- nla_total_size(payload) -----------> + * <-------- nla_attr_size(payload) ---------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * nla_data(nla)-------------^ + * <- nla_len(nla) -> + * @endcode + * + * @subsection attr_datatypes Attribute Data Types + * A number of basic data types are supported to simplify access and + * validation of netlink attributes. This data type information is + * not encoded in the attribute, both the kernel and userspace part + * are required to share this information on their own. + * + * One of the major advantages of these basic types is the automatic + * validation of each attribute based on an attribute policy. The + * validation covers most of the checks required to safely use + * attributes and thus keeps the individual sanity check to a minimum. + * + * Never access attribute payload without ensuring basic validation + * first, attributes may: + * - not be present even though required + * - contain less actual payload than expected + * - fake a attribute length which exceeds the end of the message + * - contain unterminated character strings + * + * Policies are defined as array of the struct nla_policy. The array is + * indexed with the attribute type, therefore the array must be sized + * accordingly. + * @code + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = ..., .minlen = ..., .maxlen = ... }, + * }; + * + * err = nla_validate(attrs, attrlen, ATTR_MAX, &my_policy); + * @endcode + * + * Some basic validations are performed on every attribute, regardless of type. + * - If the attribute type exceeds the maximum attribute type specified or + * the attribute type is lesser-or-equal than zero, the attribute will + * be silently ignored. + * - If the payload length falls below the \a minlen value the attribute + * will be rejected. + * - If \a maxlen is non-zero and the payload length exceeds the \a maxlen + * value the attribute will be rejected. + * + * + * @par Unspecific Attribute (NLA_UNSPEC) + * This is the standard type if no type is specified. It is used for + * binary data of arbitary length. Typically this attribute carries + * a binary structure or a stream of bytes. + * @par + * @code + * // In this example, we will assume a binary structure requires to + * // be transmitted. The definition of the structure will typically + * // go into a header file available to both the kernel and userspace + * // side. + * // + * // Note: Be careful when putting 64 bit data types into a structure. + * // The attribute payload is only aligned to 4 bytes, dereferencing + * // the member may fail. + * struct my_struct { + * int a; + * int b; + * }; + * + * // The validation function will not enforce an exact length match to + * // allow structures to grow as required. Note: While it is allowed + * // to add members to the end of the structure, changing the order or + * // inserting members in the middle of the structure will break your + * // binary interface. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_MY_STRICT] = { .type = NLA_UNSPEC, + * .minlen = sizeof(struct my_struct) }, + * + * // The binary structure is appened to the message using nla_put() + * struct my_struct foo = { .a = 1, .b = 2 }; + * nla_put(msg, ATTR_MY_STRUCT, sizeof(foo), &foo); + * + * // On the receiving side, a pointer to the structure pointing inside + * // the message payload is returned by nla_get(). + * if (attrs[ATTR_MY_STRUCT]) + * struct my_struct *foo = nla_get(attrs[ATTR_MY_STRUCT]); + * @endcode + * + * @par Integers (NLA_U8, NLA_U16, NLA_U32, NLA_U64) + * Integers come in different sizes from 8 bit to 64 bit. However, since the + * payload length is aligned to 4 bytes, integers smaller than 32 bit are + * only useful to enforce the maximum range of values. + * @par + * \b Note: There is no difference made between signed and unsigned integers. + * The validation only enforces the minimal payload length required to store + * an integer of specified type. + * @par + * @code + * // Even though possible, it does not make sense to specify .minlen or + * // .maxlen for integer types. The data types implies the corresponding + * // minimal payload length. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = NLA_U32 }, + * + * // Numeric values can be appended directly using the respective + * // nla_put_uxxx() function + * nla_put_u32(msg, ATTR_FOO, 123); + * + * // Same for the receiving side. + * if (attrs[ATTR_FOO]) + * uint32_t foo = nla_get_u32(attrs[ATTR_FOO]); + * @endcode + * + * @par Character string (NLA_STRING) + * This data type represents a NUL terminated character string of variable + * length. For binary data streams the type NLA_UNSPEC is recommended. + * @par * @code - * <------- nla_total_size(payload) -------> - * <---- nla_attr_size(payload) -----> - * +----------+- - -+- - - - - - - - - +- - -+-------- - - - * | Header | Pad | Payload | Pad | Header - * +----------+- - -+- - - - - - - - - +- - -+-------- - - - * <- nla_len(nla) -> ^ - * nla_data(nla)----^ | - * nla_next(nla)-----------------------------' + * // Enforce a NUL terminated character string of at most 4 characters + * // including the NUL termination. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_BAR] = { .type = NLA_STRING, maxlen = 4 }, + * + * // nla_put_string() creates a string attribute of the necessary length + * // and appends it to the message including the NUL termination. + * nla_put_string(msg, ATTR_BAR, "some text"); + * + * // It is safe to use the returned character string directly if the + * // attribute has been validated as the validation enforces the proper + * // termination of the string. + * if (attrs[ATTR_BAR]) + * char *text = nla_get_string(attrs[ATTR_BAR]); * @endcode * + * @par Flag (NLA_FLAG) + * This attribute type may be used to indicate the presence of a flag. The + * attribute is only valid if the payload length is zero. The presence of + * the attribute header indicates the presence of the flag. * @par - * The attribute header and payload must be aligned properly: * @code - * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> - * +---------------------+- - -+- - - - - - - - - -+- - -+ - * | Header | Pad | Payload | Pad | - * | (struct nlattr) | ing | | ing | - * +---------------------+- - -+- - - - - - - - - -+- - -+ - * <-------------- nlattr->nla_len --------------> + * // This attribute type is special as .minlen and .maxlen have no effect. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_FLAG] = { .type = NLA_FLAG }, + * + * // nla_put_flag() appends a zero sized attribute to the message. + * nla_put_flag(msg, ATTR_FLAG); + * + * // There is no need for a receival function, the presence is the value. + * if (attrs[ATTR_FLAG]) + * // flag is present + * @endcode + * + * @par Micro Seconds (NLA_MSECS) + * + * @par Nested Attribute (NLA_NESTED) + * Attributes can be nested and put into a container to create groups, lists + * or to construct trees of attributes. Nested attributes are often used to + * pass attributes to a subsystem where the top layer has no knowledge of the + * configuration possibilities of each subsystem. + * @par + * \b Note: When validating the attributes using nlmsg_validate() or + * nlmsg_parse() it will only affect the top level attributes. Each + * level of nested attributes must be validated seperately using + * nla_parse_nested() or nla_validate(). + * @par + * @code + * // The minimal length policy may be used to enforce the presence of at + * // least one attribute. + * static struct nla_policy my_policy[ATTR_MAX+1] = { + * [ATTR_OPTS] = { .type = NLA_NESTED, minlen = NLA_HDRLEN }, + * + * // Nested attributes are constructed by enclosing the attributes + * // to be nested with calls to nla_nest_start() respetively nla_nest_end(). + * struct nlattr *opts = nla_nest_start(msg, ATTR_OPTS); + * nla_put_u32(msg, ATTR_FOO, 123); + * nla_put_string(msg, ATTR_BAR, "some text"); + * nla_nest_end(msg, opts); + * + * // Various methods exist to parse nested attributes, the easiest being + * // nla_parse_nested() which also allows validation in the same step. + * if (attrs[ATTR_OPTS]) { + * struct nlattr *nested[ATTR_MAX+1]; + * + * nla_parse_nested(nested, ATTR_MAX, attrs[ATTR_OPTS], &policy); + * + * if (nested[ATTR_FOO]) + * uint32_t foo = nla_get_u32(nested[ATTR_FOO]); + * } * @endcode * - * @par Nested TLVs: - * Nested TLVs are an array of TLVs nested into another TLV. This can be useful - * to allow subsystems to have their own formatting rules without the need to - * make the underlying layer be aware of it. It can also be useful to transfer - * arrays, lists and flattened trees. - * \code - * <-------------------- NLA_ALIGN(...) -------------------> - * +---------------+- - - - - - - - - - - - - - - - - -+- - -+ - * | |+---------+---------+- - -+-------+| | - * | TLV Header || TLV 1 | TLV 2 | | TLV n || Pad | - * | |+---------+---------+- - -+-------+| | - * +---------------+- - - - - - - - - - - - - - - - - -+- - -+ - * <--------- nla_data(nla) ---------> - * \endcode - * - * @par 1) Constructing a message with attributes + * @subsection attr_exceptions Exception Based Attribute Construction + * Often a large number of attributes are added to a message in a single + * function. In order to simplify error handling, a second set of + * construction functions exist which jump to a error label when they + * fail instead of returning an error code. This second set consists + * of macros which are named after their error code based counterpart + * except that the name is written all uppercase. + * + * All of the macros jump to the target \c nla_put_failure if they fail. * @code - * int param1 = 10; - * char *param2 = "parameter text"; - * - * struct nl_msg *msg = nlmsg_alloc(); - * nla_put_u32(msg, 1, param1); - * nla_put_string(msg, 2, param2); - * - * nl_send_auto_complete(handle, nl_msg_get(msg)); - * nlmsg_free(msg); + * void my_func(struct nl_msg *msg) + * { + * NLA_PUT_U32(msg, ATTR_FOO, 10); + * NLA_PUT_STRING(msg, ATTR_BAR, "bar"); + * + * return 0; + * + * nla_put_failure: + * return -NLE_NOMEM; + * } * @endcode * - * @par 2) Constructing nested attributes + * @subsection attr_examples Examples + * @par Example 1.1 Constructing a netlink message with attributes. * @code - * struct nl_msg * nested_config(void) + * struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu) * { - * int a = 5, int b = 10; - * struct nl_msg *n = nlmsg_alloc(); - * nla_put_u32(n, 10, a); - * nla_put_u32(n, 20, b); - * return n; + * struct nl_msg *msg; + * struct nlattr *info, *vlan; + * struct ifinfomsg ifi = { + * .ifi_family = AF_INET, + * .ifi_index = ifindex, + * }; + * + * // Allocate a new netlink message, type=RTM_SETLINK, flags=NLM_F_ECHO + * if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_ECHO))) + * return NULL; + * + * // Append the family specific header (struct ifinfomsg) + * if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) + * goto nla_put_failure + * + * // Append a 32 bit integer attribute to carry the MTU + * NLA_PUT_U32(msg, IFLA_MTU, mtu); + * + * // Append a unspecific attribute to carry the link layer address + * NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr); + * + * // Append a container for nested attributes to carry link information + * if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) + * goto nla_put_failure; + * + * // Put a string attribute into the container + * NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan"); + * + * // Append another container inside the open container to carry + * // vlan specific attributes + * if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA))) + * goto nla_put_failure; + * + * // add vlan specific info attributes here... + * + * // Finish nesting the vlan attributes and close the second container. + * nla_nest_end(msg, vlan); + * + * // Finish nesting the link info attribute and close the first container. + * nla_nest_end(msg, info); + * + * return msg; + * + * // If any of the construction macros fails, we end up here. + * nla_put_failure: + * nlmsg_free(msg); + * return NULL; * } + * @endcode + * + * @par Example 2.1 Parsing a netlink message with attributes. + * @code + * int parse_message(struct nl_msg *msg) + * { + * // The policy defines two attributes: a 32 bit integer and a container + * // for nested attributes. + * struct nla_policy attr_policy[ATTR_MAX+1] = { + * [ATTR_FOO] = { .type = NLA_U32 }, + * [ATTR_BAR] = { .type = NLA_NESTED }, + * }; + * struct nlattr *attrs[ATTR_MAX+1]; + * int err; + * + * // The nlmsg_parse() function will make sure that the message contains + * // enough payload to hold the header (struct my_hdr), validates any + * // attributes attached to the messages and stores a pointer to each + * // attribute in the attrs[] array accessable by attribute type. + * if ((err = nlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs, + * ATTR_MAX, attr_policy)) < 0) + * goto errout; + * + * if (attrs[ATTR_FOO]) { + * // It is safe to directly access the attribute payload without + * // any further checks since nlmsg_parse() enforced the policy. + * uint32_t foo = nla_get_u32(attrs[ATTR_FOO]); + * } + * + * if (attrs[ATTR_BAR]) { + * struct nlattr *nested[NESTED_MAX+1]; + * + * // Attributes nested in a container can be parsed the same way + * // as top level attributes. + * if ((err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR], + * nested_policy)) < 0) + * goto errout; * - * ... - * struct nl_msg *m = nlmsg_alloc(); - * struct nl_msg *nest = nested_config(); - * nla_put_nested(m, 1, nest); + * // Process nested attributes here. + * } * - * nl_send_auto_complete(handle, nl_msg_get(m)); - * nlmsg_free(nest); - * nlmsg_free(m); + * err = 0; + * errout: + * return err; + * } * @endcode + * * @{ */ /** - * @name Size Calculations + * @name Attribute Size Calculation * @{ */ /** - * length of attribute not including padding - * @arg payload length of payload + * Return size of attribute whithout padding. + * @arg payload Payload length of attribute. + * + * @code + * <-------- nla_attr_size(payload) ---------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * @endcode + * + * @return Size of attribute in bytes without padding. */ int nla_attr_size(int payload) { @@ -111,8 +398,17 @@ int nla_attr_size(int payload) } /** - * total length of attribute including padding - * @arg payload length of payload + * Return size of attribute including padding. + * @arg payload Payload length of attribute. + * + * @code + * <----------- nla_total_size(payload) -----------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * @endcode + * + * @return Size of attribute in bytes. */ int nla_total_size(int payload) { @@ -120,8 +416,17 @@ int nla_total_size(int payload) } /** - * length of padding at the tail of the attribute - * @arg payload length of payload + * Return length of padding at the tail of the attribute. + * @arg payload Payload length of attribute. + * + * @code + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * <---> + * @endcode + * + * @return Length of padding in bytes. */ int nla_padlen(int payload) { @@ -131,13 +436,15 @@ int nla_padlen(int payload) /** @} */ /** - * @name Payload Access + * @name Parsing Attributes * @{ */ /** - * attribute type - * @arg nla netlink attribute + * Return type of the attribute. + * @arg nla Attribute. + * + * @return Type of attribute. */ int nla_type(const struct nlattr *nla) { @@ -145,8 +452,10 @@ int nla_type(const struct nlattr *nla) } /** - * head of payload - * @arg nla netlink attribute + * Return pointer to the payload section. + * @arg nla Attribute. + * + * @return Pointer to start of payload section. */ void *nla_data(const struct nlattr *nla) { @@ -154,25 +463,27 @@ void *nla_data(const struct nlattr *nla) } /** - * length of payload - * @arg nla netlink attribute + * Return length of the payload . + * @arg nla Attribute + * + * @return Length of payload in bytes. */ int nla_len(const struct nlattr *nla) { return nla->nla_len - NLA_HDRLEN; } -/** @} */ - -/** - * @name Attribute Parsing - * @{ - */ - /** - * check if the netlink attribute fits into the remaining bytes - * @arg nla netlink attribute - * @arg remaining number of bytes remaining in attribute stream + * Check if the attribute header and payload can be accessed safely. + * @arg nla Attribute of any kind. + * @arg remaining Number of bytes remaining in attribute stream. + * + * Verifies that the header and payload do not exceed the number of + * bytes left in the attribute stream. This function must be called + * before access the attribute header or payload when iterating over + * the attribute stream using nla_next(). + * + * @return True if the attribute can be accessed safely, false otherwise. */ int nla_ok(const struct nlattr *nla, int remaining) { @@ -182,12 +493,20 @@ int nla_ok(const struct nlattr *nla, int remaining) } /** - * next netlink attribte in attribute stream - * @arg nla netlink attribute - * @arg remaining number of bytes remaining in attribute stream + * Return next attribute in a stream of attributes. + * @arg nla Attribute of any kind. + * @arg remaining Variable to count remaining bytes in stream. * - * @return the next netlink attribute in the attribute stream and - * decrements remaining by the size of the current attribute. + * Calculates the offset to the next attribute based on the attribute + * given. The attribute provided is assumed to be accessible, the + * caller is responsible to use nla_ok() beforehand. The offset (length + * of specified attribute including padding) is then subtracted from + * the remaining bytes variable and a pointer to the next attribute is + * returned. + * + * nla_next() can be called as long as remainig is >0. + * + * @return Pointer to next attribute. */ struct nlattr *nla_next(const struct nlattr *nla, int *remaining) { @@ -203,7 +522,6 @@ static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { [NLA_U32] = sizeof(uint32_t), [NLA_U64] = sizeof(uint64_t), [NLA_STRING] = 1, - [NLA_NESTED] = NLA_HDRLEN, }; static int validate_nla(struct nlattr *nla, int maxtype, @@ -226,18 +544,18 @@ static int validate_nla(struct nlattr *nla, int maxtype, minlen = nla_attr_minlen[pt->type]; if (pt->type == NLA_FLAG && nla_len(nla) > 0) - return nl_errno(ERANGE); + return -NLE_RANGE; if (nla_len(nla) < minlen) - return nl_errno(ERANGE); + return -NLE_RANGE; if (pt->maxlen && nla_len(nla) > pt->maxlen) - return nl_errno(ERANGE); + return -NLE_RANGE; if (pt->type == NLA_STRING) { char *data = nla_data(nla); if (data[nla_len(nla) - 1] != '\0') - return nl_errno(EINVAL); + return -NLE_INVAL; } return 0; @@ -245,18 +563,21 @@ static int validate_nla(struct nlattr *nla, int maxtype, /** - * Parse a stream of attributes into a tb buffer - * @arg tb destination array with maxtype+1 elements - * @arg maxtype maximum attribute type to be expected - * @arg head head of attribute stream - * @arg len length of attribute stream - * @arg policy validation policy + * Create attribute index based on a stream of attributes. + * @arg tb Index array to be filled (maxtype+1 elements). + * @arg maxtype Maximum attribute type expected and accepted. + * @arg head Head of attribute stream. + * @arg len Length of attribute stream. + * @arg policy Attribute validation policy. * - * Parses a stream of attributes and stores a pointer to each attribute in - * the tb array accessable via the attribute type. Attributes with a type - * exceeding maxtype will be silently ignored for backwards compatibility - * reasons. policy may be set to NULL if no validation is required. + * Iterates over the stream of attributes and stores a pointer to each + * attribute in the index array using the attribute type as index to + * the array. Attribute with a type greater than the maximum type + * specified will be silently ignored in order to maintain backwards + * compatibility. If \a policy is not NULL, the attribute will be + * validated using the specified policy. * + * @see nla_validate * @return 0 on success or a negative error code. */ int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, @@ -295,33 +616,20 @@ errout: return err; } - /** - * parse nested attributes - * @arg tb destination array with maxtype+1 elements - * @arg maxtype maximum attribute type to be expected - * @arg nla attribute containing the nested attributes - * @arg policy validation policy + * Validate a stream of attributes. + * @arg head Head of attributes stream. + * @arg len Length of attributes stream. + * @arg maxtype Maximum attribute type expected and accepted. + * @arg policy Validation policy. * - * @see nla_parse() - */ -int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, - struct nla_policy *policy) -{ - return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); -} - -/** - * Validate a stream of attributes - * @arg head head of attribute stream - * @arg len length of attribute stream - * @arg maxtype maximum attribute type to be expected - * @arg policy validation policy + * Iterates over the stream of attributes and validates each attribute + * one by one using the specified policy. Attributes with a type greater + * than the maximum type specified will be silently ignored in order to + * maintain backwards compatibility. * - * Validates all attributes in the specified attribute stream - * against the specified policy. Attributes with a type exceeding - * maxtype will be ignored. See documenation of struct nla_policy - * for more details. + * See \ref attr_datatypes for more details on what kind of validation + * checks are performed on each attribute data type. * * @return 0 on success or a negative error code. */ @@ -343,12 +651,16 @@ errout: } /** - * Find a specific attribute in a stream of attributes - * @arg head head of attribute stream - * @arg len length of attribute stream - * @arg attrtype type of attribute to look for + * Find a single attribute in a stream of attributes. + * @arg head Head of attributes stream. + * @arg len Length of attributes stream. + * @arg attrtype Attribute type to look for. * - * @return the first attribute in the stream matching the specified type. + * Iterates over the stream of attributes and compares each type with + * the type specified. Returns the first attribute which matches the + * type. + * + * @return Pointer to attribute found or NULL. */ struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) { @@ -365,20 +677,20 @@ struct nlattr *nla_find(struct nlattr *head, int len, int attrtype) /** @} */ /** - * @name Utilities + * @name Helper Functions * @{ */ /** - * Copy a netlink attribute into another memory area - * @arg dest where to copy to memcpy - * @arg src netlink attribute to copy from - * @arg count size of the destination area + * Copy attribute payload to another memory area. + * @arg dest Pointer to destination memory area. + * @arg src Attribute + * @arg count Number of bytes to copy at most. * * Note: The number of bytes copied is limited by the length of - * attribute's payload. memcpy + * the attribute payload. * - * @return the number of bytes copied. + * @return The number of bytes copied to dest. */ int nla_memcpy(void *dest, struct nlattr *src, int count) { @@ -394,16 +706,16 @@ int nla_memcpy(void *dest, struct nlattr *src, int count) } /** - * Copy string attribute payload into a sized buffer - * @arg dst where to copy the string to - * @arg nla attribute to copy the string from - * @arg dstsize size of destination buffer + * Copy string attribute payload to a buffer. + * @arg dst Pointer to destination buffer. + * @arg nla Attribute of type NLA_STRING. + * @arg dstsize Size of destination buffer in bytes. * - * Copies at most dstsize - 1 bytes into the destination buffer. - * The result is always a valid NUL-terminated string. Unlike + * Copies at most dstsize - 1 bytes to the destination buffer. + * The result is always a valid NUL terminated string. Unlike * strlcpy the destination buffer is always padded out. * - * @return the length of the source buffer. + * @return The length of string attribute without the terminating NUL. */ size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) { @@ -424,13 +736,15 @@ size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) } /** - * Compare an attribute with sized memory area - * @arg nla netlink attribute - * @arg data memory area - * @arg size size of memory area + * Compare attribute payload with memory area. + * @arg nla Attribute. + * @arg data Memory area to compare to. + * @arg size Number of bytes to compare. + * + * @see memcmp(3) + * @return An integer less than, equal to, or greater than zero. */ -int nla_memcmp(const struct nlattr *nla, const void *data, - size_t size) +int nla_memcmp(const struct nlattr *nla, const void *data, size_t size) { int d = nla_len(nla) - size; @@ -441,9 +755,12 @@ int nla_memcmp(const struct nlattr *nla, const void *data, } /** - * Compare a string attribute against a string - * @arg nla netlink string attribute - * @arg str another string + * Compare string attribute payload with string + * @arg nla Attribute of type NLA_STRING. + * @arg str NUL terminated string. + * + * @see strcmp(3) + * @return An integer less than, equal to, or greater than zero. */ int nla_strcmp(const struct nlattr *nla, const char *str) { @@ -459,324 +776,392 @@ int nla_strcmp(const struct nlattr *nla, const char *str) /** @} */ /** - * @name Attribute Construction + * @name Unspecific Attribute * @{ */ /** - * reserve room for attribute on the skb - * @arg n netlink message - * @arg attrtype attribute type - * @arg attrlen length of attribute payload + * Reserve space for a attribute. + * @arg msg Netlink Message. + * @arg attrtype Attribute Type. + * @arg attrlen Length of payload. + * + * Reserves room for a attribute in the specified netlink message and + * fills in the attribute header (type, length). Returns NULL if there + * is unsuficient space for the attribute. * - * Adds a netlink attribute header to a netlink message and reserves - * room for the payload but does not copy it. + * Any padding between payload and the start of the next attribute is + * zeroed out. + * + * @return Pointer to start of attribute or NULL on failure. */ -struct nlattr *nla_reserve(struct nl_msg *n, int attrtype, int attrlen) +struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen) { struct nlattr *nla; int tlen; - tlen = NLMSG_ALIGN(n->nm_nlh->nlmsg_len) + nla_total_size(attrlen); + tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen); - if ((tlen + n->nm_nlh->nlmsg_len) > n->nm_size) { - nl_errno(ENOBUFS); + if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size) return NULL; - } - nla = (struct nlattr *) nlmsg_tail(n->nm_nlh); + nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh); nla->nla_type = attrtype; nla->nla_len = nla_attr_size(attrlen); memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); - n->nm_nlh->nlmsg_len = tlen; + msg->nm_nlh->nlmsg_len = tlen; NL_DBG(2, "msg %p: Reserved %d bytes at offset +%td for attr %d " - "nlmsg_len=%d\n", n, attrlen, - (void *) nla - nlmsg_data(n->nm_nlh), - attrtype, n->nm_nlh->nlmsg_len); + "nlmsg_len=%d\n", msg, attrlen, + (void *) nla - nlmsg_data(msg->nm_nlh), + attrtype, msg->nm_nlh->nlmsg_len); return nla; } /** - * Add a netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg attrlen length of attribute payload - * @arg data head of attribute payload + * Add a unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg datalen Length of data to be used as payload. + * @arg data Pointer to data to be used as attribute payload. + * + * Reserves room for a unspecific attribute and copies the provided data + * into the message as payload of the attribute. Returns an error if there + * is insufficient space for the attribute. * - * @return -1 if the tailroom of the skb is insufficient to store - * the attribute header and payload. + * @see nla_reserve + * @return 0 on success or a negative error code. */ -int nla_put(struct nl_msg *n, int attrtype, int attrlen, const void *data) +int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data) { struct nlattr *nla; - nla = nla_reserve(n, attrtype, attrlen); + nla = nla_reserve(msg, attrtype, datalen); if (!nla) - return nl_errno(ENOMEM); + return -NLE_NOMEM; - memcpy(nla_data(nla), data, attrlen); + memcpy(nla_data(nla), data, datalen); NL_DBG(2, "msg %p: Wrote %d bytes at offset +%td for attr %d\n", - n, attrlen, (void *) nla - nlmsg_data(n->nm_nlh), attrtype); + msg, datalen, (void *) nla - nlmsg_data(msg->nm_nlh), attrtype); return 0; } /** - * Add a nested netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg nested netlink attribute to nest + * Add abstract data as unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg data Abstract data object. + * + * Equivalent to nla_put() except that the length of the payload is + * derived from the abstract data object. * - * @return -1 if the tailroom of the skb is insufficient to store - * the attribute header and payload. + * @see nla_put + * @return 0 on success or a negative error code. */ -int nla_put_nested(struct nl_msg *n, int attrtype, struct nl_msg *nested) +int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data) { - return nla_put(n, attrtype, nlmsg_len(nested->nm_nlh), - nlmsg_data(nested->nm_nlh)); + return nla_put(msg, attrtype, nl_data_get_size(data), + nl_data_get(data)); } /** - * Add a u16 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Add abstract address as unspecific attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg addr Abstract address object. + * + * @see nla_put + * @return 0 on success or a negative error code. */ -int nla_put_u8(struct nl_msg *n, int attrtype, uint8_t value) +int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr) { - return nla_put(n, attrtype, sizeof(uint8_t), &value); + return nla_put(msg, attrtype, nl_addr_get_len(addr), + nl_addr_get_binary_addr(addr)); } +/** @} */ + /** - * Add a u16 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * @name Integer Attributes + */ + +/** + * Add 8 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. */ -int nla_put_u16(struct nl_msg *n, int attrtype, uint16_t value) +int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value) { - return nla_put(n, attrtype, sizeof(uint16_t), &value); + return nla_put(msg, attrtype, sizeof(uint8_t), &value); } /** - * Add a u32 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Return value of 8 bit integer attribute. + * @arg nla 8 bit integer attribute + * + * @return Payload as 8 bit integer. */ -int nla_put_u32(struct nl_msg *n, int attrtype, uint32_t value) +uint8_t nla_get_u8(struct nlattr *nla) { - return nla_put(n, attrtype, sizeof(uint32_t), &value); + return *(uint8_t *) nla_data(nla); } /** - * Add a u64 netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg value numeric value + * Add 16 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. */ -int nla_put_u64(struct nl_msg *n, int attrtype, uint64_t value) +int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value) { - return nla_put(n, attrtype, sizeof(uint64_t), &value); + return nla_put(msg, attrtype, sizeof(uint16_t), &value); } /** - * Add a string netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg str NUL terminated string + * Return payload of 16 bit integer attribute. + * @arg nla 16 bit integer attribute + * + * @return Payload as 16 bit integer. */ -int nla_put_string(struct nl_msg *n, int attrtype, const char *str) +uint16_t nla_get_u16(struct nlattr *nla) { - return nla_put(n, attrtype, strlen(str) + 1, str); + return *(uint16_t *) nla_data(nla); } /** - * Add a flag netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type + * Add 32 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. */ -int nla_put_flag(struct nl_msg *n, int attrtype) +int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value) { - return nla_put(n, attrtype, 0, NULL); + return nla_put(msg, attrtype, sizeof(uint32_t), &value); } /** - * Add a msecs netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg msecs number of msecs + * Return payload of 32 bit integer attribute. + * @arg nla 32 bit integer attribute. + * + * @return Payload as 32 bit integer. */ -int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs) +uint32_t nla_get_u32(struct nlattr *nla) { - return nla_put_u64(n, attrtype, msecs); + return *(uint32_t *) nla_data(nla); } /** - * Add an abstract data netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg data abstract data + * Add 64 bit integer attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg value Numeric value to store as payload. + * + * @see nla_put + * @return 0 on success or a negative error code. */ -int nla_put_data(struct nl_msg *n, int attrtype, struct nl_data *data) +int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value) { - return nla_put(n, attrtype, nl_data_get_size(data), - nl_data_get(data)); + return nla_put(msg, attrtype, sizeof(uint64_t), &value); } /** - * Add an abstract address netlink attribute to a netlink message - * @arg n netlink message - * @arg attrtype attribute type - * @arg addr abstract address + * Return payload of u64 attribute + * @arg nla u64 netlink attribute + * + * @return Payload as 64 bit integer. */ -int nla_put_addr(struct nl_msg *n, int attrtype, struct nl_addr *addr) +uint64_t nla_get_u64(struct nlattr *nla) { - return nla_put(n, attrtype, nl_addr_get_len(addr), - nl_addr_get_binary_addr(addr)); + uint64_t tmp; + + nla_memcpy(&tmp, nla, sizeof(tmp)); + + return tmp; } /** @} */ /** - * @name Attribute Nesting - * @{ + * @name String Attribute */ /** - * Start a new level of nested attributes - * @arg n netlink message - * @arg attrtype attribute type of container + * Add string attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg str NUL terminated string. * - * @return the container attribute + * @see nla_put + * @return 0 on success or a negative error code. */ -struct nlattr *nla_nest_start(struct nl_msg *n, int attrtype) +int nla_put_string(struct nl_msg *msg, int attrtype, const char *str) { - struct nlattr *start = (struct nlattr *) nlmsg_tail(n->nm_nlh); - - if (nla_put(n, attrtype, 0, NULL) < 0) - return NULL; - - return start; + return nla_put(msg, attrtype, strlen(str) + 1, str); } /** - * Finalize nesting of attributes - * @arg n netlink message - * @arg start container attribute - * - * Corrects the container attribute header to include the all - * appeneded attributes. + * Return payload of string attribute. + * @arg nla String attribute. * - * @return the total data length of the skb. + * @return Pointer to attribute payload. */ -int nla_nest_end(struct nl_msg *n, struct nlattr *start) +char *nla_get_string(struct nlattr *nla) { - start->nla_len = (unsigned char *) nlmsg_tail(n->nm_nlh) - - (unsigned char *) start; - return 0; + return (char *) nla_data(nla); +} + +char *nla_strdup(struct nlattr *nla) +{ + return strdup(nla_get_string(nla)); } /** @} */ /** - * @name Attribute Reading - * @{ + * @name Flag Attribute */ /** - * Return payload of u32 attribute - * @arg nla u32 netlink attribute + * Add flag netlink attribute to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * + * @see nla_put + * @return 0 on success or a negative error code. */ -uint32_t nla_get_u32(struct nlattr *nla) +int nla_put_flag(struct nl_msg *msg, int attrtype) { - return *(uint32_t *) nla_data(nla); + return nla_put(msg, attrtype, 0, NULL); } /** - * Return payload of u16 attribute - * @arg nla u16 netlink attribute + * Return true if flag attribute is set. + * @arg nla Flag netlink attribute. + * + * @return True if flag is set, otherwise false. */ -uint16_t nla_get_u16(struct nlattr *nla) +int nla_get_flag(struct nlattr *nla) { - return *(uint16_t *) nla_data(nla); + return !!nla; } +/** @} */ + /** - * Return payload of u8 attribute - * @arg nla u8 netlink attribute + * @name Microseconds Attribute */ -uint8_t nla_get_u8(struct nlattr *nla) -{ - return *(uint8_t *) nla_data(nla); -} /** - * Return payload of u64 attribute - * @arg nla u64 netlink attribute + * Add a msecs netlink attribute to a netlink message + * @arg n netlink message + * @arg attrtype attribute type + * @arg msecs number of msecs */ -uint64_t nla_get_u64(struct nlattr *nla) +int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs) { - uint64_t tmp; - - nla_memcpy(&tmp, nla, sizeof(tmp)); - - return tmp; + return nla_put_u64(n, attrtype, msecs); } /** - * return payload of string attribute - * @arg nla string netlink attribute + * Return payload of msecs attribute + * @arg nla msecs netlink attribute + * + * @return the number of milliseconds. */ -char *nla_get_string(struct nlattr *nla) +unsigned long nla_get_msecs(struct nlattr *nla) { - return (char *) nla_data(nla); + return nla_get_u64(nla); } +/** @} */ + /** - * Return payload of flag attribute - * @arg nla flag netlink attribute + * @name Nested Attribute */ -int nla_get_flag(struct nlattr *nla) + +/** + * Add nested attributes to netlink message. + * @arg msg Netlink message. + * @arg attrtype Attribute type. + * @arg nested Message containing attributes to be nested. + * + * Takes the attributes found in the \a nested message and appends them + * to the message \a msg nested in a container of the type \a attrtype. + * The \a nested message may not have a family specific header. + * + * @see nla_put + * @return 0 on success or a negative error code. + */ +int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested) { - return !!nla; + return nla_put(msg, attrtype, nlmsg_len(nested->nm_nlh), + nlmsg_data(nested->nm_nlh)); } + /** - * Return payload of msecs attribute - * @arg nla msecs netlink attribute + * Start a new level of nested attributes. + * @arg msg Netlink message. + * @arg attrtype Attribute type of container. * - * @return the number of milliseconds. + * @return Pointer to container attribute. */ -unsigned long nla_get_msecs(struct nlattr *nla) +struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype) { - return nla_get_u64(nla); + struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh); + + if (nla_put(msg, attrtype, 0, NULL) < 0) + return NULL; + + return start; } /** - * Return payload of address attribute - * @arg nla address netlink attribute - * @arg family address family + * Finalize nesting of attributes. + * @arg msg Netlink message. + * @arg start Container attribute as returned from nla_nest_start(). * - * @return Newly allocated address handle or NULL + * Corrects the container attribute header to include the appeneded attributes. + * + * @return 0 */ -struct nl_addr *nla_get_addr(struct nlattr *nla, int family) +int nla_nest_end(struct nl_msg *msg, struct nlattr *start) { - return nl_addr_build(family, nla_data(nla), nla_len(nla)); + start->nla_len = (unsigned char *) nlmsg_tail(msg->nm_nlh) - + (unsigned char *) start; + return 0; } /** - * Return payload of abstract data attribute - * @arg nla abstract data netlink attribute + * Create attribute index based on nested attribute + * @arg tb Index array to be filled (maxtype+1 elements). + * @arg maxtype Maximum attribute type expected and accepted. + * @arg nla Nested Attribute. + * @arg policy Attribute validation policy. + * + * Feeds the stream of attributes nested into the specified attribute + * to nla_parse(). * - * @return Newly allocated abstract data handle or NULL + * @see nla_parse + * @return 0 on success or a negative error code. */ -struct nl_data *nla_get_data(struct nlattr *nla) +int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, + struct nla_policy *policy) { - return nl_data_alloc(nla_data(nla), nla_len(nla)); + return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); } /** @} */ diff --git a/lib/cache.c b/lib/cache.c index 285bc31..2b24946 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -175,10 +175,8 @@ struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops) struct nl_cache *cache; cache = calloc(1, sizeof(*cache)); - if (!cache) { - nl_errno(ENOMEM); + if (!cache) return NULL; - } nl_init_list_head(&cache->c_items); cache->c_ops = ops; @@ -188,22 +186,43 @@ struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops) return cache; } +int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, + struct nl_cache **result) +{ + struct nl_cache *cache; + int err; + + if (!(cache = nl_cache_alloc(ops))) + return -NLE_NOMEM; + + if (sock && (err = nl_cache_refill(sock, cache)) < 0) { + nl_cache_free(cache); + return err; + } + + *result = cache; + return 0; +} + /** * Allocate an empty cache based on type name * @arg kind Name of cache type * @return A newly allocated and initialized cache. */ -struct nl_cache *nl_cache_alloc_name(const char *kind) +int nl_cache_alloc_name(const char *kind, struct nl_cache **result) { struct nl_cache_ops *ops; + struct nl_cache *cache; ops = nl_cache_ops_lookup(kind); - if (!ops) { - nl_error(ENOENT, "Unable to lookup cache \"%s\"", kind); - return NULL; - } + if (!ops) + return -NLE_NOCACHE; + + if (!(cache = nl_cache_alloc(ops))) + return -NLE_NOMEM; - return nl_cache_alloc(ops); + *result = cache; + return 0; } /** @@ -264,6 +283,9 @@ void nl_cache_clear(struct nl_cache *cache) */ void nl_cache_free(struct nl_cache *cache) { + if (!cache) + return; + nl_cache_clear(cache); NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache)); free(cache); @@ -304,12 +326,12 @@ int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) struct nl_object *new; if (cache->c_ops->co_obj_ops != obj->ce_ops) - return nl_error(EINVAL, "Object mismatches cache type"); + return -NLE_OBJ_MISMATCH; if (!nl_list_empty(&obj->ce_list)) { new = nl_object_clone(obj); if (!new) - return nl_errno(ENOMEM); + return -NLE_NOMEM; } else { nl_object_get(obj); new = obj; @@ -331,7 +353,7 @@ int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) int nl_cache_move(struct nl_cache *cache, struct nl_object *obj) { if (cache->c_ops->co_obj_ops != obj->ce_ops) - return nl_error(EINVAL, "Object mismatches cache type"); + return -NLE_OBJ_MISMATCH; NL_DBG(3, "Moving object %p to cache %p\n", obj, cache); @@ -405,7 +427,7 @@ struct nl_object *nl_cache_search(struct nl_cache *cache, /** * Request a full dump from the kernel to fill a cache - * @arg handle Netlink handle + * @arg sk Netlink socket. * @arg cache Cache subjected to be filled. * * Send a dumping request to the kernel causing it to dump all objects @@ -414,15 +436,15 @@ struct nl_object *nl_cache_search(struct nl_cache *cache, * Use nl_cache_pickup() to read the objects from the socket and fill them * into a cache. */ -int nl_cache_request_full_dump(struct nl_handle *handle, struct nl_cache *cache) +int nl_cache_request_full_dump(struct nl_sock *sk, struct nl_cache *cache) { NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n", cache, nl_cache_name(cache)); if (cache->c_ops->co_request_update == NULL) - return nl_error(EOPNOTSUPP, "Operation not supported"); + return -NLE_OPNOTSUPP; - return cache->c_ops->co_request_update(cache, handle); + return cache->c_ops->co_request_update(cache, sk); } /** @cond SKIP */ @@ -439,7 +461,7 @@ static int update_msg_parser(struct nl_msg *msg, void *arg) } /** @endcond */ -int __cache_pickup(struct nl_handle *handle, struct nl_cache *cache, +int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache, struct nl_parser_param *param) { int err; @@ -452,17 +474,17 @@ int __cache_pickup(struct nl_handle *handle, struct nl_cache *cache, NL_DBG(1, "Picking up answer for cache %p <%s>...\n", cache, nl_cache_name(cache)); - cb = nl_cb_clone(handle->h_cb); + cb = nl_cb_clone(sk->s_cb); if (cb == NULL) - return nl_get_errno(); + return -NLE_NOMEM; nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x); - err = nl_recvmsgs(handle, cb); + err = nl_recvmsgs(sk, cb); if (err < 0) NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \ "%d: %s", cache, nl_cache_name(cache), - err, nl_geterror()); + err, nl_geterror(err)); nl_cb_put(cb); @@ -476,7 +498,7 @@ static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) /** * Pickup a netlink dump response and put it into a cache. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg cache Cache to put items into. * * Waits for netlink messages to arrive, parses them and puts them into @@ -484,18 +506,18 @@ static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) * * @return 0 on success or a negative error code. */ -int nl_cache_pickup(struct nl_handle *handle, struct nl_cache *cache) +int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) { struct nl_parser_param p = { .pp_cb = pickup_cb, .pp_arg = cache, }; - return __cache_pickup(handle, cache, &p); + return __cache_pickup(sk, cache, &p); } static int cache_include(struct nl_cache *cache, struct nl_object *obj, - struct nl_msgtype *type, change_func_t cb) + struct nl_msgtype *type, change_func_t cb, void *data) { struct nl_object *old; @@ -507,7 +529,7 @@ static int cache_include(struct nl_cache *cache, struct nl_object *obj, nl_cache_remove(old); if (type->mt_act == NL_ACT_DEL) { if (cb) - cb(cache, old, NL_ACT_DEL); + cb(cache, old, NL_ACT_DEL, data); nl_object_put(old); } } @@ -515,10 +537,10 @@ static int cache_include(struct nl_cache *cache, struct nl_object *obj, if (type->mt_act == NL_ACT_NEW) { nl_cache_move(cache, obj); if (old == NULL && cb) - cb(cache, obj, NL_ACT_NEW); + cb(cache, obj, NL_ACT_NEW, data); else if (old) { if (nl_object_diff(old, obj) && cb) - cb(cache, obj, NL_ACT_CHANGE); + cb(cache, obj, NL_ACT_CHANGE, data); nl_object_put(old); } @@ -533,36 +555,37 @@ static int cache_include(struct nl_cache *cache, struct nl_object *obj, } int nl_cache_include(struct nl_cache *cache, struct nl_object *obj, - change_func_t change_cb) + change_func_t change_cb, void *data) { struct nl_cache_ops *ops = cache->c_ops; int i; if (ops->co_obj_ops != obj->ce_ops) - return nl_error(EINVAL, "Object mismatches cache type"); + return -NLE_OBJ_MISMATCH; for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype) return cache_include(cache, obj, &ops->co_msgtypes[i], - change_cb); + change_cb, data); - return nl_errno(EINVAL); + return -NLE_MSGTYPE_NOSUPPORT; } static int resync_cb(struct nl_object *c, struct nl_parser_param *p) { struct nl_cache_assoc *ca = p->pp_arg; - return nl_cache_include(ca->ca_cache, c, ca->ca_change); + return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data); } -int nl_cache_resync(struct nl_handle *handle, struct nl_cache *cache, - change_func_t change_cb) +int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache, + change_func_t change_cb, void *data) { struct nl_object *obj, *next; struct nl_cache_assoc ca = { .ca_cache = cache, .ca_change = change_cb, + .ca_change_data = data, }; struct nl_parser_param p = { .pp_cb = resync_cb, @@ -575,17 +598,23 @@ int nl_cache_resync(struct nl_handle *handle, struct nl_cache *cache, /* Mark all objects so we can see if some of them are obsolete */ nl_cache_mark_all(cache); - err = nl_cache_request_full_dump(handle, cache); + err = nl_cache_request_full_dump(sk, cache); if (err < 0) goto errout; - err = __cache_pickup(handle, cache, &p); + err = __cache_pickup(sk, cache, &p); if (err < 0) goto errout; - nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) - if (nl_object_is_marked(obj)) + nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) { + if (nl_object_is_marked(obj)) { + nl_object_get(obj); nl_cache_remove(obj); + if (change_cb) + change_cb(cache, obj, NL_ACT_DEL, data); + nl_object_put(obj); + } + } NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache)); @@ -607,23 +636,19 @@ int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, { int i, err; - if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) { - err = nl_error(EINVAL, "netlink message too short to be " - "of kind %s", ops->co_name); - goto errout; - } + if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) + return -NLE_MSG_TOOSHORT; for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) { if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) { err = ops->co_msg_parser(ops, who, nlh, params); - if (err != -ENOENT) + if (err != -NLE_OPNOTSUPP) goto errout; } } - err = nl_error(EINVAL, "Unsupported netlink message type %d", - nlh->nlmsg_type); + err = -NLE_MSGTYPE_NOSUPPORT; errout: return err; } @@ -651,7 +676,7 @@ int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) /** * (Re)fill a cache with the contents in the kernel. - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg cache cache to update * * Clears the specified cache and fills it with the current state in @@ -659,11 +684,11 @@ int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) * * @return 0 or a negative error code. */ -int nl_cache_refill(struct nl_handle *handle, struct nl_cache *cache) +int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) { int err; - err = nl_cache_request_full_dump(handle, cache); + err = nl_cache_request_full_dump(sk, cache); if (err < 0) return err; @@ -671,7 +696,7 @@ int nl_cache_refill(struct nl_handle *handle, struct nl_cache *cache) cache, nl_cache_name(cache)); nl_cache_clear(cache); - return nl_cache_pickup(handle, cache); + return nl_cache_pickup(sk, cache); } /** @} */ @@ -728,7 +753,7 @@ void nl_cache_dump_filter(struct nl_cache *cache, struct nl_dump_params *params, struct nl_object *filter) { - int type = params ? params->dp_type : NL_DUMP_FULL; + int type = params ? params->dp_type : NL_DUMP_DETAILS; struct nl_object_ops *ops; struct nl_object *obj; diff --git a/lib/cache_mngr.c b/lib/cache_mngr.c index a144b92..81052aa 100644 --- a/lib/cache_mngr.c +++ b/lib/cache_mngr.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -95,7 +95,7 @@ static int include_cb(struct nl_object *obj, struct nl_parser_param *p) if (nl_debug >= 4) nl_object_dump(obj, &nl_debug_dp); #endif - return nl_cache_include(ca->ca_cache, obj, ca->ca_change); + return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data); } static int event_input(struct nl_msg *msg, void *arg) @@ -140,56 +140,55 @@ found: /** * Allocate new cache manager - * @arg handle Netlink socket/handle to be used + * @arg sk Netlink socket. * @arg protocol Netlink Protocol this manager is used for * @arg flags Flags * * @return Newly allocated cache manager or NULL on failure. */ -struct nl_cache_mngr *nl_cache_mngr_alloc(struct nl_handle *handle, - int protocol, int flags) +int nl_cache_mngr_alloc(struct nl_sock *sk, int protocol, int flags, + struct nl_cache_mngr **result) { struct nl_cache_mngr *mngr; + int err = -NLE_NOMEM; - if (handle == NULL) + if (sk == NULL) BUG(); mngr = calloc(1, sizeof(*mngr)); if (!mngr) - goto enomem; + goto errout; - mngr->cm_handle = handle; + mngr->cm_handle = sk; mngr->cm_nassocs = 32; mngr->cm_protocol = protocol; mngr->cm_flags = flags; mngr->cm_assocs = calloc(mngr->cm_nassocs, sizeof(struct nl_cache_assoc)); if (!mngr->cm_assocs) - goto enomem; - + goto errout; nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM, event_input, mngr); /* Required to receive async event notifications */ - nl_disable_sequence_check(mngr->cm_handle); + nl_socket_disable_seq_check(mngr->cm_handle); - if (nl_connect(mngr->cm_handle, protocol) < 0) + if ((err = nl_connect(mngr->cm_handle, protocol) < 0)) goto errout; - if (nl_socket_set_nonblocking(mngr->cm_handle) < 0) + if ((err = nl_socket_set_nonblocking(mngr->cm_handle) < 0)) goto errout; NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n", mngr, protocol, mngr->cm_nassocs); - return mngr; + *result = mngr; + return 0; -enomem: - nl_errno(ENOMEM); errout: nl_cache_mngr_free(mngr); - return NULL; + return err; } /** @@ -197,6 +196,7 @@ errout: * @arg mngr Cache manager. * @arg name Name of cache to keep track of * @arg cb Function to be called upon changes. + * @arg result Pointer to store added cache. * * Allocates a new cache of the specified type and adds it to the manager. * The operation will trigger a full dump request from the kernel to @@ -204,10 +204,10 @@ errout: * to the notification group of the cache to keep track of any further * changes. * - * @return The newly allocated cache or NULL on failure. + * @return 0 on success or a negative error code. */ -struct nl_cache *nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name, - change_func_t cb) +int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name, + change_func_t cb, void *data, struct nl_cache **result) { struct nl_cache_ops *ops; struct nl_cache *cache; @@ -215,28 +215,19 @@ struct nl_cache *nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name, int err, i; ops = nl_cache_ops_lookup(name); - if (!ops) { - nl_error(ENOENT, "Unknown cache type"); - return NULL; - } + if (!ops) + return -NLE_NOCACHE; - if (ops->co_protocol != mngr->cm_protocol) { - nl_error(EINVAL, "Netlink protocol mismatch"); - return NULL; - } + if (ops->co_protocol != mngr->cm_protocol) + return -NLE_PROTO_MISMATCH; - if (ops->co_groups == NULL) { - nl_error(EOPNOTSUPP, NULL); - return NULL; - } + if (ops->co_groups == NULL) + return -NLE_OPNOTSUPP; - for (i = 0; i < mngr->cm_nassocs; i++) { + for (i = 0; i < mngr->cm_nassocs; i++) if (mngr->cm_assocs[i].ca_cache && - mngr->cm_assocs[i].ca_cache->c_ops == ops) { - nl_error(EEXIST, "Cache of this type already managed"); - return NULL; - } - } + mngr->cm_assocs[i].ca_cache->c_ops == ops) + return -NLE_EXIST; retry: for (i = 0; i < mngr->cm_nassocs; i++) @@ -248,10 +239,9 @@ retry: mngr->cm_assocs = realloc(mngr->cm_assocs, mngr->cm_nassocs * sizeof(struct nl_cache_assoc)); - if (mngr->cm_assocs == NULL) { - nl_errno(ENOMEM); - return NULL; - } else { + if (mngr->cm_assocs == NULL) + return -NLE_NOMEM; + else { NL_DBG(1, "Increased capacity of cache manager %p " \ "to %d\n", mngr, mngr->cm_nassocs); goto retry; @@ -259,10 +249,8 @@ retry: } cache = nl_cache_alloc(ops); - if (!cache) { - nl_errno(ENOMEM); - return NULL; - } + if (!cache) + return -NLE_NOMEM; for (grp = ops->co_groups; grp->ag_group; grp++) { err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group); @@ -276,6 +264,7 @@ retry: mngr->cm_assocs[i].ca_cache = cache; mngr->cm_assocs[i].ca_change = cb; + mngr->cm_assocs[i].ca_change_data = data; if (mngr->cm_flags & NL_AUTO_PROVIDE) nl_cache_mngt_provide(cache); @@ -283,7 +272,8 @@ retry: NL_DBG(1, "Added cache %p <%s> to cache manager %p\n", cache, nl_cache_name(cache), mngr); - return cache; + *result = cache; + return 0; errout_drop_membership: for (grp = ops->co_groups; grp->ag_group; grp++) @@ -291,7 +281,7 @@ errout_drop_membership: errout_free_cache: nl_cache_free(cache); - return NULL; + return err; } /** @@ -334,7 +324,7 @@ int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout) ret = poll(&fds, 1, timeout); NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret); if (ret < 0) - return nl_errno(errno); + return -nl_syserr2nlerr(errno); if (ret == 0) return 0; @@ -365,20 +355,24 @@ int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr) } /** - * Free cache manager - * @arg mngr Cache manager + * Free cache manager and all caches. + * @arg mngr Cache manager. * * Release all resources after usage of a cache manager. */ void nl_cache_mngr_free(struct nl_cache_mngr *mngr) { + int i; + if (!mngr) return; - if (mngr->cm_handle) { + if (mngr->cm_handle) nl_close(mngr->cm_handle); - nl_handle_destroy(mngr->cm_handle); - } + + for (i = 0; i < mngr->cm_nassocs; i++) + if (mngr->cm_assocs[i].ca_cache) + nl_cache_free(mngr->cm_assocs[i].ca_cache); free(mngr->cm_assocs); free(mngr); diff --git a/lib/cache_mngt.c b/lib/cache_mngt.c index de2bf24..d57d836 100644 --- a/lib/cache_mngt.c +++ b/lib/cache_mngt.c @@ -6,10 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** + * @ingroup core * @defgroup cache_mngt Caching * @{ */ @@ -60,11 +61,14 @@ struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype) int i; struct nl_cache_ops *ops; - for (ops = cache_ops; ops; ops = ops->co_next) + for (ops = cache_ops; ops; ops = ops->co_next) { + if (ops->co_protocol != protocol) + continue; + for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) - if (ops->co_msgtypes[i].mt_id == msgtype && - ops->co_protocol == protocol) + if (ops->co_msgtypes[i].mt_id == msgtype) return ops; + } return NULL; } @@ -126,15 +130,12 @@ void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg) */ int nl_cache_mngt_register(struct nl_cache_ops *ops) { - if (!ops->co_name) - return nl_error(EINVAL, "No cache name specified"); - - if (!ops->co_obj_ops) - return nl_error(EINVAL, "No obj cache ops specified"); + if (!ops->co_name || !ops->co_obj_ops) + return -NLE_INVAL; if (nl_cache_ops_lookup(ops->co_name)) - return nl_error(EEXIST, "Cache operations already exist"); - + return -NLE_EXIST; + ops->co_next = cache_ops; cache_ops = ops; @@ -163,7 +164,7 @@ int nl_cache_mngt_unregister(struct nl_cache_ops *ops) break; if (!t) - return nl_error(ENOENT, "No such cache operations"); + return -NLE_NOCACHE; NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name); @@ -6,11 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup utils + * @ingroup core * @defgroup data Abstract Data * @{ */ @@ -56,11 +56,25 @@ struct nl_data *nl_data_alloc(void *buf, size_t size) return data; errout: - nl_errno(ENOMEM); return NULL; } /** + * Allocate abstract data object based on netlink attribute. + * @arg nla Netlink attribute of unspecific type. + * + * Allocates a new abstract data and copies the payload of the + * attribute to the abstract data object. + * + * @see nla_data_alloc + * @return Newly allocated data handle or NULL + */ +struct nl_data *nl_data_alloc_attr(struct nlattr *nla) +{ + return nl_data_alloc(nla_data(nla), nla_len(nla)); +} + +/** * Clone an abstract data object. * @arg src Abstract data object * @@ -90,7 +104,7 @@ int nl_data_append(struct nl_data *data, void *buf, size_t size) if (size > 0) { data->d_data = realloc(data->d_data, data->d_size + size); if (!data->d_data) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (buf) memcpy(data->d_data + data->d_size, buf, size); diff --git a/lib/defs.h.in b/lib/defs.h.in deleted file mode 100644 index ef86caa..0000000 --- a/lib/defs.h.in +++ /dev/null @@ -1,28 +0,0 @@ -/* lib/defs.h.in. Generated from configure.in by autoheader. */ - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* verbose errors */ -#undef VERBOSE_ERRORS - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif @@ -6,12 +6,28 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** * @mainpage * + * @section intro Introduction + * + * libnl is a set of libraries to deal with the netlink protocol and some + * of the high level protocols implemented on top of it. Its goal is to + * simplify netlink protocol usage and to create an abstraction layer using + * object based interfaces for various netlink based subsystems.The library + * was developed and tested on the 2.6.x kernel releases but it may work with + * older kernel series. + * + * @section toc Table of Contents + * + * - \subpage core_doc + * - \subpage route_doc + * - \subpage genl_doc + * - \subpage nf_doc + * * @section remarks Remarks * * @subsection cache_alloc Allocation of Caches @@ -19,7 +35,7 @@ * Almost all subsystem provide a function to allocate a new cache * of some form. The function usually looks like this: * @code - * struct nl_cache *<object name>_alloc_cache(struct nl_handle *handle) + * struct nl_cache *<object name>_alloc_cache(struct nl_sock *sk); * @endcode * * These functions allocate a new cache for the own object type, @@ -103,4 +119,366 @@ * to the corresponding numeric value. * * @return Identifier as numeric value or a negative value if none was found. + * + * @page core_doc Core Library (-lnl) + * + * @section core_intro Introduction + * + * The core library contains the fundamentals required to communicate over + * netlink sockets. It deals with connecting and unconnecting of sockets, + * sending and receiving of data, provides a customizeable receiving state + * machine, and provides a abstract data type framework which eases the + * implementation of object based netlink protocols where objects are added, + * removed, or modified with the help of netlink messages. + * + * @section core_toc Table of Contents + * + * - \ref proto_fund + * - \ref sk_doc + * - \ref rxtx_doc + * - \ref cb_doc + * + * @section proto_fund Netlink Protocol Fundamentals + * + * The netlink protocol is a socket based IPC mechanism used for communication + * between userspace processes and the kernel. The netlink protocol uses the + * \c AF_NETLINK address family and defines a protocol type for each subsystem + * protocol (e.g. NETLINK_ROUTE, NETLINK_NETFILTER, etc). Its addressing + * schema is based on a 32 bit port number, formerly referred to as PID, which + * uniquely identifies each peer. + * + * The netlink protocol is based on messages each limited to the size of a + * memory page and consists of the netlink message header (struct nlmsghdr) + * plus the payload attached to it. The payload can consist of arbitary data + * but often contains a fixed sized family specifc header followed by a + * stream of \ref attr_doc. The use of attributes dramatically increases + * the flexibility of the protocol and allows for the protocol to be + * extended while maintaining backwards compatibility. + * + * The netlink message header (struct nlmsghdr): + * @code + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-------------------------------------------------------------+ + * | Length | + * +------------------------------+------------------------------+ + * | Type | Flags | + * +------------------------------+------------------------------+ + * | Sequence Number | + * +-------------------------------------------------------------+ + * | Port (Address) | + * +-------------------------------------------------------------+ + * @endcode + * + * Netlink differs between requests, notifications, and replies. Requests + * are messages which have the \c NLM_F_REQUEST flag set and are meant to + * request an action from the receiver. A request is typically sent from + * a userspace process to the kernel. Every request should be assigned a + * sequence number which should be incremented for each request sent on the + * sending side. Depending on the nature of the request, the receiver may + * reply to the request with regular netlink messages which should contain + * the same sequence number as the request it relates to. Notifications are + * of informal nature and don't expect a reply, therefore the sequence number + * is typically set to 0. It should be noted that unlike in protocols such as + * TCP there is no strict enforcment of the sequence number. The sole purpose + * of sequence numbers is to assist a sender in relating replies to the + * corresponding requests. + * + * @msc + * A,B; + * A=>B [label="GET (seq=1, NLM_F_REQUEST)"]; + * A<=B [label="PUT (seq=1)"]; + * ...; + * A<=B [label="NOTIFY (seq=0)"]; + * @endmsc + * + * If the size of a reply exceeds the size of a memory page and thus exceeds + * the maximum message size, the reply can be split into a series of multipart + * messages. A multipart message has the \c flag NLM_F_MULTI set and the + * receiver is expected to continue parsing the reply until the special + * message type \c NLMSG_DONE is received. + * + * @msc + * A,B; + * A=>B [label="GET (seq=1, NLM_F_REQUEST)"]; + * A<=B [label="PUT (seq=1, NLM_F_MULTI)"]; + * ...; + * A<=B [label="PUT (seq=1, NLM_F_MULTI)"]; + * A<=B [label="NLMSG_DONE (seq=1)"]; + * @endmsc + * + * Errors can be reported using the standard message type \c NLMSG_ERROR which + * can carry an error code and the netlink mesage header of the request. + * Error messages should set their sequence number to the sequence number + * of the message which caused the error. + * + * @msc + * A,B; + * A=>B [label="GET (seq=1, NLM_F_REQUEST)"]; + * A<=B [label="NLMSG_ERROR code=EINVAL (seq=1)"]; + * @endmsc + * + * The \c NLMSG_ERROR message type is also used to send acknowledge messages. + * An acknowledge message can be requested by setting the \c NLM_F_ACK flag + * message except that the error code is set to 0. + * + * @msc + * A,B; + * A=>B [label="GET (seq=1, NLM_F_REQUEST | NLM_F_ACK)"]; + * A<=B [label="ACK (seq=1)"]; + * @endmsc + * + * @section sk_doc Dealing with Netlink Sockets + * + * In order to use the netlink protocol, a netlink socket is required. Each + * socket defines a completely independent context for sending and receiving + * of messages. The netlink socket and all its related attributes are + * represented by struct nl_sock. + * + * @code + * nl_socket_alloc() Allocate new socket structure. + * nl_socket_free(s) Free socket structure. + * @endcode + * + * @subsection local_port Local Port + * The local port number uniquely identifies the socket and is used to + * address it. A unique local port is generated automatically when the socket + * is allocated. It will consist of the Process ID (22 bits) and a random + * number (10 bits) to allow up to 1024 sockets per process. + * + * @code + * nl_socket_get_local_port(sk) Return the peer's port number. + * nl_socket_set_local_port(sk, port) Set the peer's port number. + * @endcode + * + * @subsection peer_port Peer Port + * A peer port can be assigned to the socket which will result in all unicast + * messages sent over the socket to be addresses to the corresponding peer. If + * no peer is specified, the kernel will try to automatically bind the socket + * to a kernel side socket of the same netlink protocol family. It is common + * practice not to bind the socket to a peer port as typically only one kernel + * side socket exists per netlink protocol family. + * + * @code + * nl_socket_get_peer_port(sk) Return the local port number. + * nl_socket_set_peer_port(sk, port) Set the local port number. + * @endcode + * + * @subsection sock_fd File Descriptor + * The file descriptor of the socket(2). + * + * @code + * nl_socket_get_fd(sk) Return file descriptor. + * nl_socket_set_buffer_size(sk, rx, tx) Set buffer size of socket. + * nl_socket_set_nonblocking(sk) Set socket to non-blocking state. + * @endcode + * + * @subsection group_sub Group Subscriptions + * Each socket can subscribe to multicast groups of the netlink protocol + * family it is bound to. The socket will then receive a copy of each + * message sent to any of the groups. Multicast groups are commonly used + * to implement event notifications. Prior to kernel 2.6.14 the group + * subscription was performed using a bitmask which limited the number of + * groups per protocol family to 32. This outdated interface can still be + * accessed via the function nl_join_groups even though it is not recommended + * for new code. Starting with 2.6.14 a new method was introduced which + * supports subscribing to an almost unlimited number of multicast groups. + * + * @code + * nl_socket_add_membership(sk, group) Become a member of a multicast group. + * nl_socket_drop_membership(sk, group) Drop multicast group membership. + * nl_join_groups(sk, groupmask) Join a multicast group (obsolete). + * @endcode + * + * @subsection seq_num Sequence Numbers + * The socket keeps track of the sequence numbers used. The library will + * automatically verify the sequence number of messages received unless + * the check was disabled using the function nl_socket_disable_seq_check(). + * When a message is sent using nl_send_auto_complete(), the sequence number + * is automatically filled in, and replies will be verified correctly. + * + * @code + * nl_socket_disable_seq_check(sk) Disable checking of sequece numbers. + * nl_socket_use_seq(sk) Use sequence number and bump to next. + * @endcode + * + * @subsection sock_cb Callback Configuration + * Every socket is associated a callback configuration which enables the + * applications to hook into various internal functions and control the + * receiving and sendings semantics. For more information, see section + * \ref cb_doc. + * + * @code + * nl_socket_alloc_cb(cb) Allocate socket based on callback set. + * nl_socket_get_cb(sk) Return callback configuration. + * nl_socket_set_cb(sk, cb) Replace callback configuration. + * nl_socket_modify_cb(sk, ...) Modify a specific callback function. + * @endcode + * + * @subsection sk_other Other Functions + * @code + * nl_socket_enable_auto_ack(sock) Enable automatic request of ACK. + * nl_socket_disable_auto_ack(sock) Disable automatic request of ACK. + * nl_socket_enable_msg_peek(sock) Enable message peeking. + * nl_socket_disable_msg_peek(sock) Disable message peeking. + * nl_socket_set_passcred(sk, state) Enable/disable credential passing. + * nl_socket_recv_pktinfo(sk, state) Enable/disable packet information. + * @endcode + * + * @section rxtx_doc Sending and Receiving of Data + * + * @subsection recv_semantisc Receiving Semantics + * @code + * nl_recvmsgs_default(set) + * | cb = nl_socket_get_cb(sk) + * v + * nl_recvmsgs(sk, cb) + * | [Application provides nl_recvmsgs() replacement] + * |- - - - - - - - - - - - - - - v + * | cb->cb_recvmsgs_ow() + * | + * | [Application provides nl_recv() replacement] + * +-------------->|- - - - - - - - - - - - - - - v + * | nl_recv() cb->cb_recv_ow() + * | +----------->|<- - - - - - - - - - - - - - -+ + * | | v + * | | Parse Message + * | | |- - - - - - - - - - - - - - - v + * | | | NL_CB_MSG_IN() + * | | |<- - - - - - - - - - - - - - -+ + * | | | + * | | |- - - - - - - - - - - - - - - v + * | | Sequence Check NL_CB_SEQ_CHECK() + * | | |<- - - - - - - - - - - - - - -+ + * | | | + * | | |- - - - - - - - - - - - - - - v [ NLM_F_ACK is set ] + * | | | NL_CB_SEND_ACK() + * | | |<- - - - - - - - - - - - - - -+ + * | | | + * | | +-----+------+--------------+----------------+--------------+ + * | | v v v v v + * | | Valid Message ACK NO-OP Message End of Multipart Error + * | | | | | | | + * | | v v v v v + * | |NL_CB_VALID() NL_CB_ACK() NL_CB_SKIPPED() NL_CB_FINISH() cb->cb_err() + * | | | | | | | + * | | +------------+--------------+----------------+ v + * | | | (FAILURE) + * | | | [Callback returned NL_SKIP] + * | | [More messages to be parsed] |<----------- + * | +----------------------------------| + * | | + * | [is Multipart message] | + * +-------------------------------------| [Callback returned NL_STOP] + * |<----------- + * v + * (SUCCESS) + * + * At any time: + * Message Format Error + * |- - - - - - - - - - - - v + * v NL_CB_INVALID() + * (FAILURE) + * + * Message Overrun (Kernel Lost Data) + * |- - - - - - - - - - - - v + * v NL_CB_OVERRUN() + * (FAILURE) + * + * Callback returned negative error code + * (FAILURE) + * @endcode + * + * @subsection send_semantics Sending Semantisc + * + * @code + * nl_send_auto_complete(sk, msg) + * | [Automatically completes netlink message header] + * | [(local port, sequence number) ] + * | + * | [Application provies nl_send() replacement] + * |- - - - - - - - - - - - - - - - - - - - v + * v cb->cb_send_ow() + * nl_send(sk, msg) + * | [If available, add peer port and credentials] + * v + * nl_sendmsg(sk, msg, msghdr) + * |- - - - - - - - - - - - - - - - - - - - v + * | NL_CB_MSG_OUT() + * |<- - - - - - - - - - - - - - - - - - - -+ + * v + * sendmsg() + * @endcode + * + * @section cb_doc Callback Configurations + * Callbacks and overwriting capabilities are provided to control various + * semantics of the library. All callback functions are packed together in + * struct nl_cb which is attached to a netlink socket or passed on to + * the respective functions directly. + * + * @subsection cb_ret_doc Callback Return Values + * Callback functions can control the flow of the calling layer by returning + * appropriate error codes: + * @code + * Action ID | Description + * -----------------+------------------------------------------------------- + * NL_OK | Proceed with whatever comes next. + * NL_SKIP | Skip message currently being processed and continue + * | with next message. + * NL_STOP | Stop parsing and discard all remaining messages in + * | this set of messages. + * @endcode + * + * All callbacks are optional and a default action is performed if no + * application specific implementation is provided: + * + * @code + * Callback ID | Default Return Value + * ------------------+---------------------- + * NL_CB_VALID | NL_OK + * NL_CB_FINISH | NL_STOP + * NL_CB_OVERRUN | NL_STOP + * NL_CB_SKIPPED | NL_SKIP + * NL_CB_ACK | NL_STOP + * NL_CB_MSG_IN | NL_OK + * NL_CB_MSG_OUT | NL_OK + * NL_CB_INVALID | NL_STOP + * NL_CB_SEQ_CHECK | NL_OK + * NL_CB_SEND_ACK | NL_OK + * | + * Error Callback | NL_STOP + * @endcode + * + * In order to simplify typical usages of the library, different sets of + * default callback implementations exist: + * @code + * NL_CB_DEFAULT: No additional actions + * NL_CB_VERBOSE: Automatically print warning and error messages to a file + * descriptor as appropriate. This is useful for CLI based + * applications. + * NL_CB_DEBUG: Print informal debugging information for each message + * received. This will result in every message beint sent or + * received to be printed to the screen in a decoded, + * human-readable format. + * @endcode + * + * @par 1) Setting up a callback set + * @code + * // Allocate a callback set and initialize it to the verbose default set + * struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE); + * + * // Modify the set to call my_func() for all valid messages + * nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL); + * + * // Set the error message handler to the verbose default implementation + * // and direct it to print all errors to the given file descriptor. + * FILE *file = fopen(...); + * nl_cb_err(cb, NL_CB_VERBOSE, NULL, file); + * @endcode + * + * @page route_doc Routing Family + * + * @page genl_doc Generic Netlink Family + * + * @page nf_doc Netfilter Subsystem */ diff --git a/lib/error.c b/lib/error.c new file mode 100644 index 0000000..9a9fac7 --- /dev/null +++ b/lib/error.c @@ -0,0 +1,110 @@ +/* + * lib/error.c Error Handling + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink-local.h> +#include <netlink/netlink.h> + +static const char *errmsg[NLE_MAX+1] = { +[NLE_SUCCESS] = "Success", +[NLE_FAILURE] = "Unspecific failure", +[NLE_INTR] = "Interrupted system call", +[NLE_BAD_SOCK] = "Bad socket", +[NLE_AGAIN] = "Try again", +[NLE_NOMEM] = "Out of memory", +[NLE_EXIST] = "Object exists", +[NLE_INVAL] = "Invalid input data or parameter", +[NLE_RANGE] = "Input data out of range", +[NLE_MSGSIZE] = "Message size not sufficient", +[NLE_OPNOTSUPP] = "Operation not supported", +[NLE_AF_NOSUPPORT] = "Address family not supported", +[NLE_OBJ_NOTFOUND] = "Object not found", +[NLE_NOATTR] = "Attribute not available", +[NLE_MISSING_ATTR] = "Missing attribute", +[NLE_AF_MISMATCH] = "Address family mismatch", +[NLE_SEQ_MISMATCH] = "Message sequence number mismatch", +[NLE_MSG_OVERFLOW] = "Kernel reported message overflow", +[NLE_MSG_TRUNC] = "Kernel reported truncated message", +[NLE_NOADDR] = "Invalid address for specified address family", +[NLE_SRCRT_NOSUPPORT] = "Source based routing not supported", +[NLE_MSG_TOOSHORT] = "Netlink message is too short", +[NLE_MSGTYPE_NOSUPPORT] = "Netlink message type is not supported", +[NLE_OBJ_MISMATCH] = "Object type does not match cache", +[NLE_NOCACHE] = "Unknown or invalid cache type", +[NLE_BUSY] = "Object busy", +[NLE_PROTO_MISMATCH] = "Protocol mismatch", +[NLE_NOACCESS] = "No Access", +[NLE_PERM] = "Operation not permitted", +[NLE_PKTLOC_FILE] = "Unable to open packet location file", +}; + +/** + * Return error message for an error code + * @return error message + */ +const char *nl_geterror(int error) +{ + error = abs(error); + + if (error > NLE_MAX) + error = NLE_FAILURE; + + return errmsg[error]; +} + +/** + * Print a libnl error message + * @arg s error message prefix + * + * Prints the error message of the call that failed last. + * + * If s is not NULL and *s is not a null byte the argument + * string is printed, followed by a colon and a blank. Then + * the error message and a new-line. + */ +void nl_perror(int error, const char *s) +{ + if (s && *s) + fprintf(stderr, "%s: %s\n", s, nl_geterror(error)); + else + fprintf(stderr, "%s\n", nl_geterror(error)); +} + +int nl_syserr2nlerr(int error) +{ + error = abs(error); + + switch (error) { + case EBADF: return NLE_BAD_SOCK; + case EADDRINUSE: return NLE_EXIST; + case EEXIST: return NLE_EXIST; + case EADDRNOTAVAIL: return NLE_NOADDR; + case ENOENT: return NLE_OBJ_NOTFOUND; + case EINTR: return NLE_INTR; + case EAGAIN: return NLE_AGAIN; + case ENOTSOCK: return NLE_BAD_SOCK; + case ENOPROTOOPT: return NLE_INVAL; + case EFAULT: return NLE_INVAL; + case EACCES: return NLE_NOACCESS; + case EINVAL: return NLE_INVAL; + case ENOBUFS: return NLE_NOMEM; + case ENOMEM: return NLE_NOMEM; + case EAFNOSUPPORT: return NLE_AF_NOSUPPORT; + case EPROTONOSUPPORT: return NLE_PROTO_MISMATCH; + case EOPNOTSUPP: return NLE_OPNOTSUPP; + case EPERM: return NLE_PERM; + case EBUSY: return NLE_BUSY; + case ERANGE: return NLE_RANGE; + default: return NLE_FAILURE; + } +} + +/** @} */ + diff --git a/lib/family.c b/lib/family.c deleted file mode 100644 index ba1d65f..0000000 --- a/lib/family.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * lib/family.c Netlink Family - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -/** - * @defgroup nlfam Netlink Families - * @brief - * - * @{ - */ - -#include <netlink-local.h> -#include <netlink/netlink.h> -#include <netlink/utils.h> - -/** - * @name Netlink Family Name Translation - * @{ - */ - -static struct trans_tbl nlfamilies[] = { - __ADD(NETLINK_ROUTE,route) - __ADD(NETLINK_USERSOCK,usersock) - __ADD(NETLINK_FIREWALL,firewall) - __ADD(NETLINK_INET_DIAG,inetdiag) - __ADD(NETLINK_NFLOG,nflog) - __ADD(NETLINK_XFRM,xfrm) - __ADD(NETLINK_SELINUX,selinux) - __ADD(NETLINK_ISCSI,iscsi) - __ADD(NETLINK_AUDIT,audit) - __ADD(NETLINK_FIB_LOOKUP,fib_lookup) - __ADD(NETLINK_CONNECTOR,connector) - __ADD(NETLINK_NETFILTER,netfilter) - __ADD(NETLINK_IP6_FW,ip6_fw) - __ADD(NETLINK_DNRTMSG,dnrtmsg) - __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent) - __ADD(NETLINK_GENERIC,generic) - __ADD(NETLINK_SCSITRANSPORT,scsitransport) - __ADD(NETLINK_ECRYPTFS,ecryptfs) -}; - -char * nl_nlfamily2str(int family, char *buf, size_t size) -{ - return __type2str(family, buf, size, nlfamilies, - ARRAY_SIZE(nlfamilies)); -} - -int nl_str2nlfamily(const char *name) -{ - return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies)); -} - -/** @} */ - -/** @} */ diff --git a/lib/fib_lookup/lookup.c b/lib/fib_lookup/lookup.c index 5766035..ce9c027 100644 --- a/lib/fib_lookup/lookup.c +++ b/lib/fib_lookup/lookup.c @@ -6,11 +6,10 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup nlfam * @defgroup fib_lookup FIB Lookup * @brief * @{ @@ -63,7 +62,7 @@ static int result_clone(struct nl_object *_dst, struct nl_object *_src) if (src->fr_req) if (!(dst->fr_req = (struct flnl_request *) nl_object_clone(OBJ_CAST(src->fr_req)))) - return nl_get_errno(); + return -NLE_NOMEM; return 0; } @@ -74,7 +73,7 @@ static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct flnl_result *res; struct fib_result_nl *fr; struct nl_addr *addr; - int err = -EINVAL; + int err = -NLE_INVAL; res = flnl_result_alloc(); if (!res) @@ -121,27 +120,24 @@ errout: return err; } -static int result_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p) { struct flnl_result *res = (struct flnl_result *) obj; char buf[128]; - int line = 1; - dp_dump(p, "table %s prefixlen %u next-hop-selector %u\n", + nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n", rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)), res->fr_prefixlen, res->fr_nh_sel); - dp_dump_line(p, line++, "type %s ", + nl_dump_line(p, "type %s ", nl_rtntype2str(res->fr_type, buf, sizeof(buf))); - dp_dump(p, "scope %s error %s (%d)\n", + nl_dump(p, "scope %s error %s (%d)\n", rtnl_scope2str(res->fr_scope, buf, sizeof(buf)), strerror(-res->fr_error), res->fr_error); - - return line; } -static int result_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p) { - return result_dump_brief(obj, p); + result_dump_line(obj, p); } static int result_compare(struct nl_object *_a, struct nl_object *_b, @@ -209,7 +205,8 @@ struct nl_cache *flnl_result_alloc_cache(void) * @note Not all attributes can be changed, see * \ref link_changeable "Changeable Attributes" for more details. */ -struct nl_msg *flnl_lookup_build_request(struct flnl_request *req, int flags) +int flnl_lookup_build_request(struct flnl_request *req, int flags, + struct nl_msg **result) { struct nl_msg *msg; struct nl_addr *addr; @@ -228,30 +225,29 @@ struct nl_msg *flnl_lookup_build_request(struct flnl_request *req, int flags) fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC; addr = flnl_request_get_addr(req); - if (!addr) { - nl_error(EINVAL, "Request must specify the address"); - return NULL; - } + if (!addr) + return -NLE_MISSING_ATTR; fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr); msg = nlmsg_alloc_simple(0, flags); if (!msg) - goto errout; + return -NLE_NOMEM; if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0) goto errout; - return msg; + *result = msg; + return 0; errout: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** * Perform FIB Lookup - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg req Lookup request object. * @arg cache Cache for result. * @@ -260,22 +256,21 @@ errout: * * @return 0 on success or a negative error code. */ -int flnl_lookup(struct nl_handle *handle, struct flnl_request *req, +int flnl_lookup(struct nl_sock *sk, struct flnl_request *req, struct nl_cache *cache) { struct nl_msg *msg; int err; - msg = flnl_lookup_build_request(req, 0); - if (!msg) - return nl_errno(ENOMEM); + if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_cache_pickup(handle, cache); + return nl_cache_pickup(sk, cache); } /** @} */ @@ -322,8 +317,10 @@ static struct nl_object_ops result_obj_ops = { .oo_size = sizeof(struct flnl_result), .oo_free_data = result_free_data, .oo_clone = result_clone, - .oo_dump[NL_DUMP_BRIEF] = result_dump_brief, - .oo_dump[NL_DUMP_FULL] = result_dump_full, + .oo_dump = { + [NL_DUMP_LINE] = result_dump_line, + [NL_DUMP_DETAILS] = result_dump_details, + }, .oo_compare = result_compare, }; diff --git a/lib/fib_lookup/request.c b/lib/fib_lookup/request.c index 8b00224..ffcf8f5 100644 --- a/lib/fib_lookup/request.c +++ b/lib/fib_lookup/request.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -48,11 +48,9 @@ static int request_clone(struct nl_object *_dst, struct nl_object *_src) if (src->lr_addr) if (!(dst->lr_addr = nl_addr_clone(src->lr_addr))) - goto errout; + return -NLE_NOMEM; return 0; -errout: - return nl_get_errno(); } static int request_compare(struct nl_object *_a, struct nl_object *_b, @@ -152,7 +150,7 @@ int flnl_request_get_table(struct flnl_request *req) int flnl_request_set_addr(struct flnl_request *req, struct nl_addr *addr) { if (addr->a_family != AF_INET) - return nl_error(EINVAL, "Address must be an IPv4 address"); + return -NLE_AF_NOSUPPORT; if (req->lr_addr) nl_addr_put(req->lr_addr); diff --git a/lib/genl/ctrl.c b/lib/genl/ctrl.c index 9948a57..1301642 100644 --- a/lib/genl/ctrl.c +++ b/lib/genl/ctrl.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -31,7 +31,7 @@ static struct nl_cache_ops genl_ctrl_ops; /** @endcond */ -static int ctrl_request_update(struct nl_cache *c, struct nl_handle *h) +static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h) { return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, CTRL_VERSION, NLM_F_DUMP); @@ -61,17 +61,17 @@ static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd, family = genl_family_alloc(); if (family == NULL) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) { - err = nl_error(EINVAL, "Missing family name TLV"); + err = -NLE_MISSING_ATTR; goto errout; } if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) { - err = nl_error(EINVAL, "Missing family id TLV"); + err = -NLE_MISSING_ATTR; goto errout; } @@ -111,7 +111,7 @@ static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd, goto errout; if (tb[CTRL_ATTR_OP_ID] == NULL) { - err = nl_errno(EINVAL); + err = -NLE_MISSING_ATTR; goto errout; } @@ -128,11 +128,6 @@ static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd, } err = pp->pp_cb((struct nl_object *) family, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; - errout: genl_family_put(family); return err; @@ -143,20 +138,9 @@ errout: * @{ */ -struct nl_cache *genl_ctrl_alloc_cache(struct nl_handle *handle) +int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result) { - struct nl_cache * cache; - - cache = nl_cache_alloc(&genl_ctrl_ops); - if (cache == NULL) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - return cache; + return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result); } /** @@ -227,7 +211,7 @@ struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, /** * Resolve generic netlink family name to its identifier - * @arg handle Netlink Handle + * @arg sk Netlink socket. * @arg name Name of generic netlink family * * Resolves the generic netlink family name to its identifer and returns @@ -235,19 +219,18 @@ struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, * * @return A positive identifier or a negative error code. */ -int genl_ctrl_resolve(struct nl_handle *handle, const char *name) +int genl_ctrl_resolve(struct nl_sock *sk, const char *name) { struct nl_cache *cache; struct genl_family *family; int err; - cache = genl_ctrl_alloc_cache(handle); - if (cache == NULL) - return nl_get_errno(); + if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0) + return err; family = genl_ctrl_search_by_name(cache, name); if (family == NULL) { - err = nl_error(ENOENT, "Generic Netlink Family not found"); + err = -NLE_OBJ_NOTFOUND; goto errout; } diff --git a/lib/genl/family.c b/lib/genl/family.c index e05b52c..4c6c18d 100644 --- a/lib/genl/family.c +++ b/lib/genl/family.c @@ -71,14 +71,12 @@ static int family_clone(struct nl_object *_dst, struct nl_object *_src) return 0; } -static int family_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p) { struct genl_family *family = (struct genl_family *) obj; - dp_dump(p, "0x%04x %s version %u\n", + nl_dump(p, "0x%04x %s version %u\n", family->gf_id, family->gf_name, family->gf_version); - - return 1; } static struct trans_tbl ops_flags[] = { @@ -93,13 +91,12 @@ static char *ops_flags2str(int flags, char *buf, size_t len) return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags)); } -static int family_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p) { struct genl_family *family = (struct genl_family *) obj; - int line; - line = family_dump_brief(obj, p); - dp_dump_line(p, line++, " hdrsize %u maxattr %u\n", + family_dump_line(obj, p); + nl_dump_line(p, " hdrsize %u maxattr %u\n", family->gf_hdrsize, family->gf_maxattr); if (family->ce_mask & FAMILY_ATTR_OPS) { @@ -111,24 +108,21 @@ static int family_dump_full(struct nl_object *obj, struct nl_dump_params *p) genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf)); - dp_dump_line(p, line++, " op %s (0x%02x)", - buf, op->o_id); + nl_dump_line(p, " op %s (0x%02x)", buf, op->o_id); if (op->o_flags) - dp_dump(p, " <%s>", + nl_dump(p, " <%s>", ops_flags2str(op->o_flags, buf, sizeof(buf))); - dp_dump(p, "\n"); + nl_dump(p, "\n"); } } - - return line; } -static int family_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { - return family_dump_full(obj, p); + family_dump_details(obj, p); } static int family_compare(struct nl_object *_a, struct nl_object *_b, @@ -250,7 +244,7 @@ int genl_family_add_op(struct genl_family *family, int id, int flags) op = calloc(1, sizeof(*op)); if (op == NULL) - return nl_errno(ENOMEM); + return -NLE_NOMEM; op->o_id = id; op->o_flags = flags; @@ -270,13 +264,11 @@ struct nl_object_ops genl_family_ops = { .oo_constructor = family_constructor, .oo_free_data = family_free_data, .oo_clone = family_clone, - .oo_dump[NL_DUMP_BRIEF] = family_dump_brief, - .oo_dump[NL_DUMP_FULL] = family_dump_full, - .oo_dump[NL_DUMP_STATS] = family_dump_stats, -#if 0 - .oo_dump[NL_DUMP_XML] = addr_dump_xml, - .oo_dump[NL_DUMP_ENV] = addr_dump_env, -#endif + .oo_dump = { + [NL_DUMP_LINE] = family_dump_line, + [NL_DUMP_DETAILS] = family_dump_details, + [NL_DUMP_STATS] = family_dump_stats, + }, .oo_compare = family_compare, .oo_id_attrs = FAMILY_ATTR_ID, }; diff --git a/lib/genl/genl.c b/lib/genl/genl.c index 04cfebf..055be91 100644 --- a/lib/genl/genl.c +++ b/lib/genl/genl.c @@ -6,11 +6,10 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup nlfam * @defgroup genl Generic Netlink * * @par Message Format @@ -38,12 +37,12 @@ * #include <netlink/genl/genl.h> * #include <netlink/genl/ctrl.h> * - * struct nl_handle *sock; + * struct nl_sock *sock; * struct nl_msg *msg; * int family; * * // Allocate a new netlink socket - * sock = nl_handle_alloc(); + * sock = nl_socket_alloc(); * * // Connect to generic netlink socket on kernel side * genl_connect(sock); @@ -100,9 +99,9 @@ * @{ */ -int genl_connect(struct nl_handle *handle) +int genl_connect(struct nl_sock *sk) { - return nl_connect(handle, NETLINK_GENERIC); + return nl_connect(sk, NETLINK_GENERIC); } /** @} */ @@ -114,7 +113,7 @@ int genl_connect(struct nl_handle *handle) /** * Send trivial generic netlink message - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg family Generic netlink family * @arg cmd Command * @arg version Version @@ -125,7 +124,7 @@ int genl_connect(struct nl_handle *handle) * * @return 0 on success or a negative error code. */ -int genl_send_simple(struct nl_handle *handle, int family, int cmd, +int genl_send_simple(struct nl_sock *sk, int family, int cmd, int version, int flags) { struct genlmsghdr hdr = { @@ -133,7 +132,7 @@ int genl_send_simple(struct nl_handle *handle, int family, int cmd, .version = version, }; - return nl_send_simple(handle, family, flags, &hdr, sizeof(hdr)); + return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr)); } /** @} */ @@ -164,7 +163,7 @@ int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, struct genlmsghdr *ghdr; if (!genlmsg_valid_hdr(nlh, hdrlen)) - return nl_errno(EINVAL); + return -NLE_MSG_TOOSHORT; ghdr = nlmsg_data(nlh); return nla_validate(genlmsg_attrdata(ghdr, hdrlen), @@ -177,7 +176,7 @@ int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], struct genlmsghdr *ghdr; if (!genlmsg_valid_hdr(nlh, hdrlen)) - return nl_errno(EINVAL); + return -NLE_MSG_TOOSHORT; ghdr = nlmsg_data(nlh); return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen), diff --git a/lib/genl/mngt.c b/lib/genl/mngt.c index d737697..0ebe74d 100644 --- a/lib/genl/mngt.c +++ b/lib/genl/mngt.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -108,12 +108,12 @@ static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, goto found; } - err = nl_errno(ENOENT); + err = -NLE_MSGTYPE_NOSUPPORT; goto errout; found: if (cmd->c_msg_parser == NULL) - err = nl_error(EOPNOTSUPP, "No message parser found."); + err = -NLE_OPNOTSUPP; else { struct nlattr *tb[cmd->c_maxattr + 1]; struct genl_info info = { @@ -174,22 +174,17 @@ int genl_register(struct nl_cache_ops *ops) int err; if (ops->co_protocol != NETLINK_GENERIC) { - err = nl_error(EINVAL, "cache operations not for protocol " \ - "NETLINK_GENERIC (protocol=%s)", - ops->co_protocol); + err = -NLE_PROTO_MISMATCH; goto errout; } if (ops->co_hdrsize < GENL_HDRSIZE(0)) { - err = nl_error(EINVAL, "co_hdrsize too short, probably " \ - "not including genlmsghdr, minsize=%d", - GENL_HDRSIZE(0)); + err = -NLE_INVAL; goto errout; } if (ops->co_genl == NULL) { - err = nl_error(EINVAL, "co_genl is NULL, must provide " \ - "valid genl operations"); + err = -NLE_INVAL; goto errout; } @@ -236,20 +231,16 @@ static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops) return 0; } - return nl_error(ENOENT, "Unable to find generic netlink family \"%s\"", - ops->o_name); + return -NLE_OBJ_NOTFOUND; } -int genl_ops_resolve(struct nl_handle *handle, struct genl_ops *ops) +int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops) { struct nl_cache *ctrl; int err; - ctrl = genl_ctrl_alloc_cache(handle); - if (ctrl == NULL) { - err = nl_get_errno(); + if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) goto errout; - } err = __genl_ops_resolve(ctrl, ops); @@ -258,17 +249,14 @@ errout: return err; } -int genl_mngt_resolve(struct nl_handle *handle) +int genl_mngt_resolve(struct nl_sock *sk) { struct nl_cache *ctrl; struct genl_ops *ops; int err = 0; - ctrl = genl_ctrl_alloc_cache(handle); - if (ctrl == NULL) { - err = nl_get_errno(); + if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) goto errout; - } nl_list_for_each_entry(ops, &genl_ops_list, o_list) { err = __genl_ops_resolve(ctrl, ops); diff --git a/lib/handlers.c b/lib/handlers.c index 1797e4f..f13b89e 100644 --- a/lib/handlers.c +++ b/lib/handlers.c @@ -6,64 +6,14 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup nl + * @ingroup core * @defgroup cb Callbacks/Customization - * @brief - * - * Callbacks and overwriting capabilities are provided to take influence - * in various control flows inside the library. All callbacks are packed - * together in struct nl_cb which is then attached to a netlink socket or - * passed on to the respective functions directly. - * - * Callbacks can control the flow of the underlying layer by returning - * the appropriate error codes: - * @code - * Action ID | Description - * -----------------+------------------------------------------------------- - * NL_OK | Proceed with whatever comes next. - * NL_SKIP | Skip message currently being processed and continue - * | with next message. - * NL_STOP | Stop parsing and discard all remaining messages in - * | this set of messages. - * @endcode - * - * All callbacks are optional and a default action is performed if no - * application specific implementation is provided: - * - * @code - * Callback ID | Default Return Value - * ------------------+---------------------- - * NL_CB_VALID | NL_OK - * NL_CB_FINISH | NL_STOP - * NL_CB_OVERRUN | NL_STOP - * NL_CB_SKIPPED | NL_SKIP - * NL_CB_ACK | NL_STOP - * NL_CB_MSG_IN | NL_OK - * NL_CB_MSG_OUT | NL_OK - * NL_CB_INVALID | NL_STOP - * NL_CB_SEQ_CHECK | NL_OK - * NL_CB_SEND_ACK | NL_OK - * | - * Error Callback | NL_STOP - * @endcode - * - * In order to simplify typical usages of the library, different sets of - * default callback implementations exist: - * @code - * NL_CB_DEFAULT: No additional actions - * NL_CB_VERBOSE: Automatically print warning and error messages to a file - * descriptor as appropriate. This is useful for CLI based - * applications. - * NL_CB_DEBUG: Print informal debugging information for each message - * received. This will result in every message beint sent or - * received to be printed to the screen in a decoded, - * human-readable format. - * @endcode * + * @details * @par 1) Setting up a callback set * @code * // Allocate a callback set and initialize it to the verbose default set @@ -140,7 +90,7 @@ static int nl_error_handler_verbose(struct sockaddr_nl *who, print_header_content(ofd, &e->msg); fprintf(ofd, "\n"); - return e->error; + return -nl_syserr2nlerr(e->error); } static int nl_valid_handler_debug(struct nl_msg *msg, void *arg) @@ -261,10 +211,8 @@ struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind) return NULL; cb = calloc(1, sizeof(*cb)); - if (!cb) { - nl_errno(ENOMEM); + if (!cb) return NULL; - } cb->cb_refcnt = 1; @@ -338,10 +286,10 @@ int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg) { if (type < 0 || type > NL_CB_TYPE_MAX) - return nl_error(ERANGE, "Callback type out of range"); + return -NLE_RANGE; if (kind < 0 || kind > NL_CB_KIND_MAX) - return nl_error(ERANGE, "Callback kind out of range"); + return -NLE_RANGE; if (kind == NL_CB_CUSTOM) { cb->cb_set[type] = func; @@ -388,7 +336,7 @@ int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg) { if (kind < 0 || kind > NL_CB_KIND_MAX) - return nl_error(ERANGE, "Callback kind out of range"); + return -NLE_RANGE; if (kind == NL_CB_CUSTOM) { cb->cb_err = func; @@ -414,7 +362,7 @@ int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, * @arg func replacement callback for nl_recvmsgs() */ void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, - int (*func)(struct nl_handle *, struct nl_cb *)) + int (*func)(struct nl_sock *, struct nl_cb *)) { cb->cb_recvmsgs_ow = func; } @@ -425,7 +373,7 @@ void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, * @arg func replacement callback for nl_recv() */ void nl_cb_overwrite_recv(struct nl_cb *cb, - int (*func)(struct nl_handle *, struct sockaddr_nl *, + int (*func)(struct nl_sock *, struct sockaddr_nl *, unsigned char **, struct ucred **)) { cb->cb_recv_ow = func; @@ -437,7 +385,7 @@ void nl_cb_overwrite_recv(struct nl_cb *cb, * @arg func replacement callback for nl_send() */ void nl_cb_overwrite_send(struct nl_cb *cb, - int (*func)(struct nl_handle *, struct nl_msg *)) + int (*func)(struct nl_sock *, struct nl_msg *)) { cb->cb_send_ow = func; } @@ -6,11 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup nl + * @ingroup core * @defgroup msg Messages * Netlink Message Construction/Parsing Interface * @@ -284,7 +284,7 @@ int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) */ int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) { - return (remaining >= sizeof(struct nlmsghdr) && + return (remaining >= (int)sizeof(struct nlmsghdr) && nlh->nlmsg_len >= sizeof(struct nlmsghdr) && nlh->nlmsg_len <= remaining); } @@ -320,7 +320,7 @@ int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, struct nla_policy *policy) { if (!nlmsg_valid_hdr(nlh, hdrlen)) - return nl_errno(EINVAL); + return -NLE_MSG_TOOSHORT; return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), policy); @@ -351,7 +351,7 @@ int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, struct nla_policy *policy) { if (!nlmsg_valid_hdr(nlh, hdrlen)) - return nl_errno(EINVAL); + return -NLE_MSG_TOOSHORT; return nla_validate(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), maxtype, policy); @@ -372,10 +372,14 @@ static struct nl_msg *__nlmsg_alloc(size_t len) if (!nm) goto errout; - nm->nm_nlh = calloc(1, len); + nm->nm_refcnt = 1; + + nm->nm_nlh = malloc(len); if (!nm->nm_nlh) goto errout; + memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr)); + nm->nm_protocol = -1; nm->nm_size = len; nm->nm_nlh->nlmsg_len = nlmsg_total_size(0); @@ -385,7 +389,6 @@ static struct nl_msg *__nlmsg_alloc(size_t len) return nm; errout: free(nm); - nl_errno(ENOMEM); return NULL; } @@ -517,10 +520,8 @@ void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad) tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; - if ((tlen + nlmsg_len) > n->nm_size) { - nl_errno(ENOBUFS); + if ((tlen + nlmsg_len) > n->nm_size) return NULL; - } buf += nlmsg_len; n->nm_nlh->nlmsg_len += tlen; @@ -552,7 +553,7 @@ int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad) tmp = nlmsg_reserve(n, len, pad); if (tmp == NULL) - return nl_errno(ENOMEM); + return -NLE_NOMEM; memcpy(tmp, data, len); NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad); @@ -579,11 +580,11 @@ int nlmsg_expand(struct nl_msg *n, size_t newlen) void *tmp; if (newlen <= n->nm_size) - return nl_errno(EINVAL); + return -NLE_INVAL; tmp = realloc(n->nm_nlh, newlen); if (tmp == NULL) - return nl_errno(ENOMEM); + return -NLE_NOMEM; n->nm_nlh = tmp; n->nm_size = newlen; @@ -646,21 +647,39 @@ struct nlmsghdr *nlmsg_hdr(struct nl_msg *n) } /** - * Free a netlink message - * @arg n netlink message - * - * Destroys a netlink message and frees up all used memory. + * Acquire a reference on a netlink message + * @arg msg message to acquire reference from + */ +void nlmsg_get(struct nl_msg *msg) +{ + msg->nm_refcnt++; + NL_DBG(4, "New reference to message %p, total %d\n", + msg, msg->nm_refcnt); +} + +/** + * Release a reference from an netlink message + * @arg msg message to release reference from * - * @pre The message must be unused. + * Frees memory after the last reference has been released. */ -void nlmsg_free(struct nl_msg *n) +void nlmsg_free(struct nl_msg *msg) { - if (!n) + if (!msg) return; - free(n->nm_nlh); - free(n); - NL_DBG(2, "msg %p: Freed\n", n); + msg->nm_refcnt--; + NL_DBG(4, "Returned message reference %p, %d remaining\n", + msg, msg->nm_refcnt); + + if (msg->nm_refcnt < 0) + BUG(); + + if (msg->nm_refcnt <= 0) { + free(msg->nm_nlh); + free(msg); + NL_DBG(2, "msg %p: Freed\n", msg); + } } /** @} */ @@ -821,8 +840,7 @@ int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *), ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlmsg_hdr(msg)->nlmsg_type); if (ops == NULL) - return nl_error(ENOENT, "Unknown message type %d", - nlmsg_hdr(msg)->nlmsg_type); + return -NLE_MSGTYPE_NOSUPPORT; p.pp_arg = &x; return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p); diff --git a/lib/netfilter/ct.c b/lib/netfilter/ct.c index e9df924..9d61b6c 100644 --- a/lib/netfilter/ct.c +++ b/lib/netfilter/ct.c @@ -6,9 +6,10 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c= 2008 Patrick McHardy <kaber@trash.net> */ /** @@ -112,36 +113,36 @@ static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr) goto errout; if (tb[CTA_IP_V4_SRC]) { - addr = nla_get_addr(tb[CTA_IP_V4_SRC], AF_INET); + addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET); if (addr == NULL) - goto errout_errno; + goto errout_enomem; err = nfnl_ct_set_src(ct, repl, addr); nl_addr_put(addr); if (err < 0) goto errout; } if (tb[CTA_IP_V4_DST]) { - addr = nla_get_addr(tb[CTA_IP_V4_DST], AF_INET); + addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET); if (addr == NULL) - goto errout_errno; + goto errout_enomem; err = nfnl_ct_set_dst(ct, repl, addr); nl_addr_put(addr); if (err < 0) goto errout; } if (tb[CTA_IP_V6_SRC]) { - addr = nla_get_addr(tb[CTA_IP_V6_SRC], AF_INET6); + addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6); if (addr == NULL) - goto errout_errno; + goto errout_enomem; err = nfnl_ct_set_src(ct, repl, addr); nl_addr_put(addr); if (err < 0) goto errout; } if (tb[CTA_IP_V6_DST]) { - addr = nla_get_addr(tb[CTA_IP_V6_DST], AF_INET6); + addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6); if (addr == NULL) - goto errout_errno; + goto errout_enomem; err = nfnl_ct_set_dst(ct, repl, addr); nl_addr_put(addr); if (err < 0) @@ -150,8 +151,8 @@ static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr) return 0; -errout_errno: - return nl_get_errno(); +errout_enomem: + err = -NLE_NOMEM; errout: return err; } @@ -169,13 +170,13 @@ static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr) nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM])); if (tb[CTA_PROTO_SRC_PORT]) nfnl_ct_set_src_port(ct, repl, - nla_get_u16(tb[CTA_PROTO_SRC_PORT])); + ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]))); if (tb[CTA_PROTO_DST_PORT]) nfnl_ct_set_dst_port(ct, repl, - nla_get_u16(tb[CTA_PROTO_DST_PORT])); + ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]))); if (tb[CTA_PROTO_ICMP_ID]) nfnl_ct_set_icmp_id(ct, repl, - nla_get_u16(tb[CTA_PROTO_ICMP_ID])); + ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]))); if (tb[CTA_PROTO_ICMP_TYPE]) nfnl_ct_set_icmp_type(ct, repl, nla_get_u8(tb[CTA_PROTO_ICMP_TYPE])); @@ -286,7 +287,7 @@ int nfnlmsg_ct_group(struct nlmsghdr *nlh) } } -struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh) +int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result) { struct nfnl_ct *ct; struct nlattr *tb[CTA_MAX+1]; @@ -294,7 +295,7 @@ struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh) ct = nfnl_ct_alloc(); if (!ct) - return NULL; + return -NLE_NOMEM; ct->ce_msgtype = nlh->nlmsg_type; @@ -345,11 +346,12 @@ struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh) goto errout; } - return ct; + *result = ct; + return 0; errout: nfnl_ct_put(ct); - return NULL; + return err; } static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, @@ -358,34 +360,179 @@ static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nfnl_ct *ct; int err; - ct = nfnlmsg_ct_parse(nlh); - if (ct == NULL) - goto errout_errno; - - err = pp->pp_cb((struct nl_object *) ct, pp); - if (err < 0) + if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0) goto errout; - err = P_ACCEPT; - + err = pp->pp_cb((struct nl_object *) ct, pp); errout: nfnl_ct_put(ct); return err; - -errout_errno: - err = nl_get_errno(); - goto errout; } -int nfnl_ct_dump_request(struct nl_handle *h) +int nfnl_ct_dump_request(struct nl_sock *sk) { - return nfnl_send_simple(h, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET, + return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET, NLM_F_DUMP, AF_UNSPEC, 0); } -static int ct_request_update(struct nl_cache *c, struct nl_handle *h) +static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + return nfnl_ct_dump_request(sk); +} + +static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct, + int repl) +{ + struct nlattr *tuple, *ip, *proto; + struct nl_addr *addr; + int family; + + family = nfnl_ct_get_family(ct); + + tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG); + if (!tuple) + goto nla_put_failure; + + ip = nla_nest_start(msg, CTA_TUPLE_IP); + if (!ip) + goto nla_put_failure; + + addr = nfnl_ct_get_src(ct, repl); + if (addr) + NLA_PUT_ADDR(msg, + family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC, + addr); + + addr = nfnl_ct_get_dst(ct, repl); + if (addr) + NLA_PUT_ADDR(msg, + family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST, + addr); + + nla_nest_end(msg, ip); + + proto = nla_nest_start(msg, CTA_TUPLE_PROTO); + if (!proto) + goto nla_put_failure; + + if (nfnl_ct_test_proto(ct)) + NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct)); + + if (nfnl_ct_test_src_port(ct, repl)) + NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT, + htons(nfnl_ct_get_src_port(ct, repl))); + + if (nfnl_ct_test_dst_port(ct, repl)) + NLA_PUT_U16(msg, CTA_PROTO_DST_PORT, + htons(nfnl_ct_get_dst_port(ct, repl))); + + if (nfnl_ct_test_icmp_id(ct, repl)) + NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID, + htons(nfnl_ct_get_icmp_id(ct, repl))); + + if (nfnl_ct_test_icmp_type(ct, repl)) + NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE, + nfnl_ct_get_icmp_type(ct, repl)); + + if (nfnl_ct_test_icmp_code(ct, repl)) + NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE, + nfnl_ct_get_icmp_code(ct, repl)); + + nla_nest_end(msg, proto); + + nla_nest_end(msg, tuple); + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags, + struct nl_msg **result) +{ + struct nl_msg *msg; + int err; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags, + nfnl_ct_get_family(ct), 0); + if (msg == NULL) + return -NLE_NOMEM; + + if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0) + goto err_out; + + *result = msg; + return 0; + +err_out: + nlmsg_free(msg); + return err; +} + +int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags, + struct nl_msg **result) +{ + return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result); +} + +int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) { - return nfnl_ct_dump_request(h); + struct nl_msg *msg; + int err; + + if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags, + struct nl_msg **result) +{ + return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result); +} + +int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags, + struct nl_msg **result) +{ + return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result); +} + +int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); } /** @@ -395,29 +542,17 @@ static int ct_request_update(struct nl_cache *c, struct nl_handle *h) /** * Build a conntrack cache holding all conntrack currently in the kernel - * @arg handle netlink handle + * @arg sk Netlink socket. + * @arg result Pointer to store resulting cache. * * Allocates a new cache, initializes it properly and updates it to * contain all conntracks currently in the kernel. * - * @note The caller is responsible for destroying and freeing the - * cache after using it. - * @return The cache or NULL if an error has occured. + * @return 0 on success or a negative error code. */ -struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *handle) +int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result) { - struct nl_cache *cache; - - cache = nl_cache_alloc(&nfnl_ct_ops); - if (!cache) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - free(cache); - return NULL; - } - - return cache; + return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result); } /** @} */ diff --git a/lib/netfilter/ct_obj.c b/lib/netfilter/ct_obj.c index 0f5a79e..ae14c0d 100644 --- a/lib/netfilter/ct_obj.c +++ b/lib/netfilter/ct_obj.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ @@ -75,116 +75,199 @@ static int ct_clone(struct nl_object *_dst, struct nl_object *_src) if (src->ct_orig.src) { addr = nl_addr_clone(src->ct_orig.src); if (!addr) - goto errout; + return -NLE_NOMEM; dst->ct_orig.src = addr; } if (src->ct_orig.dst) { addr = nl_addr_clone(src->ct_orig.dst); if (!addr) - goto errout; + return -NLE_NOMEM; dst->ct_orig.dst = addr; } if (src->ct_repl.src) { addr = nl_addr_clone(src->ct_repl.src); if (!addr) - goto errout; + return -NLE_NOMEM; dst->ct_repl.src = addr; } if (src->ct_repl.dst) { addr = nl_addr_clone(src->ct_repl.dst); if (!addr) - goto errout; + return -NLE_NOMEM; dst->ct_repl.dst = addr; } return 0; -errout: - return nl_get_errno(); } -static void ct_dump_dir(struct nfnl_ct *ct, int repl, - struct nl_dump_params *p) +static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port) { - struct nl_addr *addr; - char addrbuf[64]; + char buf[64]; - addr = nfnl_ct_get_src(ct, repl); if (addr) - dp_dump(p, "src=%s ", - nl_addr2str(addr, addrbuf, sizeof(addrbuf))); + nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf))); - addr = nfnl_ct_get_dst(ct, repl); - if (addr) - dp_dump(p, "dst=%s ", - nl_addr2str(addr, addrbuf, sizeof(addrbuf))); + if (port) + nl_dump(p, ":%u ", port); + else if (addr) + nl_dump(p, " "); +} + +static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply) +{ + if (nfnl_ct_test_icmp_type(ct, reply)) + nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply)); + + if (nfnl_ct_test_icmp_type(ct, reply)) + nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply)); + + if (nfnl_ct_test_icmp_type(ct, reply)) + nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply)); +} + +static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p) +{ + struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst; + int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0; + int sync = 0; + + orig_src = nfnl_ct_get_src(ct, 0); + orig_dst = nfnl_ct_get_dst(ct, 0); + reply_src = nfnl_ct_get_src(ct, 1); + reply_dst = nfnl_ct_get_dst(ct, 1); + + if (nfnl_ct_test_src_port(ct, 0)) + orig_sport = nfnl_ct_get_src_port(ct, 0); + + if (nfnl_ct_test_dst_port(ct, 0)) + orig_dport = nfnl_ct_get_dst_port(ct, 0); + + if (nfnl_ct_test_src_port(ct, 1)) + reply_sport = nfnl_ct_get_src_port(ct, 1); - if (nfnl_ct_test_src_port(ct, repl)) - dp_dump(p, "sport=%u ", ntohs(nfnl_ct_get_src_port(ct, repl))); - if (nfnl_ct_test_dst_port(ct, repl)) - dp_dump(p, "dport=%u ", ntohs(nfnl_ct_get_dst_port(ct, repl))); + if (nfnl_ct_test_dst_port(ct, 1)) + reply_dport = nfnl_ct_get_dst_port(ct, 1); - if (nfnl_ct_test_icmp_type(ct, repl)) - dp_dump(p, "type=%d ", nfnl_ct_get_icmp_type(ct, repl)); - if (nfnl_ct_test_icmp_type(ct, repl)) - dp_dump(p, "code=%d ", nfnl_ct_get_icmp_code(ct, repl)); - if (nfnl_ct_test_icmp_type(ct, repl)) - dp_dump(p, "id=%d ", ntohs(nfnl_ct_get_icmp_id(ct, repl))); + if (orig_src && orig_dst && reply_src && reply_dst && + orig_sport == reply_dport && orig_dport == reply_sport && + !nl_addr_cmp(orig_src, reply_dst) && + !nl_addr_cmp(orig_dst, reply_src)) + sync = 1; - if (nfnl_ct_test_packets(ct, repl)) - dp_dump(p, "packets=%llu ", nfnl_ct_get_packets(ct, repl)); - if (nfnl_ct_test_bytes(ct, repl)) - dp_dump(p, "bytes=%llu ", nfnl_ct_get_bytes(ct, repl)); + dump_addr(p, orig_src, orig_sport); + nl_dump(p, sync ? "<-> " : "-> "); + dump_addr(p, orig_dst, orig_dport); + dump_icmp(p, ct, 0); + + if (!sync) { + dump_addr(p, reply_src, reply_sport); + nl_dump(p, "<- "); + dump_addr(p, reply_dst, reply_dport); + dump_icmp(p, ct, 1); + } } /* Compatible with /proc/net/nf_conntrack */ -static int ct_dump(struct nl_object *a, struct nl_dump_params *p) +static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p) { struct nfnl_ct *ct = (struct nfnl_ct *) a; char buf[64]; - uint32_t status; - uint8_t family; - uint8_t proto; - family = nfnl_ct_get_family(ct); - dp_dump(p, "%-8s %u ", nl_af2str(family, buf, sizeof(buf)), family); + nl_new_line(p); - if (nfnl_ct_test_proto(ct)) { - proto = nfnl_ct_get_proto(ct); - dp_dump(p, "%-8s %u ", - nl_ip_proto2str(proto, buf, sizeof(buf)), proto); - } - - if (nfnl_ct_test_timeout(ct)) - dp_dump(p, "%ld ", nfnl_ct_get_timeout(ct)); + if (nfnl_ct_test_proto(ct)) + nl_dump(p, "%s ", + nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf))); if (nfnl_ct_test_tcp_state(ct)) - dp_dump(p, "%s ", + nl_dump(p, "%s ", nfnl_ct_tcp_state2str(nfnl_ct_get_tcp_state(ct), buf, sizeof(buf))); - ct_dump_dir(ct, 0, p); + ct_dump_tuples(ct, p); - status = nfnl_ct_get_status(ct); - if (!(status & IPS_SEEN_REPLY)) - dp_dump(p, "[UNREPLIED] "); + if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct)) + nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct)); - ct_dump_dir(ct, 1, p); + nl_dump(p, "\n"); +} - if (status & IPS_ASSURED) - dp_dump(p, "[ASSURED] "); +static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_ct *ct = (struct nfnl_ct *) a; + char buf[64]; + int fp = 0; - if (nfnl_ct_test_mark(ct)) - dp_dump(p, "mark=%u ", nfnl_ct_get_mark(ct)); + ct_dump_line(a, p); + + nl_dump(p, " id 0x%x ", ct->ct_id); + nl_dump_line(p, "family %s ", + nl_af2str(ct->ct_family, buf, sizeof(buf))); if (nfnl_ct_test_use(ct)) - dp_dump(p, "use=%u ", nfnl_ct_get_use(ct)); + nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct)); + + if (nfnl_ct_test_timeout(ct)) { + uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL; + nl_dump(p, "timeout %s ", + nl_msec2str(timeout_ms, buf, sizeof(buf))); + } + + if (ct->ct_status) + nl_dump(p, "<"); + +#define PRINT_FLAG(str) \ + { nl_dump(p, "%s%s", fp++ ? "," : "", (str)); } + + if (ct->ct_status & IPS_EXPECTED) + PRINT_FLAG("EXPECTED"); + if (!(ct->ct_status & IPS_SEEN_REPLY)) + PRINT_FLAG("NOREPLY"); + if (ct->ct_status & IPS_ASSURED) + PRINT_FLAG("ASSURED"); + if (!(ct->ct_status & IPS_CONFIRMED)) + PRINT_FLAG("NOTSENT"); + if (ct->ct_status & IPS_SRC_NAT) + PRINT_FLAG("SNAT"); + if (ct->ct_status & IPS_DST_NAT) + PRINT_FLAG("DNAT"); + if (ct->ct_status & IPS_SEQ_ADJUST) + PRINT_FLAG("SEQADJUST"); + if (!(ct->ct_status & IPS_SRC_NAT_DONE)) + PRINT_FLAG("SNAT_INIT"); + if (!(ct->ct_status & IPS_DST_NAT_DONE)) + PRINT_FLAG("DNAT_INIT"); + if (ct->ct_status & IPS_DYING) + PRINT_FLAG("DYING"); + if (ct->ct_status & IPS_FIXED_TIMEOUT) + PRINT_FLAG("FIXED_TIMEOUT"); +#undef PRINT_FLAG + + if (ct->ct_status) + nl_dump(p, ">"); + nl_dump(p, "\n"); +} + +static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_ct *ct = (struct nfnl_ct *) a; + double res; + char *unit; + + ct_dump_details(a, p); - dp_dump(p, "\n"); + nl_dump_line(p, " # packets volume\n"); - return 1; + res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 1), &unit); + nl_dump_line(p, " rx %10llu %7.2f %s\n", + nfnl_ct_get_packets(ct, 1), res, unit); + + res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, 0), &unit); + nl_dump_line(p, " tx %10llu %7.2f %s\n", + nfnl_ct_get_packets(ct, 0), res, unit); } static int ct_compare(struct nl_object *_a, struct nl_object *_b, @@ -197,7 +280,7 @@ static int ct_compare(struct nl_object *_a, struct nl_object *_b, #define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR) #define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD) #define CT_DIFF_ADDR(ATTR, FIELD) \ - ((flags & LOOSE_FLAG_COMPARISON) \ + ((flags & LOOSE_COMPARISON) \ ? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \ : CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD))) @@ -227,7 +310,7 @@ static int ct_compare(struct nl_object *_a, struct nl_object *_b, diff |= CT_DIFF_VAL(REPL_PACKETS, ct_repl.packets); diff |= CT_DIFF_VAL(REPL_BYTES, ct_repl.bytes); - if (flags & LOOSE_FLAG_COMPARISON) + if (flags & LOOSE_COMPARISON) diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) & b->ct_status_mask); else @@ -389,6 +472,31 @@ uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct) return ct->ct_status; } +static struct trans_tbl status_flags[] = { + __ADD(IPS_EXPECTED, expected) + __ADD(IPS_SEEN_REPLY, seen_reply) + __ADD(IPS_ASSURED, assured) + __ADD(IPS_CONFIRMED, confirmed) + __ADD(IPS_SRC_NAT, snat) + __ADD(IPS_DST_NAT, dnat) + __ADD(IPS_SEQ_ADJUST, seqadjust) + __ADD(IPS_SRC_NAT_DONE, snat_done) + __ADD(IPS_DST_NAT_DONE, dnat_done) + __ADD(IPS_DYING, dying) + __ADD(IPS_FIXED_TIMEOUT, fixed_timeout) +}; + +char * nfnl_ct_status2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, status_flags, + ARRAY_SIZE(status_flags)); +} + +int nfnl_ct_str2status(const char *name) +{ + return __str2flags(name, status_flags, ARRAY_SIZE(status_flags)); +} + void nfnl_ct_set_timeout(struct nfnl_ct *ct, uint32_t timeout) { ct->ct_timeout = timeout; @@ -458,7 +566,7 @@ static int ct_set_addr(struct nfnl_ct *ct, struct nl_addr *addr, { if (ct->ce_mask & CT_ATTR_FAMILY) { if (addr->a_family != ct->ct_family) - return nl_error(EINVAL, "Address family mismatch"); + return -NLE_AF_MISMATCH; } else nfnl_ct_set_family(ct, addr->a_family); @@ -665,9 +773,11 @@ struct nl_object_ops ct_obj_ops = { .oo_size = sizeof(struct nfnl_ct), .oo_free_data = ct_free_data, .oo_clone = ct_clone, - .oo_dump[NL_DUMP_BRIEF] = ct_dump, - .oo_dump[NL_DUMP_FULL] = ct_dump, - .oo_dump[NL_DUMP_STATS] = ct_dump, + .oo_dump = { + [NL_DUMP_LINE] = ct_dump_line, + [NL_DUMP_DETAILS] = ct_dump_details, + [NL_DUMP_STATS] = ct_dump_stats, + }, .oo_compare = ct_compare, .oo_attrs2str = ct_attrs2str, }; diff --git a/lib/netfilter/log.c b/lib/netfilter/log.c index a6bf3d5..96ae6c5 100644 --- a/lib/netfilter/log.c +++ b/lib/netfilter/log.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ @@ -26,172 +26,13 @@ #include <netlink/netfilter/nfnl.h> #include <netlink/netfilter/log.h> -static struct nl_cache_ops nfnl_log_ops; - -#if __BYTE_ORDER == __BIG_ENDIAN -static uint64_t ntohll(uint64_t x) -{ - return x; -} -#elif __BYTE_ORDER == __LITTLE_ENDIAN -static uint64_t ntohll(uint64_t x) -{ - return __bswap_64(x); -} -#endif - -static struct nla_policy log_policy[NFULA_MAX+1] = { - [NFULA_PACKET_HDR] = { - .minlen = sizeof(struct nfulnl_msg_packet_hdr) - }, - [NFULA_MARK] = { .type = NLA_U32 }, - [NFULA_TIMESTAMP] = { - .minlen = sizeof(struct nfulnl_msg_packet_timestamp) - }, - [NFULA_IFINDEX_INDEV] = { .type = NLA_U32 }, - [NFULA_IFINDEX_OUTDEV] = { .type = NLA_U32 }, - [NFULA_IFINDEX_PHYSINDEV] = { .type = NLA_U32 }, - [NFULA_IFINDEX_PHYSOUTDEV] = { .type = NLA_U32 }, - [NFULA_HWADDR] = { - .minlen = sizeof(struct nfulnl_msg_packet_hw) - }, - //[NFULA_PAYLOAD] - [NFULA_PREFIX] = { .type = NLA_STRING, }, - [NFULA_UID] = { .type = NLA_U32 }, - [NFULA_SEQ] = { .type = NLA_U32 }, - [NFULA_SEQ_GLOBAL] = { .type = NLA_U32 }, -}; - -struct nfnl_log *nfnlmsg_log_parse(struct nlmsghdr *nlh) -{ - struct nfnl_log *log; - struct nlattr *tb[NFULA_MAX+1]; - struct nlattr *attr; - int err; - - log = nfnl_log_alloc(); - if (!log) - return NULL; - - log->ce_msgtype = nlh->nlmsg_type; - - err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX, - log_policy); - if (err < 0) - goto errout; - - nfnl_log_set_family(log, nfnlmsg_family(nlh)); - - attr = tb[NFULA_PACKET_HDR]; - if (attr) { - struct nfulnl_msg_packet_hdr *hdr = nla_data(attr); - - nfnl_log_set_hwproto(log, hdr->hw_protocol); - nfnl_log_set_hook(log, hdr->hook); - } - - attr = tb[NFULA_MARK]; - if (attr) - nfnl_log_set_mark(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_TIMESTAMP]; - if (attr) { - struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr); - struct timeval tv; - - tv.tv_sec = ntohll(timestamp->sec); - tv.tv_usec = ntohll(timestamp->usec); - nfnl_log_set_timestamp(log, &tv); - } - - attr = tb[NFULA_IFINDEX_INDEV]; - if (attr) - nfnl_log_set_indev(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_IFINDEX_OUTDEV]; - if (attr) - nfnl_log_set_outdev(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_IFINDEX_PHYSINDEV]; - if (attr) - nfnl_log_set_physindev(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_IFINDEX_PHYSOUTDEV]; - if (attr) - nfnl_log_set_physoutdev(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_HWADDR]; - if (attr) { - struct nfulnl_msg_packet_hw *hw = nla_data(attr); - - nfnl_log_set_hwaddr(log, hw->hw_addr, ntohs(hw->hw_addrlen)); - } - - attr = tb[NFULA_PAYLOAD]; - if (attr) { - err = nfnl_log_set_payload(log, nla_data(attr), nla_len(attr)); - if (err < 0) - goto errout; - } - - attr = tb[NFULA_PREFIX]; - if (attr) { - err = nfnl_log_set_prefix(log, nla_data(attr)); - if (err < 0) - goto errout; - } - - attr = tb[NFULA_UID]; - if (attr) - nfnl_log_set_uid(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_SEQ]; - if (attr) - nfnl_log_set_seq(log, ntohl(nla_get_u32(attr))); - - attr = tb[NFULA_SEQ_GLOBAL]; - if (attr) - nfnl_log_set_seq_global(log, ntohl(nla_get_u32(attr))); - - return log; - -errout: - nfnl_log_put(log); - return NULL; -} - -static int log_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, - struct nlmsghdr *nlh, struct nl_parser_param *pp) -{ - struct nfnl_log *log; - int err; - - log = nfnlmsg_log_parse(nlh); - if (log == NULL) - goto errout_errno; - - err = pp->pp_cb((struct nl_object *) log, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; - -errout: - nfnl_log_put(log); - return err; - -errout_errno: - err = nl_get_errno(); - goto errout; -} - /** * @name Log Commands * @{ */ -static struct nl_msg *build_log_cmd_msg(uint8_t family, uint16_t queuenum, - uint8_t command) +static int build_log_cmd_request(uint8_t family, uint16_t queuenum, + uint8_t command, struct nl_msg **result) { struct nl_msg *msg; struct nfulnl_msg_config_cmd cmd; @@ -199,142 +40,202 @@ static struct nl_msg *build_log_cmd_msg(uint8_t family, uint16_t queuenum, msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0, family, queuenum); if (msg == NULL) - return NULL; + return -NLE_NOMEM; cmd.command = command; if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0) goto nla_put_failure; - return msg; + *result = msg; + return 0; nla_put_failure: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } -static int send_log_msg(struct nl_handle *handle, struct nl_msg *msg) +static int send_log_request(struct nl_sock *sk, struct nl_msg *msg) { int err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } -struct nl_msg *nfnl_log_build_bind(uint16_t queuenum) +int nfnl_log_build_pf_bind(uint8_t pf, struct nl_msg **result) { - return build_log_cmd_msg(0, queuenum, NFULNL_CFG_CMD_BIND); + return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_BIND, result); } -int nfnl_log_bind(struct nl_handle *nlh, uint16_t queuenum) +int nfnl_log_pf_bind(struct nl_sock *nlh, uint8_t pf) { struct nl_msg *msg; + int err; - msg = nfnl_log_build_bind(queuenum); - if (!msg) - return nl_get_errno(); + if ((err = nfnl_log_build_pf_bind(pf, &msg)) < 0) + return err; - return send_log_msg(nlh, msg); + return send_log_request(nlh, msg); } -struct nl_msg *nfnl_log_build_unbind(uint16_t queuenum) +int nfnl_log_build_pf_unbind(uint8_t pf, struct nl_msg **result) { - return build_log_cmd_msg(0, queuenum, NFULNL_CFG_CMD_UNBIND); + return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_UNBIND, result); } -int nfnl_log_unbind(struct nl_handle *nlh, uint16_t queuenum) +int nfnl_log_pf_unbind(struct nl_sock *nlh, uint8_t pf) { struct nl_msg *msg; + int err; - msg = nfnl_log_build_bind(queuenum); - if (!msg) - return nl_get_errno(); - - return send_log_msg(nlh, msg); -} + if ((err = nfnl_log_build_pf_unbind(pf, &msg)) < 0) + return err; -struct nl_msg *nfnl_log_build_pf_bind(uint8_t pf) -{ - return build_log_cmd_msg(pf, 0, NFULNL_CFG_CMD_PF_BIND); + return send_log_request(nlh, msg); } -int nfnl_log_pf_bind(struct nl_handle *nlh, uint8_t pf) +static int nfnl_log_build_request(const struct nfnl_log *log, + struct nl_msg **result) { struct nl_msg *msg; - msg = nfnl_log_build_pf_bind(pf); - if (!msg) - return nl_get_errno(); + if (!nfnl_log_test_group(log)) + return -NLE_MISSING_ATTR; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0, + 0, nfnl_log_get_group(log)); + if (msg == NULL) + return -NLE_NOMEM; + + /* This sucks. The nfnetlink_log interface always expects both + * parameters to be present. Needs to be done properly. + */ + if (nfnl_log_test_copy_mode(log)) { + struct nfulnl_msg_config_mode mode; + + switch (nfnl_log_get_copy_mode(log)) { + case NFNL_LOG_COPY_NONE: + mode.copy_mode = NFULNL_COPY_NONE; + break; + case NFNL_LOG_COPY_META: + mode.copy_mode = NFULNL_COPY_META; + break; + case NFNL_LOG_COPY_PACKET: + mode.copy_mode = NFULNL_COPY_PACKET; + break; + } + mode.copy_range = htonl(nfnl_log_get_copy_range(log)); + mode._pad = 0; + + if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0) + goto nla_put_failure; + } + + if (nfnl_log_test_flush_timeout(log) && + nla_put_u32(msg, NFULA_CFG_TIMEOUT, + htonl(nfnl_log_get_flush_timeout(log))) < 0) + goto nla_put_failure; + + if (nfnl_log_test_alloc_size(log) && + nla_put_u32(msg, NFULA_CFG_NLBUFSIZ, + htonl(nfnl_log_get_alloc_size(log))) < 0) + goto nla_put_failure; + + if (nfnl_log_test_queue_threshold(log) && + nla_put_u32(msg, NFULA_CFG_QTHRESH, + htonl(nfnl_log_get_queue_threshold(log))) < 0) + goto nla_put_failure; + + *result = msg; + return 0; - return send_log_msg(nlh, msg); +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; } -struct nl_msg *nfnl_log_build_pf_unbind(uint8_t pf) +int nfnl_log_build_create_request(const struct nfnl_log *log, + struct nl_msg **result) { - return build_log_cmd_msg(pf, 0, NFULNL_CFG_CMD_PF_UNBIND); + struct nfulnl_msg_config_cmd cmd; + int err; + + if ((err = nfnl_log_build_request(log, result)) < 0) + return err; + + cmd.command = NFULNL_CFG_CMD_BIND; + + if (nla_put(*result, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0) + goto nla_put_failure; + + return 0; + +nla_put_failure: + nlmsg_free(*result); + return -NLE_MSGSIZE; } -int nfnl_log_pf_unbind(struct nl_handle *nlh, uint8_t pf) +int nfnl_log_create(struct nl_sock *nlh, const struct nfnl_log *log) { struct nl_msg *msg; + int err; - msg = nfnl_log_build_pf_unbind(pf); - if (!msg) - return nl_get_errno(); + if ((err = nfnl_log_build_create_request(log, &msg)) < 0) + return err; + + return send_log_request(nlh, msg); +} - return send_log_msg(nlh, msg); +int nfnl_log_build_change_request(const struct nfnl_log *log, + struct nl_msg **result) +{ + return nfnl_log_build_request(log, result); } -struct nl_msg *nfnl_log_build_mode(uint16_t queuenum, uint8_t copy_mode, - uint32_t copy_range) +int nfnl_log_change(struct nl_sock *nlh, const struct nfnl_log *log) { struct nl_msg *msg; - struct nfulnl_msg_config_mode mode; + int err; - msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0, - 0, queuenum); - if (msg == NULL) - return NULL; + if ((err = nfnl_log_build_change_request(log, &msg)) < 0) + return err; - mode.copy_mode = copy_mode; - mode.copy_range = htonl(copy_range); - if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0) - goto nla_put_failure; + return send_log_request(nlh, msg); +} - return msg; +int nfnl_log_build_delete_request(const struct nfnl_log *log, + struct nl_msg **result) +{ + if (!nfnl_log_test_group(log)) + return -NLE_MISSING_ATTR; -nla_put_failure: - nlmsg_free(msg); - return NULL; + return build_log_cmd_request(0, nfnl_log_get_group(log), + NFULNL_CFG_CMD_UNBIND, result); } -int nfnl_log_set_mode(struct nl_handle *nlh, uint16_t queuenum, - uint8_t copy_mode, uint32_t copy_range) +int nfnl_log_delete(struct nl_sock *nlh, const struct nfnl_log *log) { struct nl_msg *msg; + int err; + + if ((err = nfnl_log_build_delete_request(log, &msg)) < 0) + return err; - msg = nfnl_log_build_mode(queuenum, copy_mode, copy_range); - if (!msg) - return nl_get_errno(); - return send_log_msg(nlh, msg); + return send_log_request(nlh, msg); } /** @} */ -#define NFNLMSG_LOG_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_ULOG, (type)) static struct nl_cache_ops nfnl_log_ops = { .co_name = "netfilter/log", - .co_hdrsize = NFNL_HDRLEN, + .co_obj_ops = &log_obj_ops, .co_msgtypes = { - { NFNLMSG_LOG_TYPE(NFULNL_MSG_PACKET), NL_ACT_NEW, "new" }, END_OF_MSGTYPES_LIST, }, - .co_protocol = NETLINK_NETFILTER, - .co_msg_parser = log_msg_parser, - .co_obj_ops = &log_obj_ops, }; static void __init log_init(void) diff --git a/lib/netfilter/log_msg.c b/lib/netfilter/log_msg.c new file mode 100644 index 0000000..cad6ddd --- /dev/null +++ b/lib/netfilter/log_msg.c @@ -0,0 +1,209 @@ +/* + * lib/netfilter/log_msg.c Netfilter Log Message + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> + * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup nfnl + * @defgroup log Log + * @brief + * @{ + */ + +#include <sys/types.h> +#include <linux/netfilter/nfnetlink_log.h> + +#include <netlink-local.h> +#include <netlink/attr.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/log_msg.h> + +#if __BYTE_ORDER == __BIG_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return x; +} +#elif __BYTE_ORDER == __LITTLE_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return __bswap_64(x); +} +#endif + +static struct nla_policy log_msg_policy[NFULA_MAX+1] = { + [NFULA_PACKET_HDR] = { + .minlen = sizeof(struct nfulnl_msg_packet_hdr) + }, + [NFULA_MARK] = { .type = NLA_U32 }, + [NFULA_TIMESTAMP] = { + .minlen = sizeof(struct nfulnl_msg_packet_timestamp) + }, + [NFULA_IFINDEX_INDEV] = { .type = NLA_U32 }, + [NFULA_IFINDEX_OUTDEV] = { .type = NLA_U32 }, + [NFULA_IFINDEX_PHYSINDEV] = { .type = NLA_U32 }, + [NFULA_IFINDEX_PHYSOUTDEV] = { .type = NLA_U32 }, + [NFULA_HWADDR] = { + .minlen = sizeof(struct nfulnl_msg_packet_hw) + }, + //[NFULA_PAYLOAD] + [NFULA_PREFIX] = { .type = NLA_STRING, }, + [NFULA_UID] = { .type = NLA_U32 }, + [NFULA_GID] = { .type = NLA_U32 }, + [NFULA_SEQ] = { .type = NLA_U32 }, + [NFULA_SEQ_GLOBAL] = { .type = NLA_U32 }, +}; + +int nfnlmsg_log_msg_parse(struct nlmsghdr *nlh, struct nfnl_log_msg **result) +{ + struct nfnl_log_msg *msg; + struct nlattr *tb[NFULA_MAX+1]; + struct nlattr *attr; + int err; + + msg = nfnl_log_msg_alloc(); + if (!msg) + return -NLE_NOMEM; + + msg->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX, + log_msg_policy); + if (err < 0) + goto errout; + + nfnl_log_msg_set_family(msg, nfnlmsg_family(nlh)); + + attr = tb[NFULA_PACKET_HDR]; + if (attr) { + struct nfulnl_msg_packet_hdr *hdr = nla_data(attr); + + if (hdr->hw_protocol) + nfnl_log_msg_set_hwproto(msg, hdr->hw_protocol); + nfnl_log_msg_set_hook(msg, hdr->hook); + } + + attr = tb[NFULA_MARK]; + if (attr) + nfnl_log_msg_set_mark(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_TIMESTAMP]; + if (attr) { + struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr); + struct timeval tv; + + tv.tv_sec = ntohll(timestamp->sec); + tv.tv_usec = ntohll(timestamp->usec); + nfnl_log_msg_set_timestamp(msg, &tv); + } + + attr = tb[NFULA_IFINDEX_INDEV]; + if (attr) + nfnl_log_msg_set_indev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_IFINDEX_OUTDEV]; + if (attr) + nfnl_log_msg_set_outdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_IFINDEX_PHYSINDEV]; + if (attr) + nfnl_log_msg_set_physindev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_IFINDEX_PHYSOUTDEV]; + if (attr) + nfnl_log_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_HWADDR]; + if (attr) { + struct nfulnl_msg_packet_hw *hw = nla_data(attr); + + nfnl_log_msg_set_hwaddr(msg, hw->hw_addr, ntohs(hw->hw_addrlen)); + } + + attr = tb[NFULA_PAYLOAD]; + if (attr) { + err = nfnl_log_msg_set_payload(msg, nla_data(attr), nla_len(attr)); + if (err < 0) + goto errout; + } + + attr = tb[NFULA_PREFIX]; + if (attr) { + err = nfnl_log_msg_set_prefix(msg, nla_data(attr)); + if (err < 0) + goto errout; + } + + attr = tb[NFULA_UID]; + if (attr) + nfnl_log_msg_set_uid(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_GID]; + if (attr) + nfnl_log_msg_set_gid(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_SEQ]; + if (attr) + nfnl_log_msg_set_seq(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFULA_SEQ_GLOBAL]; + if (attr) + nfnl_log_msg_set_seq_global(msg, ntohl(nla_get_u32(attr))); + + *result = msg; + return 0; + +errout: + nfnl_log_msg_put(msg); + return err; +} + +static int log_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct nfnl_log_msg *msg; + int err; + + if ((err = nfnlmsg_log_msg_parse(nlh, &msg)) < 0) + goto errout; + + err = pp->pp_cb((struct nl_object *) msg, pp); +errout: + nfnl_log_msg_put(msg); + return err; +} + +/** @} */ + +#define NFNLMSG_LOG_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_ULOG, (type)) +static struct nl_cache_ops nfnl_log_msg_ops = { + .co_name = "netfilter/log_msg", + .co_hdrsize = NFNL_HDRLEN, + .co_msgtypes = { + { NFNLMSG_LOG_TYPE(NFULNL_MSG_PACKET), NL_ACT_NEW, "new" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_NETFILTER, + .co_msg_parser = log_msg_parser, + .co_obj_ops = &log_msg_obj_ops, +}; + +static void __init log_msg_init(void) +{ + nl_cache_mngt_register(&nfnl_log_msg_ops); +} + +static void __exit log_msg_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_log_msg_ops); +} + +/** @} */ diff --git a/lib/netfilter/log_msg_obj.c b/lib/netfilter/log_msg_obj.c new file mode 100644 index 0000000..d2cde4e --- /dev/null +++ b/lib/netfilter/log_msg_obj.c @@ -0,0 +1,458 @@ +/* + * lib/netfilter/log_msg_obj.c Netfilter Log Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> + * Copyright (c) 2007 Secure Computing Corporation + */ + +#include <netlink-local.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/netfilter.h> +#include <netlink/netfilter/log_msg.h> + +/** @cond SKIP */ +#define LOG_MSG_ATTR_FAMILY (1UL << 0) +#define LOG_MSG_ATTR_HWPROTO (1UL << 1) +#define LOG_MSG_ATTR_HOOK (1UL << 2) +#define LOG_MSG_ATTR_MARK (1UL << 3) +#define LOG_MSG_ATTR_TIMESTAMP (1UL << 4) +#define LOG_MSG_ATTR_INDEV (1UL << 5) +#define LOG_MSG_ATTR_OUTDEV (1UL << 6) +#define LOG_MSG_ATTR_PHYSINDEV (1UL << 7) +#define LOG_MSG_ATTR_PHYSOUTDEV (1UL << 8) +#define LOG_MSG_ATTR_HWADDR (1UL << 9) +#define LOG_MSG_ATTR_PAYLOAD (1UL << 10) +#define LOG_MSG_ATTR_PREFIX (1UL << 11) +#define LOG_MSG_ATTR_UID (1UL << 12) +#define LOG_MSG_ATTR_GID (1UL << 13) +#define LOG_MSG_ATTR_SEQ (1UL << 14) +#define LOG_MSG_ATTR_SEQ_GLOBAL (1UL << 15) +/** @endcond */ + +static void log_msg_free_data(struct nl_object *c) +{ + struct nfnl_log_msg *msg = (struct nfnl_log_msg *) c; + + if (msg == NULL) + return; + + free(msg->log_msg_payload); + free(msg->log_msg_prefix); +} + +static int log_msg_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct nfnl_log_msg *dst = (struct nfnl_log_msg *) _dst; + struct nfnl_log_msg *src = (struct nfnl_log_msg *) _src; + int err; + + if (src->log_msg_payload) { + err = nfnl_log_msg_set_payload(dst, src->log_msg_payload, + src->log_msg_payload_len); + if (err < 0) + goto errout; + } + + if (src->log_msg_prefix) { + err = nfnl_log_msg_set_prefix(dst, src->log_msg_prefix); + if (err < 0) + goto errout; + } + + return 0; +errout: + return err; +} + +static void log_msg_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_log_msg *msg = (struct nfnl_log_msg *) a; + struct nl_cache *link_cache; + char buf[64]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_new_line(p); + + if (msg->ce_mask & LOG_MSG_ATTR_PREFIX) + nl_dump(p, "%s", msg->log_msg_prefix); + + if (msg->ce_mask & LOG_MSG_ATTR_INDEV) { + if (link_cache) + nl_dump(p, "IN=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_indev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->log_msg_indev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_PHYSINDEV) { + if (link_cache) + nl_dump(p, "PHYSIN=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_physindev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->log_msg_physindev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_OUTDEV) { + if (link_cache) + nl_dump(p, "OUT=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_outdev, + buf, sizeof(buf))); + else + nl_dump(p, "OUT=%d ", msg->log_msg_outdev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_PHYSOUTDEV) { + if (link_cache) + nl_dump(p, "PHYSOUT=%s ", + rtnl_link_i2name(link_cache, + msg->log_msg_physoutdev, + buf, sizeof(buf))); + else + nl_dump(p, "PHYSOUT=%d ", msg->log_msg_physoutdev); + } + + if (msg->ce_mask & LOG_MSG_ATTR_HWADDR) { + int i; + + nl_dump(p, "MAC"); + for (i = 0; i < msg->log_msg_hwaddr_len; i++) + nl_dump(p, "%c%02x", i?':':'=', msg->log_msg_hwaddr[i]); + nl_dump(p, " "); + } + + /* FIXME: parse the payload to get iptables LOG compatible format */ + + if (msg->ce_mask & LOG_MSG_ATTR_FAMILY) + nl_dump(p, "FAMILY=%s ", + nl_af2str(msg->log_msg_family, buf, sizeof(buf))); + + if (msg->ce_mask & LOG_MSG_ATTR_HWPROTO) + nl_dump(p, "HWPROTO=%s ", + nl_ether_proto2str(ntohs(msg->log_msg_hwproto), + buf, sizeof(buf))); + + if (msg->ce_mask & LOG_MSG_ATTR_HOOK) + nl_dump(p, "HOOK=%s ", + nfnl_inet_hook2str(msg->log_msg_hook, + buf, sizeof(buf))); + + if (msg->ce_mask & LOG_MSG_ATTR_MARK) + nl_dump(p, "MARK=%u ", msg->log_msg_mark); + + if (msg->ce_mask & LOG_MSG_ATTR_PAYLOAD) + nl_dump(p, "PAYLOADLEN=%d ", msg->log_msg_payload_len); + + if (msg->ce_mask & LOG_MSG_ATTR_UID) + nl_dump(p, "UID=%u ", msg->log_msg_uid); + + if (msg->ce_mask & LOG_MSG_ATTR_GID) + nl_dump(p, "GID=%u ", msg->log_msg_gid); + + if (msg->ce_mask & LOG_MSG_ATTR_SEQ) + nl_dump(p, "SEQ=%d ", msg->log_msg_seq); + + if (msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL) + nl_dump(p, "SEQGLOBAL=%d ", msg->log_msg_seq_global); + + nl_dump(p, "\n"); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_log_msg *nfnl_log_msg_alloc(void) +{ + return (struct nfnl_log_msg *) nl_object_alloc(&log_msg_obj_ops); +} + +void nfnl_log_msg_get(struct nfnl_log_msg *msg) +{ + nl_object_get((struct nl_object *) msg); +} + +void nfnl_log_msg_put(struct nfnl_log_msg *msg) +{ + nl_object_put((struct nl_object *) msg); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_log_msg_set_family(struct nfnl_log_msg *msg, uint8_t family) +{ + msg->log_msg_family = family; + msg->ce_mask |= LOG_MSG_ATTR_FAMILY; +} + +uint8_t nfnl_log_msg_get_family(const struct nfnl_log_msg *msg) +{ + if (msg->ce_mask & LOG_MSG_ATTR_FAMILY) + return msg->log_msg_family; + else + return AF_UNSPEC; +} + +void nfnl_log_msg_set_hwproto(struct nfnl_log_msg *msg, uint16_t hwproto) +{ + msg->log_msg_hwproto = hwproto; + msg->ce_mask |= LOG_MSG_ATTR_HWPROTO; +} + +int nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_HWPROTO); +} + +uint16_t nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_hwproto; +} + +void nfnl_log_msg_set_hook(struct nfnl_log_msg *msg, uint8_t hook) +{ + msg->log_msg_hook = hook; + msg->ce_mask |= LOG_MSG_ATTR_HOOK; +} + +int nfnl_log_msg_test_hook(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_HOOK); +} + +uint8_t nfnl_log_msg_get_hook(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_hook; +} + +void nfnl_log_msg_set_mark(struct nfnl_log_msg *msg, uint32_t mark) +{ + msg->log_msg_mark = mark; + msg->ce_mask |= LOG_MSG_ATTR_MARK; +} + +int nfnl_log_msg_test_mark(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_MARK); +} + +uint32_t nfnl_log_msg_get_mark(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_mark; +} + +void nfnl_log_msg_set_timestamp(struct nfnl_log_msg *msg, struct timeval *tv) +{ + msg->log_msg_timestamp.tv_sec = tv->tv_sec; + msg->log_msg_timestamp.tv_usec = tv->tv_usec; + msg->ce_mask |= LOG_MSG_ATTR_TIMESTAMP; +} + +const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *msg) +{ + if (!(msg->ce_mask & LOG_MSG_ATTR_TIMESTAMP)) + return NULL; + return &msg->log_msg_timestamp; +} + +void nfnl_log_msg_set_indev(struct nfnl_log_msg *msg, uint32_t indev) +{ + msg->log_msg_indev = indev; + msg->ce_mask |= LOG_MSG_ATTR_INDEV; +} + +uint32_t nfnl_log_msg_get_indev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_indev; +} + +void nfnl_log_msg_set_outdev(struct nfnl_log_msg *msg, uint32_t outdev) +{ + msg->log_msg_outdev = outdev; + msg->ce_mask |= LOG_MSG_ATTR_OUTDEV; +} + +uint32_t nfnl_log_msg_get_outdev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_outdev; +} + +void nfnl_log_msg_set_physindev(struct nfnl_log_msg *msg, uint32_t physindev) +{ + msg->log_msg_physindev = physindev; + msg->ce_mask |= LOG_MSG_ATTR_PHYSINDEV; +} + +uint32_t nfnl_log_msg_get_physindev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_physindev; +} + +void nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *msg, uint32_t physoutdev) +{ + msg->log_msg_physoutdev = physoutdev; + msg->ce_mask |= LOG_MSG_ATTR_PHYSOUTDEV; +} + +uint32_t nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_physoutdev; +} + +void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *msg, uint8_t *hwaddr, int len) +{ + if (len > sizeof(msg->log_msg_hwaddr)) + len = sizeof(msg->log_msg_hwaddr); + msg->log_msg_hwaddr_len = len; + memcpy(msg->log_msg_hwaddr, hwaddr, len); + msg->ce_mask |= LOG_MSG_ATTR_HWADDR; +} + +const uint8_t *nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *msg, int *len) +{ + if (!(msg->ce_mask & LOG_MSG_ATTR_HWADDR)) { + *len = 0; + return NULL; + } + + *len = msg->log_msg_hwaddr_len; + return msg->log_msg_hwaddr; +} + +int nfnl_log_msg_set_payload(struct nfnl_log_msg *msg, uint8_t *payload, int len) +{ + free(msg->log_msg_payload); + msg->log_msg_payload = malloc(len); + if (!msg->log_msg_payload) + return -NLE_NOMEM; + + memcpy(msg->log_msg_payload, payload, len); + msg->log_msg_payload_len = len; + msg->ce_mask |= LOG_MSG_ATTR_PAYLOAD; + return 0; +} + +const void *nfnl_log_msg_get_payload(const struct nfnl_log_msg *msg, int *len) +{ + if (!(msg->ce_mask & LOG_MSG_ATTR_PAYLOAD)) { + *len = 0; + return NULL; + } + + *len = msg->log_msg_payload_len; + return msg->log_msg_payload; +} + +int nfnl_log_msg_set_prefix(struct nfnl_log_msg *msg, void *prefix) +{ + free(msg->log_msg_prefix); + msg->log_msg_prefix = strdup(prefix); + if (!msg->log_msg_prefix) + return -NLE_NOMEM; + + msg->ce_mask |= LOG_MSG_ATTR_PREFIX; + return 0; +} + +const char *nfnl_log_msg_get_prefix(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_prefix; +} + +void nfnl_log_msg_set_uid(struct nfnl_log_msg *msg, uint32_t uid) +{ + msg->log_msg_uid = uid; + msg->ce_mask |= LOG_MSG_ATTR_UID; +} + +int nfnl_log_msg_test_uid(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_UID); +} + +uint32_t nfnl_log_msg_get_uid(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_uid; +} + +void nfnl_log_msg_set_gid(struct nfnl_log_msg *msg, uint32_t gid) +{ + msg->log_msg_gid = gid; + msg->ce_mask |= LOG_MSG_ATTR_GID; +} + +int nfnl_log_msg_test_gid(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_GID); +} + +uint32_t nfnl_log_msg_get_gid(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_gid; +} + + +void nfnl_log_msg_set_seq(struct nfnl_log_msg *msg, uint32_t seq) +{ + msg->log_msg_seq = seq; + msg->ce_mask |= LOG_MSG_ATTR_SEQ; +} + +int nfnl_log_msg_test_seq(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ); +} + +uint32_t nfnl_log_msg_get_seq(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_seq; +} + +void nfnl_log_msg_set_seq_global(struct nfnl_log_msg *msg, uint32_t seq_global) +{ + msg->log_msg_seq_global = seq_global; + msg->ce_mask |= LOG_MSG_ATTR_SEQ_GLOBAL; +} + +int nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *msg) +{ + return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL); +} + +uint32_t nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *msg) +{ + return msg->log_msg_seq_global; +} + +/** @} */ + +struct nl_object_ops log_msg_obj_ops = { + .oo_name = "netfilter/log_msg", + .oo_size = sizeof(struct nfnl_log_msg), + .oo_free_data = log_msg_free_data, + .oo_clone = log_msg_clone, + .oo_dump = { + [NL_DUMP_LINE] = log_msg_dump, + [NL_DUMP_DETAILS] = log_msg_dump, + [NL_DUMP_STATS] = log_msg_dump, + }, +}; + +/** @} */ diff --git a/lib/netfilter/log_obj.c b/lib/netfilter/log_obj.c index c3adc51..ff2b63a 100644 --- a/lib/netfilter/log_obj.c +++ b/lib/netfilter/log_obj.c @@ -6,9 +6,10 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> */ #include <netlink-local.h> @@ -16,143 +17,61 @@ #include <netlink/netfilter/log.h> /** @cond SKIP */ -#define LOG_ATTR_FAMILY (1UL << 0) -#define LOG_ATTR_HWPROTO (1UL << 1) -#define LOG_ATTR_HOOK (1UL << 2) -#define LOG_ATTR_MARK (1UL << 3) -#define LOG_ATTR_TIMESTAMP (1UL << 4) -#define LOG_ATTR_INDEV (1UL << 5) -#define LOG_ATTR_OUTDEV (1UL << 6) -#define LOG_ATTR_PHYSINDEV (1UL << 7) -#define LOG_ATTR_PHYSOUTDEV (1UL << 8) -#define LOG_ATTR_HWADDR (1UL << 9) -#define LOG_ATTR_PAYLOAD (1UL << 10) -#define LOG_ATTR_PREFIX (1UL << 11) -#define LOG_ATTR_UID (1UL << 12) -#define LOG_ATTR_SEQ (1UL << 13) -#define LOG_ATTR_SEQ_GLOBAL (1UL << 14) +#define LOG_ATTR_GROUP (1UL << 0) +#define LOG_ATTR_COPY_MODE (1UL << 1) +#define LOG_ATTR_COPY_RANGE (1UL << 3) +#define LOG_ATTR_FLUSH_TIMEOUT (1UL << 4) +#define LOG_ATTR_ALLOC_SIZE (1UL << 5) +#define LOG_ATTR_QUEUE_THRESHOLD (1UL << 6) + /** @endcond */ -static void log_free_data(struct nl_object *c) +static void nfnl_log_dump(struct nl_object *a, struct nl_dump_params *p) { - struct nfnl_log *log = (struct nfnl_log *) c; + struct nfnl_log *log = (struct nfnl_log *) a; + char buf[64]; + + nl_new_line(p); + + if (log->ce_mask & LOG_ATTR_GROUP) + nl_dump(p, "group=%u ", log->log_group); + + if (log->ce_mask & LOG_ATTR_COPY_MODE) + nl_dump(p, "copy_mode=%s ", + nfnl_log_copy_mode2str(log->log_copy_mode, + buf, sizeof(buf))); + + if (log->ce_mask & LOG_ATTR_COPY_RANGE) + nl_dump(p, "copy_range=%u ", log->log_copy_range); - if (log == NULL) - return; + if (log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT) + nl_dump(p, "flush_timeout=%u ", log->log_flush_timeout); - free(log->log_payload); - free(log->log_prefix); + if (log->ce_mask & LOG_ATTR_ALLOC_SIZE) + nl_dump(p, "alloc_size=%u ", log->log_alloc_size); + + if (log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD) + nl_dump(p, "queue_threshold=%u ", log->log_queue_threshold); + + nl_dump(p, "\n"); } -static int log_clone(struct nl_object *_dst, struct nl_object *_src) +static struct trans_tbl copy_modes[] = { + __ADD(NFNL_LOG_COPY_NONE, none) + __ADD(NFNL_LOG_COPY_META, meta) + __ADD(NFNL_LOG_COPY_PACKET, packet) +}; + +char *nfnl_log_copy_mode2str(enum nfnl_log_copy_mode copy_mode, char *buf, + size_t len) { - struct nfnl_log *dst = (struct nfnl_log *) _dst; - struct nfnl_log *src = (struct nfnl_log *) _src; - int err; - - if (src->log_payload) { - err = nfnl_log_set_payload(dst, src->log_payload, - src->log_payload_len); - if (err < 0) - goto errout; - } - - if (src->log_prefix) { - err = nfnl_log_set_prefix(dst, src->log_prefix); - if (err < 0) - goto errout; - } - - return 0; -errout: - return err; + return __type2str(copy_mode, buf, len, copy_modes, + ARRAY_SIZE(copy_modes)); } -static int log_dump(struct nl_object *a, struct nl_dump_params *p) +enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *name) { - struct nfnl_log *log = (struct nfnl_log *) a; - struct nl_cache *link_cache; - char buf[64]; - - link_cache = nl_cache_mngt_require("route/link"); - - if (log->ce_mask & LOG_ATTR_PREFIX) - dp_dump(p, "%s", log->log_prefix); - - if (log->ce_mask & LOG_ATTR_INDEV) { - if (link_cache) - dp_dump(p, "IN=%s ", - rtnl_link_i2name(link_cache, log->log_indev, - buf, sizeof(buf))); - else - dp_dump(p, "IN=%d ", log->log_indev); - } - - if (log->ce_mask & LOG_ATTR_PHYSINDEV) { - if (link_cache) - dp_dump(p, "PHYSIN=%s ", - rtnl_link_i2name(link_cache, log->log_physindev, - buf, sizeof(buf))); - else - dp_dump(p, "IN=%d ", log->log_physindev); - } - - if (log->ce_mask & LOG_ATTR_OUTDEV) { - if (link_cache) - dp_dump(p, "OUT=%s ", - rtnl_link_i2name(link_cache, log->log_outdev, - buf, sizeof(buf))); - else - dp_dump(p, "OUT=%d ", log->log_outdev); - } - - if (log->ce_mask & LOG_ATTR_PHYSOUTDEV) { - if (link_cache) - dp_dump(p, "PHYSOUT=%s ", - rtnl_link_i2name(link_cache,log->log_physoutdev, - buf, sizeof(buf))); - else - dp_dump(p, "PHYSOUT=%d ", log->log_physoutdev); - } - - if (log->ce_mask & LOG_ATTR_HWADDR) { - int i; - - dp_dump(p, "MAC"); - for (i = 0; i < log->log_hwaddr_len; i++) - dp_dump(p, "%c%02x", i?':':'=', log->log_hwaddr[i]); - dp_dump(p, " "); - } - - /* FIXME: parse the payload to get iptables LOG compatible format */ - - if (log->ce_mask & LOG_ATTR_FAMILY) - dp_dump(p, "FAMILY=%s ", - nl_af2str(log->log_family, buf, sizeof(buf))); - - if (log->ce_mask & LOG_ATTR_HWPROTO) - dp_dump(p, "HWPROTO=%s ", - nl_ether_proto2str(ntohs(log->log_hwproto), - buf, sizeof(buf))); - - if (log->ce_mask & LOG_ATTR_HOOK) - dp_dump(p, "HOOK=%d ", log->log_hook); - - if (log->ce_mask & LOG_ATTR_MARK) - dp_dump(p, "MARK=%d ", log->log_mark); - - if (log->ce_mask & LOG_ATTR_PAYLOAD) - dp_dump(p, "PAYLOADLEN=%d ", log->log_payload_len); - - if (log->ce_mask & LOG_ATTR_SEQ) - dp_dump(p, "SEQ=%d ", log->log_seq); - - if (log->ce_mask & LOG_ATTR_SEQ_GLOBAL) - dp_dump(p, "SEQGLOBAL=%d ", log->log_seq_global); - - dp_dump(p, "\n"); - - return 1; + return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes)); } /** @@ -182,232 +101,172 @@ void nfnl_log_put(struct nfnl_log *log) * @{ */ -void nfnl_log_set_family(struct nfnl_log *log, uint8_t family) -{ - log->log_family = family; - log->ce_mask |= LOG_ATTR_FAMILY; -} - -uint8_t nfnl_log_get_family(const struct nfnl_log *log) -{ - if (log->ce_mask & LOG_ATTR_FAMILY) - return log->log_family; - else - return AF_UNSPEC; -} - -void nfnl_log_set_hwproto(struct nfnl_log *log, uint16_t hwproto) -{ - log->log_hwproto = hwproto; - log->ce_mask |= LOG_ATTR_HWPROTO; -} - -int nfnl_log_test_hwproto(const struct nfnl_log *log) -{ - return !!(log->ce_mask & LOG_ATTR_HWPROTO); -} - -uint16_t nfnl_log_get_hwproto(const struct nfnl_log *log) +void nfnl_log_set_group(struct nfnl_log *log, uint16_t group) { - return log->log_hwproto; + log->log_group = group; + log->ce_mask |= LOG_ATTR_GROUP; } -void nfnl_log_set_hook(struct nfnl_log *log, uint8_t hook) +int nfnl_log_test_group(const struct nfnl_log *log) { - log->log_hook = hook; - log->ce_mask |= LOG_ATTR_HOOK; + return !!(log->ce_mask & LOG_ATTR_GROUP); } -int nfnl_log_test_hook(const struct nfnl_log *log) +uint16_t nfnl_log_get_group(const struct nfnl_log *log) { - return !!(log->ce_mask & LOG_ATTR_HOOK); + return log->log_group; } -uint8_t nfnl_log_get_hook(const struct nfnl_log *log) +void nfnl_log_set_copy_mode(struct nfnl_log *log, enum nfnl_log_copy_mode mode) { - return log->log_hook; + log->log_copy_mode = mode; + log->ce_mask |= LOG_ATTR_COPY_MODE; } -void nfnl_log_set_mark(struct nfnl_log *log, uint32_t mark) +int nfnl_log_test_copy_mode(const struct nfnl_log *log) { - log->log_mark = mark; - log->ce_mask |= LOG_ATTR_MARK; + return !!(log->ce_mask & LOG_ATTR_COPY_MODE); } -int nfnl_log_test_mark(const struct nfnl_log *log) +enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *log) { - return !!(log->ce_mask & LOG_ATTR_MARK); + return log->log_copy_mode; } -uint32_t nfnl_log_get_mark(const struct nfnl_log *log) +void nfnl_log_set_copy_range(struct nfnl_log *log, uint32_t copy_range) { - return log->log_mark; + log->log_copy_range = copy_range; + log->ce_mask |= LOG_ATTR_COPY_RANGE; } -void nfnl_log_set_timestamp(struct nfnl_log *log, struct timeval *tv) +int nfnl_log_test_copy_range(const struct nfnl_log *log) { - log->log_timestamp.tv_sec = tv->tv_sec; - log->log_timestamp.tv_usec = tv->tv_usec; - log->ce_mask |= LOG_ATTR_TIMESTAMP; + return !!(log->ce_mask & LOG_ATTR_COPY_RANGE); } -const struct timeval *nfnl_log_get_timestamp(const struct nfnl_log *log) +uint32_t nfnl_log_get_copy_range(const struct nfnl_log *log) { - if (!(log->ce_mask & LOG_ATTR_TIMESTAMP)) - return NULL; - return &log->log_timestamp; + return log->log_copy_range; } -void nfnl_log_set_indev(struct nfnl_log *log, uint32_t indev) +void nfnl_log_set_flush_timeout(struct nfnl_log *log, uint32_t timeout) { - log->log_indev = indev; - log->ce_mask |= LOG_ATTR_INDEV; + log->log_flush_timeout = timeout; + log->ce_mask |= LOG_ATTR_FLUSH_TIMEOUT; } -uint32_t nfnl_log_get_indev(const struct nfnl_log *log) +int nfnl_log_test_flush_timeout(const struct nfnl_log *log) { - return log->log_indev; + return !!(log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT); } -void nfnl_log_set_outdev(struct nfnl_log *log, uint32_t outdev) +uint32_t nfnl_log_get_flush_timeout(const struct nfnl_log *log) { - log->log_outdev = outdev; - log->ce_mask |= LOG_ATTR_OUTDEV; + return log->log_flush_timeout; } -uint32_t nfnl_log_get_outdev(const struct nfnl_log *log) +void nfnl_log_set_alloc_size(struct nfnl_log *log, uint32_t alloc_size) { - return log->log_outdev; + log->log_alloc_size = alloc_size; + log->ce_mask |= LOG_ATTR_ALLOC_SIZE; } -void nfnl_log_set_physindev(struct nfnl_log *log, uint32_t physindev) +int nfnl_log_test_alloc_size(const struct nfnl_log *log) { - log->log_physindev = physindev; - log->ce_mask |= LOG_ATTR_PHYSINDEV; + return !!(log->ce_mask & LOG_ATTR_ALLOC_SIZE); } -uint32_t nfnl_log_get_physindev(const struct nfnl_log *log) +uint32_t nfnl_log_get_alloc_size(const struct nfnl_log *log) { - return log->log_physindev; + return log->log_alloc_size; } -void nfnl_log_set_physoutdev(struct nfnl_log *log, uint32_t physoutdev) +void nfnl_log_set_queue_threshold(struct nfnl_log *log, uint32_t threshold) { - log->log_physoutdev = physoutdev; - log->ce_mask |= LOG_ATTR_PHYSOUTDEV; + log->log_queue_threshold = threshold; + log->ce_mask |= LOG_ATTR_QUEUE_THRESHOLD; } -uint32_t nfnl_log_get_physoutdev(const struct nfnl_log *log) +int nfnl_log_test_queue_threshold(const struct nfnl_log *log) { - return log->log_physoutdev; + return !!(log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD); } -void nfnl_log_set_hwaddr(struct nfnl_log *log, uint8_t *hwaddr, int len) +uint32_t nfnl_log_get_queue_threshold(const struct nfnl_log *log) { - if (len > sizeof(log->log_hwaddr)) - len = sizeof(log->log_hwaddr); - log->log_hwaddr_len = len; - memcpy(log->log_hwaddr, hwaddr, len); - log->ce_mask |= LOG_ATTR_HWADDR; + return log->log_queue_threshold; } -const uint8_t *nfnl_log_get_hwaddr(const struct nfnl_log *log, int *len) -{ - if (!(log->ce_mask & LOG_ATTR_HWADDR)) { - *len = 0; - return NULL; - } - - *len = log->log_hwaddr_len; - return log->log_hwaddr; -} - -int nfnl_log_set_payload(struct nfnl_log *log, uint8_t *payload, int len) -{ - free(log->log_payload); - log->log_payload = malloc(len); - if (!log->log_payload) - return nl_errno(ENOMEM); - - memcpy(log->log_payload, payload, len); - log->log_payload_len = len; - log->ce_mask |= LOG_ATTR_PAYLOAD; - return 0; -} - -const void *nfnl_log_get_payload(const struct nfnl_log *log, int *len) +/* We don't actually use the flags for anything yet since the + * nfnetlog_log interface truly sucks - it only contains the + * flag value, but not mask, so we would have to make assumptions + * about the supported flags. + */ +void nfnl_log_set_flags(struct nfnl_log *log, unsigned int flags) { - if (!(log->ce_mask & LOG_ATTR_PAYLOAD)) { - *len = 0; - return NULL; - } - - *len = log->log_payload_len; - return log->log_payload; + log->log_flags |= flags; + log->log_flag_mask |= flags; } -int nfnl_log_set_prefix(struct nfnl_log *log, void *prefix) +void nfnl_log_unset_flags(struct nfnl_log *log, unsigned int flags) { - free(log->log_prefix); - log->log_prefix = strdup(prefix); - if (!log->log_prefix) - return nl_errno(ENOMEM); - - log->ce_mask |= LOG_ATTR_PREFIX; - return 0; + log->log_flags &= ~flags; + log->log_flag_mask |= flags; } -const char *nfnl_log_get_prefix(const struct nfnl_log *log) -{ - return log->log_prefix; -} +static struct trans_tbl log_flags[] = { + __ADD(NFNL_LOG_FLAG_SEQ, seq) + __ADD(NFNL_LOG_FLAG_SEQ_GLOBAL, seq_global) +}; -void nfnl_log_set_uid(struct nfnl_log *log, uint32_t uid) +char *nfnl_log_flags2str(unsigned int flags, char *buf, size_t len) { - log->log_uid = uid; - log->ce_mask |= LOG_ATTR_UID; + return __flags2str(flags, buf, len, log_flags, ARRAY_SIZE(log_flags)); } -int nfnl_log_test_uid(const struct nfnl_log *log) +unsigned int nfnl_log_str2flags(const char *name) { - return !!(log->ce_mask & LOG_ATTR_UID); + return __str2flags(name, log_flags, ARRAY_SIZE(log_flags)); } -uint32_t nfnl_log_get_uid(const struct nfnl_log *log) +static int nfnl_log_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) { - return log->log_uid; -} + struct nfnl_log *a = (struct nfnl_log *) _a; + struct nfnl_log *b = (struct nfnl_log *) _b; + int diff = 0; -void nfnl_log_set_seq(struct nfnl_log *log, uint32_t seq) -{ - log->log_seq = seq; - log->ce_mask |= LOG_ATTR_SEQ; -} +#define NFNL_LOG_DIFF(ATTR, EXPR) \ + ATTR_DIFF(attrs, LOG_ATTR_##ATTR, a, b, EXPR) +#define NFNL_LOG_DIFF_VAL(ATTR, FIELD) \ + NFNL_LOG_DIFF(ATTR, a->FIELD != b->FIELD) -int nfnl_log_test_seq(const struct nfnl_log *log) -{ - return !!(log->ce_mask & LOG_ATTR_SEQ); -} + diff |= NFNL_LOG_DIFF_VAL(GROUP, log_group); + diff |= NFNL_LOG_DIFF_VAL(COPY_MODE, log_copy_mode); + diff |= NFNL_LOG_DIFF_VAL(COPY_RANGE, log_copy_range); + diff |= NFNL_LOG_DIFF_VAL(FLUSH_TIMEOUT, log_flush_timeout); + diff |= NFNL_LOG_DIFF_VAL(ALLOC_SIZE, log_alloc_size); + diff |= NFNL_LOG_DIFF_VAL(QUEUE_THRESHOLD, log_queue_threshold); -uint32_t nfnl_log_get_seq(const struct nfnl_log *log) -{ - return log->log_seq; -} +#undef NFNL_LOG_DIFF +#undef NFNL_LOG_DIFF_VAL -void nfnl_log_set_seq_global(struct nfnl_log *log, uint32_t seq_global) -{ - log->log_seq_global = seq_global; - log->ce_mask |= LOG_ATTR_SEQ_GLOBAL; + return diff; } -int nfnl_log_test_seq_global(const struct nfnl_log *log) -{ - return !!(log->ce_mask & LOG_ATTR_SEQ_GLOBAL); -} +static struct trans_tbl nfnl_log_attrs[] = { + __ADD(LOG_ATTR_GROUP, group) + __ADD(LOG_ATTR_COPY_MODE, copy_mode) + __ADD(LOG_ATTR_COPY_RANGE, copy_range) + __ADD(LOG_ATTR_FLUSH_TIMEOUT, flush_timeout) + __ADD(LOG_ATTR_ALLOC_SIZE, alloc_size) + __ADD(LOG_ATTR_QUEUE_THRESHOLD, queue_threshold) +}; -uint32_t nfnl_log_get_seq_global(const struct nfnl_log *log) +static char *nfnl_log_attrs2str(int attrs, char *buf, size_t len) { - return log->log_seq_global; + return __flags2str(attrs, buf, len, nfnl_log_attrs, + ARRAY_SIZE(nfnl_log_attrs)); } /** @} */ @@ -415,11 +274,14 @@ uint32_t nfnl_log_get_seq_global(const struct nfnl_log *log) struct nl_object_ops log_obj_ops = { .oo_name = "netfilter/log", .oo_size = sizeof(struct nfnl_log), - .oo_free_data = log_free_data, - .oo_clone = log_clone, - .oo_dump[NL_DUMP_BRIEF] = log_dump, - .oo_dump[NL_DUMP_FULL] = log_dump, - .oo_dump[NL_DUMP_STATS] = log_dump, + .oo_dump = { + [NL_DUMP_LINE] = nfnl_log_dump, + [NL_DUMP_DETAILS] = nfnl_log_dump, + [NL_DUMP_STATS] = nfnl_log_dump, + }, + .oo_compare = nfnl_log_compare, + .oo_attrs2str = nfnl_log_attrs2str, + .oo_id_attrs = LOG_ATTR_GROUP, }; /** @} */ diff --git a/lib/netfilter/netfilter.c b/lib/netfilter/netfilter.c new file mode 100644 index 0000000..f88b355 --- /dev/null +++ b/lib/netfilter/netfilter.c @@ -0,0 +1,53 @@ +/* + * lib/netfilter/netfilter.c Netfilter Generic Functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + */ + +#include <netlink-local.h> +#include <netlink/netfilter/netfilter.h> +#include <linux/netfilter.h> + +static struct trans_tbl nfnl_verdicts[] = { + __ADD(NF_DROP, NF_DROP) + __ADD(NF_ACCEPT, NF_ACCEPT) + __ADD(NF_STOLEN, NF_STOLEN) + __ADD(NF_QUEUE, NF_QUEUE) + __ADD(NF_REPEAT, NF_REPEAT) + __ADD(NF_STOP, NF_STOP) +}; + +char *nfnl_verdict2str(unsigned int verdict, char *buf, size_t len) +{ + return __type2str(verdict, buf, len, nfnl_verdicts, + ARRAY_SIZE(nfnl_verdicts)); +} + +unsigned int nfnl_str2verdict(const char *name) +{ + return __str2type(name, nfnl_verdicts, ARRAY_SIZE(nfnl_verdicts)); +} + +static struct trans_tbl nfnl_inet_hooks[] = { + __ADD(NF_INET_PRE_ROUTING, NF_INET_PREROUTING) + __ADD(NF_INET_LOCAL_IN, NF_INET_LOCAL_IN) + __ADD(NF_INET_FORWARD, NF_INET_FORWARD) + __ADD(NF_INET_LOCAL_OUT, NF_INET_LOCAL_OUT) + __ADD(NF_INET_POST_ROUTING, NF_INET_POST_ROUTING) +}; + +char *nfnl_inet_hook2str(unsigned int hook, char *buf, size_t len) +{ + return __type2str(hook, buf, len, nfnl_inet_hooks, + ARRAY_SIZE(nfnl_inet_hooks)); +} + +unsigned int nfnl_str2inet_hook(const char *name) +{ + return __str2type(name, nfnl_inet_hooks, ARRAY_SIZE(nfnl_inet_hooks)); +} diff --git a/lib/netfilter/nfnl.c b/lib/netfilter/nfnl.c index 554e234..ddce4b9 100644 --- a/lib/netfilter/nfnl.c +++ b/lib/netfilter/nfnl.c @@ -6,13 +6,12 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ /** - * @ingroup nlfam * @defgroup nfnl Netfilter Netlink * * @par Message Format @@ -47,7 +46,7 @@ * nla_put_u32(msg, 1, 0x10); * * // Message is ready to be sent. - * nl_send_auto_complete(nl_handle, msg); + * nl_send_auto_complete(sk, msg); * * // All done? Free the message. * nlmsg_free(msg); @@ -57,7 +56,7 @@ * @code * // For trivial messages not requiring any subsys specific header or * // attributes, nfnl_send_simple() may be used to send messages directly. - * nfnl_send_simple(nl_handle, SUBSYS, TYPE, 0, FAMILY, RES_ID); + * nfnl_send_simple(sk, SUBSYS, TYPE, 0, FAMILY, RES_ID); * @endcode * @{ */ @@ -73,7 +72,7 @@ /** * Create and connect netfilter netlink socket. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * * Creates a NETLINK_NETFILTER netlink socket, binds the socket and * issues a connection attempt. @@ -82,9 +81,9 @@ * * @return 0 on success or a negative error code. */ -int nfnl_connect(struct nl_handle *handle) +int nfnl_connect(struct nl_sock *sk) { - return nl_connect(handle, NETLINK_NETFILTER); + return nl_connect(sk, NETLINK_NETFILTER); } /** @} */ @@ -96,7 +95,7 @@ int nfnl_connect(struct nl_handle *handle) /** * Send trivial netfilter netlink message - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg subsys_id nfnetlink subsystem * @arg type nfnetlink message type * @arg flags message flags @@ -105,7 +104,7 @@ int nfnl_connect(struct nl_handle *handle) * * @return Newly allocated netlink message or NULL. */ -int nfnl_send_simple(struct nl_handle *handle, uint8_t subsys_id, uint8_t type, +int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type, int flags, uint8_t family, uint16_t res_id) { struct nfgenmsg hdr = { @@ -114,7 +113,7 @@ int nfnl_send_simple(struct nl_handle *handle, uint8_t subsys_id, uint8_t type, .res_id = htons(res_id), }; - return nl_send_simple(handle, NFNLMSG_TYPE(subsys_id, type), flags, + return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags, &hdr, sizeof(hdr)); } @@ -178,7 +177,7 @@ static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id) nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO); if (nfg == NULL) - return nl_errno(ENOMEM); + return -NLE_NOMEM; nfg->nfgen_family = family; nfg->version = NFNETLINK_V0; @@ -236,7 +235,7 @@ int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags); if (nlh == NULL) - return nl_get_errno(); + return -NLE_MSGSIZE; return nfnlmsg_append(msg, family, res_id); } diff --git a/lib/netfilter/queue.c b/lib/netfilter/queue.c new file mode 100644 index 0000000..ff1de0e --- /dev/null +++ b/lib/netfilter/queue.c @@ -0,0 +1,251 @@ +/* + * lib/netfilter/queue.c Netfilter Queue + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup nfnl + * @defgroup queue Queue + * @brief + * @{ + */ + +#include <sys/types.h> +#include <linux/netfilter/nfnetlink_queue.h> + +#include <netlink-local.h> +#include <netlink/attr.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/queue.h> + +struct nl_sock *nfnl_queue_socket_alloc(void) +{ + struct nl_sock *nlsk; + + nlsk = nl_socket_alloc(); + if (nlsk) + nl_socket_disable_auto_ack(nlsk); + return nlsk; +} + +static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg) +{ + int err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + +/** + * @name Queue Commands + * @{ + */ + +static int build_queue_cmd_request(uint8_t family, uint16_t queuenum, + uint8_t command, struct nl_msg **result) +{ + struct nl_msg *msg; + struct nfqnl_msg_config_cmd cmd; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0, + family, queuenum); + if (msg == NULL) + return -NLE_NOMEM; + + cmd.pf = htons(family); + cmd._pad = 0; + cmd.command = command; + if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0) + goto nla_put_failure; + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result) +{ + return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result); +} + +int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result) +{ + return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result); +} + +int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +static int nfnl_queue_build_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + struct nl_msg *msg; + + if (!nfnl_queue_test_group(queue)) + return -NLE_MISSING_ATTR; + + msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0, + 0, nfnl_queue_get_group(queue)); + if (msg == NULL) + return -NLE_NOMEM; + + if (nfnl_queue_test_maxlen(queue) && + nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN, + htonl(nfnl_queue_get_maxlen(queue))) < 0) + goto nla_put_failure; + + /* This sucks, the nfnetlink_queue interface always expects both + * parameters to be present. Needs to be done properly. + */ + if (nfnl_queue_test_copy_mode(queue)) { + struct nfqnl_msg_config_params params; + + switch (nfnl_queue_get_copy_mode(queue)) { + case NFNL_QUEUE_COPY_NONE: + params.copy_mode = NFQNL_COPY_NONE; + break; + case NFNL_QUEUE_COPY_META: + params.copy_mode = NFQNL_COPY_META; + break; + case NFNL_QUEUE_COPY_PACKET: + params.copy_mode = NFQNL_COPY_PACKET; + break; + } + params.copy_range = htonl(nfnl_queue_get_copy_range(queue)); + + if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), ¶ms) < 0) + goto nla_put_failure; + } + + *result = msg; + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; +} + +int nfnl_queue_build_create_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + struct nfqnl_msg_config_cmd cmd; + int err; + + if ((err = nfnl_queue_build_request(queue, result)) < 0) + return err; + + cmd.pf = 0; + cmd._pad = 0; + cmd.command = NFQNL_CFG_CMD_BIND; + + NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd); + + return 0; + +nla_put_failure: + nlmsg_free(*result); + return -NLE_MSGSIZE; +} + +int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +int nfnl_queue_build_change_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + return nfnl_queue_build_request(queue, result); +} + +int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +int nfnl_queue_build_delete_request(const struct nfnl_queue *queue, + struct nl_msg **result) +{ + if (!nfnl_queue_test_group(queue)) + return -NLE_MISSING_ATTR; + + return build_queue_cmd_request(0, nfnl_queue_get_group(queue), + NFQNL_CFG_CMD_UNBIND, result); +} + +int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue) +{ + struct nl_msg *msg; + int err; + + if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0) + return err; + + return send_queue_request(nlh, msg); +} + +/** @} */ + +static struct nl_cache_ops nfnl_queue_ops = { + .co_name = "netfilter/queue", + .co_obj_ops = &queue_obj_ops, + .co_msgtypes = { + END_OF_MSGTYPES_LIST, + }, +}; + +static void __init nfnl_queue_init(void) +{ + nl_cache_mngt_register(&nfnl_queue_ops); +} + +static void __exit nfnl_queue_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_queue_ops); +} + +/** @} */ diff --git a/lib/netfilter/queue_msg.c b/lib/netfilter/queue_msg.c new file mode 100644 index 0000000..ab0a58b --- /dev/null +++ b/lib/netfilter/queue_msg.c @@ -0,0 +1,284 @@ +/* + * lib/netfilter/queue_msg.c Netfilter Queue Messages + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + * Copyright (c) 2010 Karl Hiramoto <karl@hiramoto.org> + */ + +/** + * @ingroup nfnl + * @defgroup queue Queue + * @brief + * @{ + */ + +#include <sys/types.h> +#include <linux/netfilter/nfnetlink_queue.h> + +#include <netlink-local.h> +#include <netlink/attr.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/queue_msg.h> + +static struct nl_cache_ops nfnl_queue_msg_ops; + +#if __BYTE_ORDER == __BIG_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return x; +} +#elif __BYTE_ORDER == __LITTLE_ENDIAN +static uint64_t ntohll(uint64_t x) +{ + return __bswap_64(x); +} +#endif + +static struct nla_policy queue_policy[NFQA_MAX+1] = { + [NFQA_PACKET_HDR] = { + .minlen = sizeof(struct nfqnl_msg_packet_hdr), + }, + [NFQA_VERDICT_HDR] = { + .minlen = sizeof(struct nfqnl_msg_verdict_hdr), + }, + [NFQA_MARK] = { .type = NLA_U32 }, + [NFQA_TIMESTAMP] = { + .minlen = sizeof(struct nfqnl_msg_packet_timestamp), + }, + [NFQA_IFINDEX_INDEV] = { .type = NLA_U32 }, + [NFQA_IFINDEX_OUTDEV] = { .type = NLA_U32 }, + [NFQA_IFINDEX_PHYSINDEV] = { .type = NLA_U32 }, + [NFQA_IFINDEX_PHYSOUTDEV] = { .type = NLA_U32 }, + [NFQA_HWADDR] = { + .minlen = sizeof(struct nfqnl_msg_packet_hw), + }, +}; + +int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh, + struct nfnl_queue_msg **result) +{ + struct nfnl_queue_msg *msg; + struct nlattr *tb[NFQA_MAX+1]; + struct nlattr *attr; + int err; + + msg = nfnl_queue_msg_alloc(); + if (!msg) + return -NLE_NOMEM; + + msg->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX, + queue_policy); + if (err < 0) + goto errout; + + nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh)); + nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh)); + + attr = tb[NFQA_PACKET_HDR]; + if (attr) { + struct nfqnl_msg_packet_hdr *hdr = nla_data(attr); + + nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id)); + if (hdr->hw_protocol) + nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol); + nfnl_queue_msg_set_hook(msg, hdr->hook); + } + + attr = tb[NFQA_MARK]; + if (attr) + nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_TIMESTAMP]; + if (attr) { + struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr); + struct timeval tv; + + tv.tv_sec = ntohll(timestamp->sec); + tv.tv_usec = ntohll(timestamp->usec); + nfnl_queue_msg_set_timestamp(msg, &tv); + } + + attr = tb[NFQA_IFINDEX_INDEV]; + if (attr) + nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_IFINDEX_OUTDEV]; + if (attr) + nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_IFINDEX_PHYSINDEV]; + if (attr) + nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_IFINDEX_PHYSOUTDEV]; + if (attr) + nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr))); + + attr = tb[NFQA_HWADDR]; + if (attr) { + struct nfqnl_msg_packet_hw *hw = nla_data(attr); + + nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr, + ntohs(hw->hw_addrlen)); + } + + attr = tb[NFQA_PAYLOAD]; + if (attr) { + err = nfnl_queue_msg_set_payload(msg, nla_data(attr), + nla_len(attr)); + if (err < 0) + goto errout; + } + + *result = msg; + return 0; + +errout: + nfnl_queue_msg_put(msg); + return err; +} + +static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct nfnl_queue_msg *msg; + int err; + + if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0) + goto errout; + + err = pp->pp_cb((struct nl_object *) msg, pp); +errout: + nfnl_queue_msg_put(msg); + return err; +} + +/** @} */ + +struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg) +{ + struct nl_msg *nlmsg; + struct nfqnl_msg_verdict_hdr verdict; + + nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0, + nfnl_queue_msg_get_family(msg), + nfnl_queue_msg_get_group(msg)); + if (nlmsg == NULL) + return NULL; + + verdict.id = htonl(nfnl_queue_msg_get_packetid(msg)); + verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg)); + if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0) + goto nla_put_failure; + + if (nfnl_queue_msg_test_mark(msg) && + nla_put_u32(nlmsg, NFQA_MARK, + ntohl(nfnl_queue_msg_get_mark(msg))) < 0) + goto nla_put_failure; + + return nlmsg; + +nla_put_failure: + nlmsg_free(nlmsg); + return NULL; +} + +/** +* Send a message verdict/mark +* @arg nlh netlink messsage header +* @arg msg queue msg +* @return 0 on OK or error code +*/ +int nfnl_queue_msg_send_verdict(struct nl_sock *nlh, + const struct nfnl_queue_msg *msg) +{ + struct nl_msg *nlmsg; + int err; + + nlmsg = nfnl_queue_msg_build_verdict(msg); + if (nlmsg == NULL) + return -NLE_NOMEM; + + err = nl_send_auto_complete(nlh, nlmsg); + nlmsg_free(nlmsg); + if (err < 0) + return err; + return wait_for_ack(nlh); +} + +/** +* Send a message verdict including the payload +* @arg nlh netlink messsage header +* @arg msg queue msg +* @arg payload_data packet payload data +* @arg payload_len payload length +* @return 0 on OK or error code +*/ +int nfnl_queue_msg_send_verdict_payload(struct nl_sock *nlh, + const struct nfnl_queue_msg *msg, + const void *payload_data, unsigned payload_len) +{ + struct nl_msg *nlmsg; + int err; + struct iovec iov[3]; + struct nlattr nla; + + nlmsg = nfnl_queue_msg_build_verdict(msg); + if (nlmsg == NULL) + return -NLE_NOMEM; + + memset(iov, 0, sizeof(iov)); + + iov[0].iov_base = (void *) nlmsg_hdr(nlmsg); + iov[0].iov_len = nlmsg_hdr(nlmsg)->nlmsg_len; + + nla.nla_type = NFQA_PAYLOAD; + nla.nla_len = payload_len + sizeof(nla); + nlmsg_hdr(nlmsg)->nlmsg_len += nla.nla_len; + + iov[1].iov_base = (void *) &nla; + iov[1].iov_len = sizeof(nla); + + iov[2].iov_base = (void *) payload_data; + iov[2].iov_len = NLA_ALIGN(payload_len); + + nl_auto_complete(nlh, nlmsg); + err = nl_send_iovec(nlh, nlmsg, iov, 3); + + nlmsg_free(nlmsg); + if (err < 0) + return err; + return wait_for_ack(nlh); +} + +#define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type)) +static struct nl_cache_ops nfnl_queue_msg_ops = { + .co_name = "netfilter/queue_msg", + .co_hdrsize = NFNL_HDRLEN, + .co_msgtypes = { + { NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_NETFILTER, + .co_msg_parser = queue_msg_parser, + .co_obj_ops = &queue_msg_obj_ops, +}; + +static void __init nfnl_msg_queue_init(void) +{ + nl_cache_mngt_register(&nfnl_queue_msg_ops); +} + +static void __exit nfnl_queue_msg_exit(void) +{ + nl_cache_mngt_unregister(&nfnl_queue_msg_ops); +} + +/** @} */ diff --git a/lib/netfilter/queue_msg_obj.c b/lib/netfilter/queue_msg_obj.c new file mode 100644 index 0000000..97813e8 --- /dev/null +++ b/lib/netfilter/queue_msg_obj.c @@ -0,0 +1,492 @@ +/* + * lib/netfilter/queue_msg_obj.c Netfilter Queue Message Object + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + */ + +#include <netlink-local.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/netfilter.h> +#include <netlink/netfilter/queue_msg.h> +#include <linux/netfilter.h> + +/** @cond SKIP */ +#define QUEUE_MSG_ATTR_GROUP (1UL << 0) +#define QUEUE_MSG_ATTR_FAMILY (1UL << 1) +#define QUEUE_MSG_ATTR_PACKETID (1UL << 2) +#define QUEUE_MSG_ATTR_HWPROTO (1UL << 3) +#define QUEUE_MSG_ATTR_HOOK (1UL << 4) +#define QUEUE_MSG_ATTR_MARK (1UL << 5) +#define QUEUE_MSG_ATTR_TIMESTAMP (1UL << 6) +#define QUEUE_MSG_ATTR_INDEV (1UL << 7) +#define QUEUE_MSG_ATTR_OUTDEV (1UL << 8) +#define QUEUE_MSG_ATTR_PHYSINDEV (1UL << 9) +#define QUEUE_MSG_ATTR_PHYSOUTDEV (1UL << 10) +#define QUEUE_MSG_ATTR_HWADDR (1UL << 11) +#define QUEUE_MSG_ATTR_PAYLOAD (1UL << 12) +#define QUEUE_MSG_ATTR_VERDICT (1UL << 13) +/** @endcond */ + +static void nfnl_queue_msg_free_data(struct nl_object *c) +{ + struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) c; + + if (msg == NULL) + return; + + free(msg->queue_msg_payload); +} + +static int nfnl_queue_msg_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct nfnl_queue_msg *dst = (struct nfnl_queue_msg *) _dst; + struct nfnl_queue_msg *src = (struct nfnl_queue_msg *) _src; + int err; + + if (src->queue_msg_payload) { + err = nfnl_queue_msg_set_payload(dst, src->queue_msg_payload, + src->queue_msg_payload_len); + if (err < 0) + goto errout; + } + + return 0; +errout: + return err; +} + +static void nfnl_queue_msg_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) a; + struct nl_cache *link_cache; + char buf[64]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_new_line(p); + + if (msg->ce_mask & QUEUE_MSG_ATTR_GROUP) + nl_dump(p, "GROUP=%u ", msg->queue_msg_group); + + if (msg->ce_mask & QUEUE_MSG_ATTR_INDEV) { + if (link_cache) + nl_dump(p, "IN=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_indev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->queue_msg_indev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV) { + if (link_cache) + nl_dump(p, "PHYSIN=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_physindev, + buf, sizeof(buf))); + else + nl_dump(p, "IN=%d ", msg->queue_msg_physindev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV) { + if (link_cache) + nl_dump(p, "OUT=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_outdev, + buf, sizeof(buf))); + else + nl_dump(p, "OUT=%d ", msg->queue_msg_outdev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV) { + if (link_cache) + nl_dump(p, "PHYSOUT=%s ", + rtnl_link_i2name(link_cache, + msg->queue_msg_physoutdev, + buf, sizeof(buf))); + else + nl_dump(p, "PHYSOUT=%d ", msg->queue_msg_physoutdev); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_HWADDR) { + int i; + + nl_dump(p, "MAC"); + for (i = 0; i < msg->queue_msg_hwaddr_len; i++) + nl_dump(p, "%c%02x", i?':':'=', + msg->queue_msg_hwaddr[i]); + nl_dump(p, " "); + } + + if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY) + nl_dump(p, "FAMILY=%s ", + nl_af2str(msg->queue_msg_family, buf, sizeof(buf))); + + if (msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO) + nl_dump(p, "HWPROTO=%s ", + nl_ether_proto2str(ntohs(msg->queue_msg_hwproto), + buf, sizeof(buf))); + + if (msg->ce_mask & QUEUE_MSG_ATTR_HOOK) + nl_dump(p, "HOOK=%s ", + nfnl_inet_hook2str(msg->queue_msg_hook, + buf, sizeof(buf))); + + if (msg->ce_mask & QUEUE_MSG_ATTR_MARK) + nl_dump(p, "MARK=%d ", msg->queue_msg_mark); + + if (msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD) + nl_dump(p, "PAYLOADLEN=%d ", msg->queue_msg_payload_len); + + if (msg->ce_mask & QUEUE_MSG_ATTR_PACKETID) + nl_dump(p, "PACKETID=%u ", msg->queue_msg_packetid); + + if (msg->ce_mask & QUEUE_MSG_ATTR_VERDICT) + nl_dump(p, "VERDICT=%s ", + nfnl_verdict2str(msg->queue_msg_verdict, + buf, sizeof(buf))); + + nl_dump(p, "\n"); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_queue_msg *nfnl_queue_msg_alloc(void) +{ + return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops); +} + +void nfnl_queue_msg_get(struct nfnl_queue_msg *msg) +{ + nl_object_get((struct nl_object *) msg); +} + +void nfnl_queue_msg_put(struct nfnl_queue_msg *msg) +{ + nl_object_put((struct nl_object *) msg); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group) +{ + msg->queue_msg_group = group; + msg->ce_mask |= QUEUE_MSG_ATTR_GROUP; +} + +int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP); +} + +uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_group; +} + +/** +* Set the protocol family +* @arg msg NF queue message +* @arg family AF_XXX address family example: AF_INET, AF_UNIX, etc +*/ +void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family) +{ + msg->queue_msg_family = family; + msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY; +} + +int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY); +} + +uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg) +{ + if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY) + return msg->queue_msg_family; + else + return AF_UNSPEC; +} + +void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid) +{ + msg->queue_msg_packetid = packetid; + msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID; +} + +int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID); +} + +uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_packetid; +} + +void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto) +{ + msg->queue_msg_hwproto = hwproto; + msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO; +} + +int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO); +} + +uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_hwproto; +} + +void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook) +{ + msg->queue_msg_hook = hook; + msg->ce_mask |= QUEUE_MSG_ATTR_HOOK; +} + +int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK); +} + +uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_hook; +} + +void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark) +{ + msg->queue_msg_mark = mark; + msg->ce_mask |= QUEUE_MSG_ATTR_MARK; +} + +int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK); +} + +uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_mark; +} + +void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg, + struct timeval *tv) +{ + msg->queue_msg_timestamp.tv_sec = tv->tv_sec; + msg->queue_msg_timestamp.tv_usec = tv->tv_usec; + msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP; +} + +int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP); +} + +const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg) +{ + if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP)) + return NULL; + return &msg->queue_msg_timestamp; +} + +void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev) +{ + msg->queue_msg_indev = indev; + msg->ce_mask |= QUEUE_MSG_ATTR_INDEV; +} + +int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV); +} + +uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_indev; +} + +void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev) +{ + msg->queue_msg_outdev = outdev; + msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV; +} + +int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV); +} + +uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_outdev; +} + +void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg, + uint32_t physindev) +{ + msg->queue_msg_physindev = physindev; + msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV; +} + +int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV); +} + +uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_physindev; +} + +void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg, + uint32_t physoutdev) +{ + msg->queue_msg_physoutdev = physoutdev; + msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV; +} + +int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV); +} + +uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_physoutdev; +} + +void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr, + int len) +{ + if (len > sizeof(msg->queue_msg_hwaddr)) + len = sizeof(msg->queue_msg_hwaddr); + + msg->queue_msg_hwaddr_len = len; + memcpy(msg->queue_msg_hwaddr, hwaddr, len); + msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR; +} + +int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR); +} + +const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg, + int *len) +{ + if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) { + *len = 0; + return NULL; + } + + *len = msg->queue_msg_hwaddr_len; + return msg->queue_msg_hwaddr; +} + +int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload, + int len) +{ + free(msg->queue_msg_payload); + msg->queue_msg_payload = malloc(len); + if (!msg->queue_msg_payload) + return -NLE_NOMEM; + + memcpy(msg->queue_msg_payload, payload, len); + msg->queue_msg_payload_len = len; + msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD; + return 0; +} + +int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD); +} + +const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len) +{ + if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) { + *len = 0; + return NULL; + } + + *len = msg->queue_msg_payload_len; + return msg->queue_msg_payload; +} + +/** +* Return the number of items matching a filter in the cache +* @arg msg queue msg +* @arg verdict NF_DROP, NF_ACCEPT, NF_REPEAT, etc +*/ +void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg, + unsigned int verdict) +{ + msg->queue_msg_verdict = verdict; + msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT; +} + +int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg) +{ + return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT); +} + +unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg) +{ + return msg->queue_msg_verdict; +} + +static struct trans_tbl nfnl_queue_msg_attrs[] = { + __ADD(QUEUE_MSG_ATTR_GROUP, group) + __ADD(QUEUE_MSG_ATTR_FAMILY, family) + __ADD(QUEUE_MSG_ATTR_PACKETID, packetid) + __ADD(QUEUE_MSG_ATTR_HWPROTO, hwproto) + __ADD(QUEUE_MSG_ATTR_HOOK, hook) + __ADD(QUEUE_MSG_ATTR_MARK, mark) + __ADD(QUEUE_MSG_ATTR_TIMESTAMP, timestamp) + __ADD(QUEUE_MSG_ATTR_INDEV, indev) + __ADD(QUEUE_MSG_ATTR_OUTDEV, outdev) + __ADD(QUEUE_MSG_ATTR_PHYSINDEV, physindev) + __ADD(QUEUE_MSG_ATTR_PHYSOUTDEV, physoutdev) + __ADD(QUEUE_MSG_ATTR_HWADDR, hwaddr) + __ADD(QUEUE_MSG_ATTR_PAYLOAD, payload) + __ADD(QUEUE_MSG_ATTR_VERDICT, verdict) +}; + +static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs, + ARRAY_SIZE(nfnl_queue_msg_attrs)); +} + +/** @} */ + +struct nl_object_ops queue_msg_obj_ops = { + .oo_name = "netfilter/queuemsg", + .oo_size = sizeof(struct nfnl_queue_msg), + .oo_free_data = nfnl_queue_msg_free_data, + .oo_clone = nfnl_queue_msg_clone, + .oo_dump = { + [NL_DUMP_LINE] = nfnl_queue_msg_dump, + [NL_DUMP_DETAILS] = nfnl_queue_msg_dump, + [NL_DUMP_STATS] = nfnl_queue_msg_dump, + }, + .oo_attrs2str = nfnl_queue_msg_attrs2str, +}; + +/** @} */ diff --git a/lib/netfilter/queue_obj.c b/lib/netfilter/queue_obj.c new file mode 100644 index 0000000..ee03836 --- /dev/null +++ b/lib/netfilter/queue_obj.c @@ -0,0 +1,215 @@ +/* + * lib/netfilter/queue_obj.c Netfilter Queue + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + */ + +/** + * @ingroup nfnl + * @defgroup queue Queue + * @brief + * @{ + */ + +#include <netlink-local.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/queue.h> + +/** @cond SKIP */ +#define QUEUE_ATTR_GROUP (1UL << 0) +#define QUEUE_ATTR_MAXLEN (1UL << 1) +#define QUEUE_ATTR_COPY_MODE (1UL << 2) +#define QUEUE_ATTR_COPY_RANGE (1UL << 3) +/** @endcond */ + + +static void nfnl_queue_dump(struct nl_object *a, struct nl_dump_params *p) +{ + struct nfnl_queue *queue = (struct nfnl_queue *) a; + char buf[64]; + + nl_new_line(p); + + if (queue->ce_mask & QUEUE_ATTR_GROUP) + nl_dump(p, "group=%u ", queue->queue_group); + + if (queue->ce_mask & QUEUE_ATTR_MAXLEN) + nl_dump(p, "maxlen=%u ", queue->queue_maxlen); + + if (queue->ce_mask & QUEUE_ATTR_COPY_MODE) + nl_dump(p, "copy_mode=%s ", + nfnl_queue_copy_mode2str(queue->queue_copy_mode, + buf, sizeof(buf))); + + if (queue->ce_mask & QUEUE_ATTR_COPY_RANGE) + nl_dump(p, "copy_range=%u ", queue->queue_copy_range); + + nl_dump(p, "\n"); +} + +static struct trans_tbl copy_modes[] = { + __ADD(NFNL_QUEUE_COPY_NONE, none) + __ADD(NFNL_QUEUE_COPY_META, meta) + __ADD(NFNL_QUEUE_COPY_PACKET, packet) +}; + +char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf, + size_t len) +{ + return __type2str(copy_mode, buf, len, copy_modes, + ARRAY_SIZE(copy_modes)); +} + +enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *name) +{ + return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes)); +} + +/** + * @name Allocation/Freeing + * @{ + */ + +struct nfnl_queue *nfnl_queue_alloc(void) +{ + return (struct nfnl_queue *) nl_object_alloc(&queue_obj_ops); +} + +void nfnl_queue_get(struct nfnl_queue *queue) +{ + nl_object_get((struct nl_object *) queue); +} + +void nfnl_queue_put(struct nfnl_queue *queue) +{ + nl_object_put((struct nl_object *) queue); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void nfnl_queue_set_group(struct nfnl_queue *queue, uint16_t group) +{ + queue->queue_group = group; + queue->ce_mask |= QUEUE_ATTR_GROUP; +} + +int nfnl_queue_test_group(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_GROUP); +} + +uint16_t nfnl_queue_get_group(const struct nfnl_queue *queue) +{ + return queue->queue_group; +} + +void nfnl_queue_set_maxlen(struct nfnl_queue *queue, uint32_t maxlen) +{ + queue->queue_maxlen = maxlen; + queue->ce_mask |= QUEUE_ATTR_MAXLEN; +} + +int nfnl_queue_test_maxlen(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_MAXLEN); +} + +uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *queue) +{ + return queue->queue_maxlen; +} + +void nfnl_queue_set_copy_mode(struct nfnl_queue *queue, enum nfnl_queue_copy_mode mode) +{ + queue->queue_copy_mode = mode; + queue->ce_mask |= QUEUE_ATTR_COPY_MODE; +} + +int nfnl_queue_test_copy_mode(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_COPY_MODE); +} + +enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *queue) +{ + return queue->queue_copy_mode; +} + +void nfnl_queue_set_copy_range(struct nfnl_queue *queue, uint32_t copy_range) +{ + queue->queue_copy_range = copy_range; + queue->ce_mask |= QUEUE_ATTR_COPY_RANGE; +} + +int nfnl_queue_test_copy_range(const struct nfnl_queue *queue) +{ + return !!(queue->ce_mask & QUEUE_ATTR_COPY_RANGE); +} + +uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *queue) +{ + return queue->queue_copy_range; +} + +static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct nfnl_queue *a = (struct nfnl_queue *) _a; + struct nfnl_queue *b = (struct nfnl_queue *) _b; + int diff = 0; + +#define NFNL_QUEUE_DIFF(ATTR, EXPR) \ + ATTR_DIFF(attrs, QUEUE_ATTR_##ATTR, a, b, EXPR) +#define NFNL_QUEUE_DIFF_VAL(ATTR, FIELD) \ + NFNL_QUEUE_DIFF(ATTR, a->FIELD != b->FIELD) + + diff |= NFNL_QUEUE_DIFF_VAL(GROUP, queue_group); + diff |= NFNL_QUEUE_DIFF_VAL(MAXLEN, queue_maxlen); + diff |= NFNL_QUEUE_DIFF_VAL(COPY_MODE, queue_copy_mode); + diff |= NFNL_QUEUE_DIFF_VAL(COPY_RANGE, queue_copy_range); + +#undef NFNL_QUEUE_DIFF +#undef NFNL_QUEUE_DIFF_VAL + + return diff; +} + +static struct trans_tbl nfnl_queue_attrs[] = { + __ADD(QUEUE_ATTR_GROUP, group) + __ADD(QUEUE_ATTR_MAXLEN, maxlen) + __ADD(QUEUE_ATTR_COPY_MODE, copy_mode) + __ADD(QUEUE_ATTR_COPY_RANGE, copy_range) +}; + +static char *nfnl_queue_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, nfnl_queue_attrs, + ARRAY_SIZE(nfnl_queue_attrs)); +} + +/** @} */ + +struct nl_object_ops queue_obj_ops = { + .oo_name = "netfilter/queue", + .oo_size = sizeof(struct nfnl_queue), + .oo_dump = { + [NL_DUMP_LINE] = nfnl_queue_dump, + [NL_DUMP_DETAILS] = nfnl_queue_dump, + [NL_DUMP_STATS] = nfnl_queue_dump, + }, + .oo_compare = nfnl_queue_compare, + .oo_attrs2str = nfnl_queue_attrs2str, + .oo_id_attrs = QUEUE_ATTR_GROUP, +}; + +/** @} */ @@ -6,102 +6,17 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @defgroup nl Core Netlink API - * @brief - * - * @par Receiving Semantics - * @code - * nl_recvmsgs_default(socket) - * | - * | cb = nl_socket_get_cb(socket) - * v - * nl_recvmsgs(socket, cb) - * | [Application provides nl_recvmsgs() replacement] - * |- - - - - - - - - - - - - - - v - * | cb->cb_recvmsgs_ow() - * | - * | [Application provides nl_recv() replacement] - * +-------------->|- - - - - - - - - - - - - - - v - * | nl_recv() cb->cb_recv_ow() - * | +----------->|<- - - - - - - - - - - - - - -+ - * | | v - * | | Parse Message - * | | |- - - - - - - - - - - - - - - v - * | | | NL_CB_MSG_IN() - * | | |<- - - - - - - - - - - - - - -+ - * | | | - * | | |- - - - - - - - - - - - - - - v - * | | Sequence Check NL_CB_SEQ_CHECK() - * | | |<- - - - - - - - - - - - - - -+ - * | | | - * | | |- - - - - - - - - - - - - - - v [ NLM_F_ACK is set ] - * | | | NL_CB_SEND_ACK() - * | | |<- - - - - - - - - - - - - - -+ - * | | | - * | | +-----+------+--------------+----------------+--------------+ - * | | v v v v v - * | | Valid Message ACK NOOP Message End of Multipart Error Message - * | | | | | | | - * | | v v v v v - * | |NL_CB_VALID() NL_CB_ACK() NL_CB_SKIPPED() NL_CB_FINISH() cb->cb_err() - * | | | | | | | - * | | +------------+--------------+----------------+ v - * | | | (FAILURE) - * | | | [Callback returned NL_SKIP] - * | | [More messages to be parsed] |<----------- - * | +----------------------------------| - * | | - * | [Multipart message] | - * +-------------------------------------| [Callback returned NL_STOP] - * |<----------- - * v - * (SUCCESS) - * - * At any time: - * Message Format Error - * |- - - - - - - - - - - - v - * v NL_CB_INVALID() - * (FAILURE) - * - * Message Overrun (Kernel Lost Data) - * |- - - - - - - - - - - - v - * v NL_CB_OVERRUN() - * (FAILURE) - * - * Callback returned negative error code - * (FAILURE) - * @endcode - * - * @par Sending Semantics - * @code - * nl_send_auto_complete() - * | - * | Automatically fill in PID and/or sequence number - * | - * | [Application provides nl_send() replacement] - * |- - - - - - - - - - - - - - - - - - - - v - * v cb->cb_send_ow() - * nl_send() - * | Add destination address and credentials - * v - * nl_sendmsg() - * | Set source address - * | - * |- - - - - - - - - - - - - - - - - - - - v - * | NL_CB_MSG_OUT() - * |<- - - - - - - - - - - - - - - - - - - -+ - * v - * sendmsg() - * @endcode + * @defgroup core Core * + * @details * @par 1) Connecting the socket * @code * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example. - * nl_connect(handle, NETLINK_ROUTE); + * nl_connect(sk, NETLINK_ROUTE); * @endcode * * @par 2) Sending data @@ -110,29 +25,29 @@ * // a piece of data to the other netlink peer. This method is not * // recommended. * const char buf[] = { 0x01, 0x02, 0x03, 0x04 }; - * nl_sendto(handle, buf, sizeof(buf)); + * nl_sendto(sk, buf, sizeof(buf)); * * // A more comfortable interface is nl_send() taking a pointer to * // a netlink message. * struct nl_msg *msg = my_msg_builder(); - * nl_send(handle, nlmsg_hdr(msg)); + * nl_send(sk, nlmsg_hdr(msg)); * * // nl_sendmsg() provides additional control over the sendmsg() message * // header in order to allow more specific addressing of multiple peers etc. * struct msghdr hdr = { ... }; - * nl_sendmsg(handle, nlmsg_hdr(msg), &hdr); + * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr); * * // You're probably too lazy to fill out the netlink pid, sequence number * // and message flags all the time. nl_send_auto_complete() automatically * // extends your message header as needed with an appropriate sequence - * // number, the netlink pid stored in the netlink handle and the message - * // flags NLM_F_REQUEST and NLM_F_ACK - * nl_send_auto_complete(handle, nlmsg_hdr(msg)); + * // number, the netlink pid stored in the netlink socket and the message + * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket) + * nl_send_auto_complete(sk, nlmsg_hdr(msg)); * * // Simple protocols don't require the complex message construction interface * // and may favour nl_send_simple() to easly send a bunch of payload * // encapsulated in a netlink message header. - * nl_send_simple(handle, MY_MSG_TYPE, 0, buf, sizeof(buf)); + * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf)); * @endcode * * @par 3) Receiving data @@ -141,26 +56,26 @@ * // content and gives back the pointer to you. * struct sockaddr_nl peer; * unsigned char *msg; - * nl_recv(handle, &peer, &msg); + * nl_recv(sk, &peer, &msg); * * // nl_recvmsgs() receives a bunch of messages until the callback system * // orders it to state, usually after receving a compolete multi part * // message series. - * nl_recvmsgs(handle, my_callback_configuration); + * nl_recvmsgs(sk, my_callback_configuration); * * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback - * // configuration stored in the handle. - * nl_recvmsgs_default(handle); + * // configuration stored in the socket. + * nl_recvmsgs_default(sk); * * // In case you want to wait for the ACK to be recieved that you requested * // with your latest message, you can call nl_wait_for_ack() - * nl_wait_for_ack(handle); + * nl_wait_for_ack(sk); * @endcode * * @par 4) Closing * @code * // Close the socket first to release kernel memory - * nl_close(handle); + * nl_close(sk); * @endcode * * @{ @@ -180,7 +95,7 @@ /** * Create and connect netlink socket. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg protocol Netlink protocol to use. * * Creates a netlink socket using the specified protocol, binds the socket @@ -188,70 +103,70 @@ * * @return 0 on success or a negative error code. */ -int nl_connect(struct nl_handle *handle, int protocol) +int nl_connect(struct nl_sock *sk, int protocol) { int err; socklen_t addrlen; - handle->h_fd = socket(AF_NETLINK, SOCK_RAW, protocol); - if (handle->h_fd < 0) { - err = nl_error(1, "socket(AF_NETLINK, ...) failed"); + sk->s_fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (sk->s_fd < 0) { + err = -nl_syserr2nlerr(errno); goto errout; } - if (!(handle->h_flags & NL_SOCK_BUFSIZE_SET)) { - err = nl_set_buffer_size(handle, 0, 0); + if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) { + err = nl_socket_set_buffer_size(sk, 0, 0); if (err < 0) goto errout; } - err = bind(handle->h_fd, (struct sockaddr*) &handle->h_local, - sizeof(handle->h_local)); + err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local, + sizeof(sk->s_local)); if (err < 0) { - err = nl_error(1, "bind() failed"); + err = -nl_syserr2nlerr(errno); goto errout; } - addrlen = sizeof(handle->h_local); - err = getsockname(handle->h_fd, (struct sockaddr *) &handle->h_local, + addrlen = sizeof(sk->s_local); + err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local, &addrlen); if (err < 0) { - err = nl_error(1, "getsockname failed"); + err = -nl_syserr2nlerr(errno); goto errout; } - if (addrlen != sizeof(handle->h_local)) { - err = nl_error(EADDRNOTAVAIL, "Invalid address length"); + if (addrlen != sizeof(sk->s_local)) { + err = -NLE_NOADDR; goto errout; } - if (handle->h_local.nl_family != AF_NETLINK) { - err = nl_error(EPFNOSUPPORT, "Address format not supported"); + if (sk->s_local.nl_family != AF_NETLINK) { + err = -NLE_AF_NOSUPPORT; goto errout; } - handle->h_proto = protocol; + sk->s_proto = protocol; return 0; errout: - close(handle->h_fd); - handle->h_fd = -1; + close(sk->s_fd); + sk->s_fd = -1; return err; } /** * Close/Disconnect netlink socket. - * @arg handle Netlink handle + * @arg sk Netlink socket. */ -void nl_close(struct nl_handle *handle) +void nl_close(struct nl_sock *sk) { - if (handle->h_fd >= 0) { - close(handle->h_fd); - handle->h_fd = -1; + if (sk->s_fd >= 0) { + close(sk->s_fd); + sk->s_fd = -1; } - handle->h_proto = 0; + sk->s_proto = 0; } /** @} */ @@ -263,77 +178,73 @@ void nl_close(struct nl_handle *handle) /** * Send raw data over netlink socket. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg buf Data buffer. * @arg size Size of data buffer. * @return Number of characters written on success or a negative error code. */ -int nl_sendto(struct nl_handle *handle, void *buf, size_t size) +int nl_sendto(struct nl_sock *sk, void *buf, size_t size) { int ret; - ret = sendto(handle->h_fd, buf, size, 0, (struct sockaddr *) - &handle->h_peer, sizeof(handle->h_peer)); + ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *) + &sk->s_peer, sizeof(sk->s_peer)); if (ret < 0) - return nl_errno(errno); + return -nl_syserr2nlerr(errno); return ret; } /** * Send netlink message with control over sendmsg() message header. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * @arg hdr Sendmsg() message header. * @return Number of characters sent on sucess or a negative error code. */ -int nl_sendmsg(struct nl_handle *handle, struct nl_msg *msg, struct msghdr *hdr) +int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) { struct nl_cb *cb; int ret; - struct iovec iov = { - .iov_base = (void *) nlmsg_hdr(msg), - .iov_len = nlmsg_hdr(msg)->nlmsg_len, - }; - - hdr->msg_iov = &iov; - hdr->msg_iovlen = 1; - - nlmsg_set_src(msg, &handle->h_local); + nlmsg_set_src(msg, &sk->s_local); - cb = handle->h_cb; + cb = sk->s_cb; if (cb->cb_set[NL_CB_MSG_OUT]) if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK) return 0; - ret = sendmsg(handle->h_fd, hdr, 0); + ret = sendmsg(sk->s_fd, hdr, 0); if (ret < 0) - return nl_errno(errno); + return -nl_syserr2nlerr(errno); + NL_DBG(4, "sent %d bytes\n", ret); return ret; } /** * Send netlink message. - * @arg handle Netlink handle + * @arg sk Netlink socket. * @arg msg Netlink message to be sent. + * @arg iov iovec to be sent. + * @arg iovlen number of struct iovec to be sent. * @see nl_sendmsg() * @return Number of characters sent on success or a negative error code. */ -int nl_send(struct nl_handle *handle, struct nl_msg *msg) +int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) { struct sockaddr_nl *dst; struct ucred *creds; - struct msghdr hdr = { - .msg_name = (void *) &handle->h_peer, + .msg_name = (void *) &sk->s_peer, .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = iov, + .msg_iovlen = iovlen, }; /* Overwrite destination if specified in the message itself, defaults - * to the peer address of the handle. + * to the peer address of the socket. */ dst = nlmsg_get_dst(msg); if (dst->nl_family == AF_NETLINK) @@ -355,12 +266,51 @@ int nl_send(struct nl_handle *handle, struct nl_msg *msg) memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred)); } - return nl_sendmsg(handle, msg, &hdr); + return nl_sendmsg(sk, msg, &hdr); +} + + + +/** +* Send netlink message. +* @arg sk Netlink socket. +* @arg msg Netlink message to be sent. +* @see nl_sendmsg() +* @return Number of characters sent on success or a negative error code. +*/ +int nl_send(struct nl_sock *sk, struct nl_msg *msg) +{ + struct iovec iov = { + .iov_base = (void *) nlmsg_hdr(msg), + .iov_len = nlmsg_hdr(msg)->nlmsg_len, + }; + + return nl_send_iovec(sk, msg, &iov, 1); +} + +void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg) +{ + struct nlmsghdr *nlh; + + nlh = nlmsg_hdr(msg); + if (nlh->nlmsg_pid == 0) + nlh->nlmsg_pid = sk->s_local.nl_pid; + + if (nlh->nlmsg_seq == 0) + nlh->nlmsg_seq = sk->s_seq_next++; + + if (msg->nm_protocol == -1) + msg->nm_protocol = sk->s_proto; + + nlh->nlmsg_flags |= NLM_F_REQUEST; + + if (!(sk->s_flags & NL_NO_AUTO_ACK)) + nlh->nlmsg_flags |= NLM_F_ACK; } /** * Send netlink message and check & extend header values as needed. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg msg Netlink message to be sent. * * Checks the netlink message \c nlh for completness and extends it @@ -370,32 +320,21 @@ int nl_send(struct nl_handle *handle, struct nl_msg *msg) * @see nl_send() * @return Number of characters sent or a negative error code. */ -int nl_send_auto_complete(struct nl_handle *handle, struct nl_msg *msg) +int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg) { - struct nlmsghdr *nlh; - struct nl_cb *cb = handle->h_cb; - - nlh = nlmsg_hdr(msg); - if (nlh->nlmsg_pid == 0) - nlh->nlmsg_pid = handle->h_local.nl_pid; - - if (nlh->nlmsg_seq == 0) - nlh->nlmsg_seq = handle->h_seq_next++; + struct nl_cb *cb = sk->s_cb; - if (msg->nm_protocol == -1) - msg->nm_protocol = handle->h_proto; - - nlh->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK); + nl_auto_complete(sk, msg); if (cb->cb_send_ow) - return cb->cb_send_ow(handle, msg); + return cb->cb_send_ow(sk, msg); else - return nl_send(handle, msg); + return nl_send(sk, msg); } /** * Send simple netlink message using nl_send_auto_complete() - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg type Netlink message type. * @arg flags Netlink message flags. * @arg buf Data buffer. @@ -407,7 +346,7 @@ int nl_send_auto_complete(struct nl_handle *handle, struct nl_msg *msg) * @see nl_send_auto_complete() * @return Number of characters sent on success or a negative error code. */ -int nl_send_simple(struct nl_handle *handle, int type, int flags, void *buf, +int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size) { int err; @@ -415,7 +354,7 @@ int nl_send_simple(struct nl_handle *handle, int type, int flags, void *buf, msg = nlmsg_alloc_simple(type, flags); if (!msg) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (buf && size) { err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO); @@ -424,7 +363,7 @@ int nl_send_simple(struct nl_handle *handle, int type, int flags, void *buf, } - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); errout: nlmsg_free(msg); @@ -440,7 +379,7 @@ errout: /** * Receive data from netlink socket - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg nla Destination pointer for peer's netlink address. * @arg buf Destination pointer for message content. * @arg creds Destination pointer for credentials. @@ -457,7 +396,7 @@ errout: * * @return Number of octets read, 0 on EOF or a negative error code. */ -int nl_recv(struct nl_handle *handle, struct sockaddr_nl *nla, +int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred **creds) { int n; @@ -475,22 +414,22 @@ int nl_recv(struct nl_handle *handle, struct sockaddr_nl *nla, }; struct cmsghdr *cmsg; - if (handle->h_flags & NL_MSG_PEEK) + if (sk->s_flags & NL_MSG_PEEK) flags |= MSG_PEEK; if (page_size == 0) page_size = getpagesize(); iov.iov_len = page_size; - iov.iov_base = *buf = calloc(1, iov.iov_len); + iov.iov_base = *buf = malloc(iov.iov_len); - if (handle->h_flags & NL_SOCK_PASSCRED) { + if (sk->s_flags & NL_SOCK_PASSCRED) { msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); msg.msg_control = calloc(1, msg.msg_controllen); } retry: - n = recvmsg(handle->h_fd, &msg, flags); + n = recvmsg(sk->s_fd, &msg, flags); if (!n) goto abort; else if (n < 0) { @@ -503,7 +442,7 @@ retry: } else { free(msg.msg_control); free(*buf); - return nl_error(errno, "recvmsg failed"); + return -nl_syserr2nlerr(errno); } } @@ -527,7 +466,7 @@ retry: if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { free(msg.msg_control); free(*buf); - return nl_error(EADDRNOTAVAIL, "socket address size mismatch"); + return -NLE_NOADDR; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { @@ -564,7 +503,7 @@ do { \ } \ } while (0) -static int recvmsgs(struct nl_handle *handle, struct nl_cb *cb) +static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb) { int n, err = 0, multipart = 0; unsigned char *buf = NULL; @@ -574,30 +513,29 @@ static int recvmsgs(struct nl_handle *handle, struct nl_cb *cb) struct ucred *creds = NULL; continue_reading: - NL_DBG(3, "Attempting to read from %p\n", handle); + NL_DBG(3, "Attempting to read from %p\n", sk); if (cb->cb_recv_ow) - n = cb->cb_recv_ow(handle, &nla, &buf, &creds); + n = cb->cb_recv_ow(sk, &nla, &buf, &creds); else - n = nl_recv(handle, &nla, &buf, &creds); + n = nl_recv(sk, &nla, &buf, &creds); if (n <= 0) return n; - NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", handle, n); + NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n); hdr = (struct nlmsghdr *) buf; while (nlmsg_ok(hdr, n)) { - NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", - handle); + NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk); nlmsg_free(msg); msg = nlmsg_convert(hdr); if (!msg) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto out; } - nlmsg_set_proto(msg, handle->h_proto); + nlmsg_set_proto(msg, sk->s_proto); nlmsg_set_src(msg, &nla); if (creds) nlmsg_set_creds(msg, creds); @@ -612,12 +550,11 @@ continue_reading: * enforcing strict ordering */ if (cb->cb_set[NL_CB_SEQ_CHECK]) NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg); - else if (hdr->nlmsg_seq != handle->h_seq_expect) { + else if (hdr->nlmsg_seq != sk->s_seq_expect) { if (cb->cb_set[NL_CB_INVALID]) NL_CB_CALL(cb, NL_CB_INVALID, msg); else { - err = nl_error(EINVAL, - "Sequence number mismatch"); + err = -NLE_SEQ_MISMATCH; goto out; } } @@ -628,10 +565,10 @@ continue_reading: hdr->nlmsg_type == NLMSG_OVERRUN) { /* We can't check for !NLM_F_MULTI since some netlink * users in the kernel are broken. */ - handle->h_seq_expect++; + sk->s_seq_expect++; NL_DBG(3, "recvmsgs(%p): Increased expected " \ "sequence number to %d\n", - handle, handle->h_seq_expect); + sk, sk->s_seq_expect); } if (hdr->nlmsg_flags & NLM_F_MULTI) @@ -674,7 +611,7 @@ continue_reading: if (cb->cb_set[NL_CB_OVERRUN]) NL_CB_CALL(cb, NL_CB_OVERRUN, msg); else { - err = nl_error(EOVERFLOW, "Overrun"); + err = -NLE_MSG_OVERFLOW; goto out; } } @@ -691,8 +628,7 @@ continue_reading: if (cb->cb_set[NL_CB_INVALID]) NL_CB_CALL(cb, NL_CB_INVALID, msg); else { - err = nl_error(EINVAL, - "Truncated error message"); + err = -NLE_MSG_TRUNC; goto out; } } else if (e->error) { @@ -705,13 +641,11 @@ continue_reading: else if (err == NL_SKIP) goto skip; else if (err == NL_STOP) { - err = nl_error(-e->error, - "Netlink Error"); + err = -nl_syserr2nlerr(e->error); goto out; } } else { - err = nl_error(-e->error, - "Netlink Error"); + err = -nl_syserr2nlerr(e->error); goto out; } } else if (cb->cb_set[NL_CB_ACK]) @@ -751,7 +685,7 @@ out: /** * Receive a set of messages from a netlink socket. - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg cb set of callbacks to control behaviour. * * Repeatedly calls nl_recv() or the respective replacement if provided @@ -764,23 +698,23 @@ out: * * @return 0 on success or a negative error code from nl_recv(). */ -int nl_recvmsgs(struct nl_handle *handle, struct nl_cb *cb) +int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb) { if (cb->cb_recvmsgs_ow) - return cb->cb_recvmsgs_ow(handle, cb); + return cb->cb_recvmsgs_ow(sk, cb); else - return recvmsgs(handle, cb); + return recvmsgs(sk, cb); } /** - * Receive a set of message from a netlink socket using handlers in nl_handle. - * @arg handle netlink handle + * Receive a set of message from a netlink socket using handlers in nl_sock. + * @arg sk Netlink socket. * - * Calls nl_recvmsgs() with the handlers configured in the netlink handle. + * Calls nl_recvmsgs() with the handlers configured in the netlink socket. */ -int nl_recvmsgs_default(struct nl_handle *handle) +int nl_recvmsgs_default(struct nl_sock *sk) { - return nl_recvmsgs(handle, handle->h_cb); + return nl_recvmsgs(sk, sk->s_cb); } @@ -791,23 +725,23 @@ static int ack_wait_handler(struct nl_msg *msg, void *arg) /** * Wait for ACK. - * @arg handle netlink handle + * @arg sk Netlink socket. * @pre The netlink socket must be in blocking state. * * Waits until an ACK is received for the latest not yet acknowledged * netlink message. */ -int nl_wait_for_ack(struct nl_handle *handle) +int nl_wait_for_ack(struct nl_sock *sk) { int err; struct nl_cb *cb; - cb = nl_cb_clone(handle->h_cb); + cb = nl_cb_clone(sk->s_cb); if (cb == NULL) - return nl_get_errno(); + return -NLE_NOMEM; nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL); - err = nl_recvmsgs(handle, cb); + err = nl_recvmsgs(sk, cb); nl_cb_put(cb); return err; diff --git a/lib/object.c b/lib/object.c index 74f6e2d..d881ac9 100644 --- a/lib/object.c +++ b/lib/object.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -47,10 +47,8 @@ struct nl_object *nl_object_alloc(struct nl_object_ops *ops) BUG(); new = calloc(1, ops->oo_size); - if (!new) { - nl_errno(ENOMEM); + if (!new) return NULL; - } new->ce_refcnt = 1; nl_init_list_head(&new->ce_list); @@ -69,17 +67,18 @@ struct nl_object *nl_object_alloc(struct nl_object_ops *ops) * @arg kind name of object type * @return The new object or nULL */ -struct nl_object *nl_object_alloc_name(const char *kind) +int nl_object_alloc_name(const char *kind, struct nl_object **result) { struct nl_cache_ops *ops; ops = nl_cache_ops_lookup(kind); - if (!ops) { - nl_error(ENOENT, "Unable to lookup cache kind \"%s\"", kind); - return NULL; - } + if (!ops) + return -NLE_OPNOTSUPP; - return nl_object_alloc(ops->co_obj_ops); + if (!(*result = nl_object_alloc(ops->co_obj_ops))) + return -NLE_NOMEM; + + return 0; } struct nl_derived_object { @@ -109,6 +108,7 @@ struct nl_object *nl_object_clone(struct nl_object *obj) new->ce_ops = obj->ce_ops; new->ce_msgtype = obj->ce_msgtype; + new->ce_mask = obj->ce_mask; if (size) memcpy((void *)new + doff, (void *)obj + doff, size); @@ -265,6 +265,8 @@ int nl_object_identical(struct nl_object *a, struct nl_object *b) return 0; req_attrs = ops->oo_id_attrs; + if (req_attrs == ~0) + req_attrs = a->ce_mask & b->ce_mask; /* Both objects must provide all required attributes to uniquely * identify an object */ @@ -318,7 +320,7 @@ int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter) return 0; return !(ops->oo_compare(obj, filter, filter->ce_mask, - LOOSE_FLAG_COMPARISON)); + LOOSE_COMPARISON)); } /** @@ -376,11 +378,6 @@ struct nl_cache *nl_object_get_cache(struct nl_object *obj) return obj->ce_cache; } -inline void *nl_object_priv(struct nl_object *obj) -{ - return obj; -} - /** @} */ /** @} */ diff --git a/lib/route/.gitignore b/lib/route/.gitignore new file mode 100644 index 0000000..debf3b7 --- /dev/null +++ b/lib/route/.gitignore @@ -0,0 +1,4 @@ +pktloc_grammar.h +pktloc_grammar.c +pktloc_syntax.h +pktloc_syntax.c diff --git a/lib/route/addr.c b/lib/route/addr.c index b8ec56c..2e72f6e 100644 --- a/lib/route/addr.c +++ b/lib/route/addr.c @@ -6,8 +6,8 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - * Baruch Even <baruch@ev-en.org>, + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>, * Mediatrix Telecom, inc. <ericb@mediatrix.com> */ @@ -48,17 +48,16 @@ * // cannot be set for IPv6 addresses. * rtnl_addr_set_scope(addr, rtnl_str2scope("site")); * - * // Broadcast and anycast address may be specified using the relevant + * // Broadcast address may be specified using the relevant * // functions, the address family will be verified if one of the other * // addresses has been set already. Currently only works for IPv4. * rtnl_addr_set_broadcast(addr, broadcast_addr); - * rtnl_addr_set_anycast(addr, anycast_addr); * * // Build the netlink message and send it to the kernel, the operation will * // block until the operation has been completed. Alternatively the required * // netlink message can be built using rtnl_addr_build_add_request() to be * // sent out using nl_send_auto_complete(). - * rtnl_addr_add(handle, addr, 0); + * rtnl_addr_add(sk, addr, 0); * * // Free the memory * rtnl_addr_put(addr); @@ -99,7 +98,7 @@ * // block until the operation has been completed. Alternatively the required * // netlink message can be built using rtnl_addr_build_delete_request() * // to be sent out using nl_send_auto_complete(). - * rtnl_addr_delete(handle, addr, 0); + * rtnl_addr_delete(sk, addr, 0); * * // Free the memory * rtnl_addr_put(addr); @@ -126,13 +125,20 @@ #define ADDR_ATTR_PEER 0x0080 #define ADDR_ATTR_LOCAL 0x0100 #define ADDR_ATTR_BROADCAST 0x0200 -#define ADDR_ATTR_ANYCAST 0x0400 -#define ADDR_ATTR_MULTICAST 0x0800 +#define ADDR_ATTR_MULTICAST 0x0400 +#define ADDR_ATTR_ANYCAST 0x0800 static struct nl_cache_ops rtnl_addr_ops; static struct nl_object_ops addr_obj_ops; /** @endcond */ +static void addr_constructor(struct nl_object *obj) +{ + struct rtnl_addr *addr = nl_object_priv(obj); + + addr->a_scope = RT_SCOPE_NOWHERE; +} + static void addr_free_data(struct nl_object *obj) { struct rtnl_addr *addr = nl_object_priv(obj); @@ -143,8 +149,8 @@ static void addr_free_data(struct nl_object *obj) nl_addr_put(addr->a_peer); nl_addr_put(addr->a_local); nl_addr_put(addr->a_bcast); - nl_addr_put(addr->a_anycast); nl_addr_put(addr->a_multicast); + nl_addr_put(addr->a_anycast); } static int addr_clone(struct nl_object *_dst, struct nl_object *_src) @@ -154,27 +160,25 @@ static int addr_clone(struct nl_object *_dst, struct nl_object *_src) if (src->a_peer) if (!(dst->a_peer = nl_addr_clone(src->a_peer))) - goto errout; + return -NLE_NOMEM; if (src->a_local) if (!(dst->a_local = nl_addr_clone(src->a_local))) - goto errout; + return -NLE_NOMEM; if (src->a_bcast) if (!(dst->a_bcast = nl_addr_clone(src->a_bcast))) - goto errout; - - if (src->a_anycast) - if (!(dst->a_anycast = nl_addr_clone(src->a_anycast))) - goto errout; + return -NLE_NOMEM; if (src->a_multicast) if (!(dst->a_multicast = nl_addr_clone(src->a_multicast))) - goto errout; + return -NLE_NOMEM; + + if (src->a_anycast) + if (!(dst->a_anycast = nl_addr_clone(src->a_anycast))) + return -NLE_NOMEM; return 0; -errout: - return nl_get_errno(); } static struct nla_policy addr_policy[IFA_MAX+1] = { @@ -189,21 +193,20 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct rtnl_addr *addr; struct ifaddrmsg *ifa; struct nlattr *tb[IFA_MAX+1]; - int err = -ENOMEM, peer_prefix = 0; + int err, peer_prefix = 0, family; addr = rtnl_addr_alloc(); - if (!addr) { - err = nl_errno(ENOMEM); - goto errout; - } + if (!addr) + return -NLE_NOMEM; + addr->ce_msgtype = nlh->nlmsg_type; err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy); if (err < 0) - goto errout_free; + goto errout; ifa = nlmsg_data(nlh); - addr->a_family = ifa->ifa_family; + addr->a_family = family = ifa->ifa_family; addr->a_prefixlen = ifa->ifa_prefixlen; addr->a_flags = ifa->ifa_flags; addr->a_scope = ifa->ifa_scope; @@ -229,18 +232,18 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } if (tb[IFA_LOCAL]) { - addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family); + addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family); if (!addr->a_local) - goto errout_free; + goto errout_nomem; addr->ce_mask |= ADDR_ATTR_LOCAL; } if (tb[IFA_ADDRESS]) { struct nl_addr *a; - a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family); + a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family); if (!a) - goto errout_free; + goto errout_nomem; /* IPv6 sends the local address as IFA_ADDRESS with * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS @@ -260,48 +263,48 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, addr->a_prefixlen); if (tb[IFA_BROADCAST]) { - addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family); + addr->a_bcast = nl_addr_alloc_attr(tb[IFA_BROADCAST], family); if (!addr->a_bcast) - goto errout_free; + goto errout_nomem; addr->ce_mask |= ADDR_ATTR_BROADCAST; } - if (tb[IFA_ANYCAST]) { - addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family); - if (!addr->a_anycast) - goto errout_free; - - addr->ce_mask |= ADDR_ATTR_ANYCAST; - } - if (tb[IFA_MULTICAST]) { - addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST], - addr->a_family); + addr->a_multicast = nl_addr_alloc_attr(tb[IFA_MULTICAST], + family); if (!addr->a_multicast) - goto errout_free; + goto errout_nomem; addr->ce_mask |= ADDR_ATTR_MULTICAST; } - err = pp->pp_cb((struct nl_object *) addr, pp); - if (err < 0) - goto errout_free; + if (tb[IFA_ANYCAST]) { + addr->a_anycast = nl_addr_alloc_attr(tb[IFA_ANYCAST], + family); + if (!addr->a_anycast) + goto errout_nomem; - err = P_ACCEPT; + addr->ce_mask |= ADDR_ATTR_ANYCAST; + } -errout_free: - rtnl_addr_put(addr); + err = pp->pp_cb((struct nl_object *) addr, pp); errout: + rtnl_addr_put(addr); + return err; + +errout_nomem: + err = -NLE_NOMEM; + goto errout; } -static int addr_request_update(struct nl_cache *cache, struct nl_handle *handle) +static int addr_request_update(struct nl_cache *cache, struct nl_sock *sk) { - return nl_rtgen_request(handle, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP); + return nl_rtgen_request(sk, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP); } -static int addr_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void addr_dump_line(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct nl_cache *link_cache; @@ -310,259 +313,166 @@ static int addr_dump_brief(struct nl_object *obj, struct nl_dump_params *p) link_cache = nl_cache_mngt_require("route/link"); if (addr->ce_mask & ADDR_ATTR_LOCAL) - dp_dump(p, "%s", + nl_dump_line(p, "%s", nl_addr2str(addr->a_local, buf, sizeof(buf))); else - dp_dump(p, "none"); + nl_dump_line(p, "none"); if (addr->ce_mask & ADDR_ATTR_PEER) - dp_dump(p, " peer %s", + nl_dump(p, " peer %s", nl_addr2str(addr->a_peer, buf, sizeof(buf))); - dp_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf))); + nl_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf))); if (link_cache) - dp_dump(p, "dev %s ", + nl_dump(p, "dev %s ", rtnl_link_i2name(link_cache, addr->a_ifindex, buf, sizeof(buf))); else - dp_dump(p, "dev %d ", addr->a_ifindex); + nl_dump(p, "dev %d ", addr->a_ifindex); - dp_dump(p, "scope %s", + nl_dump(p, "scope %s", rtnl_scope2str(addr->a_scope, buf, sizeof(buf))); rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf)); if (buf[0]) - dp_dump(p, " <%s>", buf); - - dp_dump(p, "\n"); + nl_dump(p, " <%s>", buf); - return 1; + nl_dump(p, "\n"); } -static int addr_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void addr_dump_details(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_addr *addr = (struct rtnl_addr *) obj; - int line = addr_dump_brief(obj, p); char buf[128]; + addr_dump_line(obj, p); + if (addr->ce_mask & (ADDR_ATTR_LABEL | ADDR_ATTR_BROADCAST | - ADDR_ATTR_ANYCAST | ADDR_ATTR_MULTICAST)) { - dp_dump_line(p, line++, " "); + ADDR_ATTR_MULTICAST)) { + nl_dump_line(p, " "); if (addr->ce_mask & ADDR_ATTR_LABEL) - dp_dump(p, " label %s", addr->a_label); + nl_dump(p, " label %s", addr->a_label); if (addr->ce_mask & ADDR_ATTR_BROADCAST) - dp_dump(p, " broadcast %s", + nl_dump(p, " broadcast %s", nl_addr2str(addr->a_bcast, buf, sizeof(buf))); - if (addr->ce_mask & ADDR_ATTR_ANYCAST) - dp_dump(p, " anycast %s", - nl_addr2str(addr->a_anycast, buf, - sizeof(buf))); - if (addr->ce_mask & ADDR_ATTR_MULTICAST) - dp_dump(p, " multicast %s", + nl_dump(p, " multicast %s", nl_addr2str(addr->a_multicast, buf, sizeof(buf))); - dp_dump(p, "\n"); + if (addr->ce_mask & ADDR_ATTR_ANYCAST) + nl_dump(p, " anycast %s", + nl_addr2str(addr->a_anycast, buf, + sizeof(buf))); + + nl_dump(p, "\n"); } if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; - dp_dump_line(p, line++, " valid-lifetime %s", + nl_dump_line(p, " valid-lifetime %s", ci->aci_valid == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_valid * 1000, buf, sizeof(buf))); - dp_dump(p, " preferred-lifetime %s\n", + nl_dump(p, " preferred-lifetime %s\n", ci->aci_prefered == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_prefered * 1000, buf, sizeof(buf))); - dp_dump_line(p, line++, " created boot-time+%s ", + nl_dump_line(p, " created boot-time+%s ", nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10, buf, sizeof(buf))); - dp_dump(p, "last-updated boot-time+%s\n", + nl_dump(p, "last-updated boot-time+%s\n", nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10, buf, sizeof(buf))); } - - return line; -} - -static int addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p) -{ - return addr_dump_full(obj, p); } -static int addr_dump_xml(struct nl_object *obj, struct nl_dump_params *p) +static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { - struct rtnl_addr *addr = (struct rtnl_addr *) obj; - struct nl_cache *link_cache; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "<address>\n"); - dp_dump_line(p, line++, " <family>%s</family>\n", - nl_af2str(addr->a_family, buf, sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_LOCAL) - dp_dump_line(p, line++, " <local>%s</local>\n", - nl_addr2str(addr->a_local, buf, sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_PEER) - dp_dump_line(p, line++, " <peer>%s</peer>\n", - nl_addr2str(addr->a_peer, buf, sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_BROADCAST) - dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n", - nl_addr2str(addr->a_bcast, buf, sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_ANYCAST) - dp_dump_line(p, line++, " <anycast>%s</anycast>\n", - nl_addr2str(addr->a_anycast, buf, sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_MULTICAST) - dp_dump_line(p, line++, " <multicast>%s</multicast>\n", - nl_addr2str(addr->a_multicast, buf, - sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_PREFIXLEN) - dp_dump_line(p, line++, " <prefixlen>%u</prefixlen>\n", - addr->a_prefixlen); - link_cache = nl_cache_mngt_require("route/link"); - - if (link_cache) - dp_dump_line(p, line++, " <device>%s</device>\n", - rtnl_link_i2name(link_cache, addr->a_ifindex, - buf, sizeof(buf))); - else - dp_dump_line(p, line++, " <device>%u</device>\n", - addr->a_ifindex); - - if (addr->ce_mask & ADDR_ATTR_SCOPE) - dp_dump_line(p, line++, " <scope>%s</scope>\n", - rtnl_scope2str(addr->a_scope, buf, sizeof(buf))); - - if (addr->ce_mask & ADDR_ATTR_LABEL) - dp_dump_line(p, line++, " <label>%s</label>\n", addr->a_label); - - rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); - - if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { - struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; - - dp_dump_line(p, line++, " <cacheinfo>\n"); - - dp_dump_line(p, line++, " <valid>%s</valid>\n", - ci->aci_valid == 0xFFFFFFFFU ? "forever" : - nl_msec2str(ci->aci_valid * 1000, - buf, sizeof(buf))); - - dp_dump_line(p, line++, " <prefered>%s</prefered>\n", - ci->aci_prefered == 0xFFFFFFFFU ? "forever" : - nl_msec2str(ci->aci_prefered * 1000, - buf, sizeof(buf))); - - dp_dump_line(p, line++, " <created>%s</created>\n", - nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10, - buf, sizeof(buf))); - - dp_dump_line(p, line++, " <last-update>%s</last-update>\n", - nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10, - buf, sizeof(buf))); - - dp_dump_line(p, line++, " </cacheinfo>\n"); - } - - dp_dump_line(p, line++, "</address>\n"); - - return line; + addr_dump_details(obj, p); } -static int addr_dump_env(struct nl_object *obj, struct nl_dump_params *p) +static void addr_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct nl_cache *link_cache; char buf[128]; - int line = 0; - dp_dump_line(p, line++, "ADDR_FAMILY=%s\n", + nl_dump_line(p, "ADDR_FAMILY=%s\n", nl_af2str(addr->a_family, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_LOCAL) - dp_dump_line(p, line++, "ADDR_LOCAL=%s\n", + nl_dump_line(p, "ADDR_LOCAL=%s\n", nl_addr2str(addr->a_local, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_PEER) - dp_dump_line(p, line++, "ADDR_PEER=%s\n", + nl_dump_line(p, "ADDR_PEER=%s\n", nl_addr2str(addr->a_peer, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_BROADCAST) - dp_dump_line(p, line++, "ADDR_BROADCAST=%s\n", + nl_dump_line(p, "ADDR_BROADCAST=%s\n", nl_addr2str(addr->a_bcast, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_ANYCAST) - dp_dump_line(p, line++, "ADDR_ANYCAST=%s\n", + nl_dump_line(p, "ADDR_ANYCAST=%s\n", nl_addr2str(addr->a_anycast, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_MULTICAST) - dp_dump_line(p, line++, "ADDR_MULTICAST=%s\n", + nl_dump_line(p, "ADDR_MULTICAST=%s\n", nl_addr2str(addr->a_multicast, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_PREFIXLEN) - dp_dump_line(p, line++, "ADDR_PREFIXLEN=%u\n", + nl_dump_line(p, "ADDR_PREFIXLEN=%u\n", addr->a_prefixlen); link_cache = nl_cache_mngt_require("route/link"); - dp_dump_line(p, line++, "ADDR_IFINDEX=%u\n", addr->a_ifindex); + nl_dump_line(p, "ADDR_IFINDEX=%u\n", addr->a_ifindex); if (link_cache) - dp_dump_line(p, line++, "ADDR_IFNAME=%s\n", + nl_dump_line(p, "ADDR_IFNAME=%s\n", rtnl_link_i2name(link_cache, addr->a_ifindex, - buf, sizeof(buf))); + buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_SCOPE) - dp_dump_line(p, line++, "ADDR_SCOPE=%s\n", + nl_dump_line(p, "ADDR_SCOPE=%s\n", rtnl_scope2str(addr->a_scope, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_LABEL) - dp_dump_line(p, line++, "ADDR_LABEL=%s\n", addr->a_label); + nl_dump_line(p, "ADDR_LABEL=%s\n", addr->a_label); rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf)); if (buf[0]) - dp_dump_line(p, line++, "ADDR_FLAGS=%s\n", buf); + nl_dump_line(p, "ADDR_FLAGS=%s\n", buf); if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; - dp_dump_line(p, line++, "ADDR_CACHEINFO_VALID=%s\n", + nl_dump_line(p, "ADDR_CACHEINFO_VALID=%s\n", ci->aci_valid == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_valid * 1000, buf, sizeof(buf))); - dp_dump_line(p, line++, "ADDR_CACHEINFO_PREFERED=%s\n", + nl_dump_line(p, "ADDR_CACHEINFO_PREFERED=%s\n", ci->aci_prefered == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_prefered * 1000, buf, sizeof(buf))); - dp_dump_line(p, line++, "ADDR_CACHEINFO_CREATED=%s\n", + nl_dump_line(p, "ADDR_CACHEINFO_CREATED=%s\n", nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10, buf, sizeof(buf))); - dp_dump_line(p, line++, "ADDR_CACHEINFO_LASTUPDATE=%s\n", + nl_dump_line(p, "ADDR_CACHEINFO_LASTUPDATE=%s\n", nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10, buf, sizeof(buf))); } - - return line; } static int addr_compare(struct nl_object *_a, struct nl_object *_b, @@ -580,12 +490,12 @@ static int addr_compare(struct nl_object *_a, struct nl_object *_b, diff |= ADDR_DIFF(LABEL, strcmp(a->a_label, b->a_label)); diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer)); diff |= ADDR_DIFF(LOCAL, nl_addr_cmp(a->a_local, b->a_local)); - diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast,b->a_anycast)); diff |= ADDR_DIFF(MULTICAST, nl_addr_cmp(a->a_multicast, b->a_multicast)); diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast)); + diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast, b->a_anycast)); - if (flags & LOOSE_FLAG_COMPARISON) + if (flags & LOOSE_COMPARISON) diff |= ADDR_DIFF(FLAGS, (a->a_flags ^ b->a_flags) & b->a_flag_mask); else @@ -607,7 +517,6 @@ static struct trans_tbl addr_attrs[] = { __ADD(ADDR_ATTR_PEER, peer) __ADD(ADDR_ATTR_LOCAL, local) __ADD(ADDR_ATTR_BROADCAST, broadcast) - __ADD(ADDR_ATTR_ANYCAST, anycast) __ADD(ADDR_ATTR_MULTICAST, multicast) }; @@ -639,25 +548,15 @@ void rtnl_addr_put(struct rtnl_addr *addr) * @{ */ -struct nl_cache *rtnl_addr_alloc_cache(struct nl_handle *handle) +int rtnl_addr_alloc_cache(struct nl_sock *sk, struct nl_cache **result) { - struct nl_cache *cache; - - cache = nl_cache_alloc(&rtnl_addr_ops); - if (!cache) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - return cache; + return nl_cache_alloc_and_fill(&rtnl_addr_ops, sk, result); } /** @} */ -static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags) +static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags, + struct nl_msg **result) { struct nl_msg *msg; struct ifaddrmsg am = { @@ -680,7 +579,7 @@ static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags) msg = nlmsg_alloc_simple(cmd, flags); if (!msg) - goto nla_put_failure; + return -NLE_NOMEM; if (nlmsg_append(msg, &am, sizeof(am), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -690,7 +589,7 @@ static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags) if (tmpl->ce_mask & ADDR_ATTR_PEER) NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_peer); - else + else if (tmpl->ce_mask & ADDR_ATTR_LOCAL) NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_local); if (tmpl->ce_mask & ADDR_ATTR_LABEL) @@ -699,14 +598,22 @@ static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags) if (tmpl->ce_mask & ADDR_ATTR_BROADCAST) NLA_PUT_ADDR(msg, IFA_BROADCAST, tmpl->a_bcast); - if (tmpl->ce_mask & ADDR_ATTR_ANYCAST) - NLA_PUT_ADDR(msg, IFA_ANYCAST, tmpl->a_anycast); + if (tmpl->ce_mask & ADDR_ATTR_CACHEINFO) { + struct ifa_cacheinfo ca = { + .ifa_valid = tmpl->a_cacheinfo.aci_valid, + .ifa_prefered = tmpl->a_cacheinfo.aci_prefered, + }; + + NLA_PUT(msg, IFA_CACHEINFO, sizeof(ca), &ca); + } + - return msg; + *result = msg; + return 0; nla_put_failure: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** @@ -718,6 +625,7 @@ nla_put_failure: * Build netlink request message to request addition of new address * @arg addr Address object representing the new address. * @arg flags Additional netlink message flags. + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting the addition of a new * address. The netlink message header isn't fully equipped with @@ -732,25 +640,24 @@ nla_put_failure: * which case a host scope is used if not specified otherwise. * * @note Free the memory after usage using nlmsg_free(). - * @return Newly allocated netlink message or NULL if an error occured. + * + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags) +int rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags, + struct nl_msg **result) { int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL; - if ((addr->ce_mask & required) != required) { - nl_error(EINVAL, "Missing mandatory attributes, required are: " - "ifindex, family, prefixlen, local address."); - return NULL; - } + if ((addr->ce_mask & required) != required) + return -NLE_MISSING_ATTR; - return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags); + return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags, result); } /** * Request addition of new address - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg addr Address object representing the new address. * @arg flags Additional netlink message flags. * @@ -762,21 +669,20 @@ struct nl_msg *rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags) +int rtnl_addr_add(struct nl_sock *sk, struct rtnl_addr *addr, int flags) { struct nl_msg *msg; int err; - msg = rtnl_addr_build_add_request(addr, flags); - if (!msg) - return nl_get_errno(); + if ((err = rtnl_addr_build_add_request(addr, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -790,6 +696,7 @@ int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags) * Build a netlink request message to request deletion of an address * @arg addr Address object to be deleteted. * @arg flags Additional netlink message flags. + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a deletion of an address. * The netlink message header isn't fully equipped with all relevant @@ -806,24 +713,23 @@ int rtnl_addr_add(struct nl_handle *handle, struct rtnl_addr *addr, int flags) * - peer address (rtnl_addr_set_peer(), IPv4 only) * * @note Free the memory after usage using nlmsg_free(). - * @return Newly allocated netlink message or NULL if an error occured. + * + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags) +int rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags, + struct nl_msg **result) { int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY; - if ((addr->ce_mask & required) != required) { - nl_error(EINVAL, "Missing mandatory attributes, required are: " - "ifindex, family"); - return NULL; - } - - return build_addr_msg(addr, RTM_DELADDR, flags); + if ((addr->ce_mask & required) != required) + return -NLE_MISSING_ATTR; + + return build_addr_msg(addr, RTM_DELADDR, flags, result); } /** * Request deletion of an address - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg addr Address object to be deleted. * @arg flags Additional netlink message flags. * @@ -835,22 +741,20 @@ struct nl_msg *rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_addr_delete(struct nl_handle *handle, struct rtnl_addr *addr, - int flags) +int rtnl_addr_delete(struct nl_sock *sk, struct rtnl_addr *addr, int flags) { struct nl_msg *msg; int err; - msg = rtnl_addr_build_delete_request(addr, flags); - if (!msg) - return nl_get_errno(); + if ((err = rtnl_addr_build_delete_request(addr, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -860,10 +764,15 @@ int rtnl_addr_delete(struct nl_handle *handle, struct rtnl_addr *addr, * @{ */ -void rtnl_addr_set_label(struct rtnl_addr *addr, const char *label) +int rtnl_addr_set_label(struct rtnl_addr *addr, const char *label) { - strncpy(addr->a_label, label, sizeof(addr->a_label) - 1); + if (strlen(label) > sizeof(addr->a_label) - 1) + return -NLE_RANGE; + + strcpy(addr->a_label, label); addr->ce_mask |= ADDR_ATTR_LABEL; + + return 0; } char *rtnl_addr_get_label(struct rtnl_addr *addr) @@ -882,10 +791,7 @@ void rtnl_addr_set_ifindex(struct rtnl_addr *addr, int ifindex) int rtnl_addr_get_ifindex(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_IFINDEX) - return addr->a_ifindex; - else - return RTNL_LINK_NOT_FOUND; + return addr->a_ifindex; } void rtnl_addr_set_family(struct rtnl_addr *addr, int family) @@ -896,10 +802,7 @@ void rtnl_addr_set_family(struct rtnl_addr *addr, int family) int rtnl_addr_get_family(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_FAMILY) - return addr->a_family; - else - return AF_UNSPEC; + return addr->a_family; } void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefix) @@ -910,10 +813,7 @@ void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefix) int rtnl_addr_get_prefixlen(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_PREFIXLEN) - return addr->a_prefixlen; - else - return -1; + return addr->a_prefixlen; } void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope) @@ -924,10 +824,7 @@ void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope) int rtnl_addr_get_scope(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_SCOPE) - return addr->a_scope; - else - return -1; + return addr->a_scope; } void rtnl_addr_set_flags(struct rtnl_addr *addr, unsigned int flags) @@ -954,7 +851,7 @@ static inline int __assign_addr(struct rtnl_addr *addr, struct nl_addr **pos, { if (addr->ce_mask & ADDR_ATTR_FAMILY) { if (new->a_family != addr->a_family) - return nl_error(EINVAL, "Address family mismatch"); + return -NLE_AF_MISMATCH; } else addr->a_family = new->a_family; @@ -985,10 +882,7 @@ int rtnl_addr_set_local(struct rtnl_addr *addr, struct nl_addr *local) struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_LOCAL) - return addr->a_local; - else - return NULL; + return addr->a_local; } int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer) @@ -1003,10 +897,7 @@ int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer) struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_PEER) - return addr->a_peer; - else - return NULL; + return addr->a_peer; } int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast) @@ -1016,10 +907,18 @@ int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast) struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_BROADCAST) - return addr->a_bcast; - else - return NULL; + return addr->a_bcast; +} + +int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast) +{ + return __assign_addr(addr, &addr->a_multicast, multicast, + ADDR_ATTR_MULTICAST); +} + +struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr) +{ + return addr->a_multicast; } int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast) @@ -1030,24 +929,45 @@ int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast) struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_ANYCAST) - return addr->a_anycast; + return addr->a_anycast; +} + +uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *addr) +{ + if (addr->ce_mask & ADDR_ATTR_CACHEINFO) + return addr->a_cacheinfo.aci_valid; else - return NULL; + return 0xFFFFFFFFU; } -int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast) +void rtnl_addr_set_valid_lifetime(struct rtnl_addr *addr, uint32_t lifetime) { - return __assign_addr(addr, &addr->a_multicast, multicast, - ADDR_ATTR_MULTICAST); + addr->a_cacheinfo.aci_valid = lifetime; + addr->ce_mask |= ADDR_ATTR_CACHEINFO; } -struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr) +uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *addr) { - if (addr->ce_mask & ADDR_ATTR_MULTICAST) - return addr->a_multicast; + if (addr->ce_mask & ADDR_ATTR_CACHEINFO) + return addr->a_cacheinfo.aci_prefered; else - return NULL; + return 0xFFFFFFFFU; +} + +void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *addr, uint32_t lifetime) +{ + addr->a_cacheinfo.aci_prefered = lifetime; + addr->ce_mask |= ADDR_ATTR_CACHEINFO; +} + +uint32_t rtnl_addr_get_create_time(struct rtnl_addr *addr) +{ + return addr->a_cacheinfo.aci_cstamp; +} + +uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *addr) +{ + return addr->a_cacheinfo.aci_tstamp; } /** @} */ @@ -1059,6 +979,9 @@ struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr) static struct trans_tbl addr_flags[] = { __ADD(IFA_F_SECONDARY, secondary) + __ADD(IFA_F_NODAD, nodad) + __ADD(IFA_F_OPTIMISTIC, optimistic) + __ADD(IFA_F_HOMEADDRESS, homeaddress) __ADD(IFA_F_DEPRECATED, deprecated) __ADD(IFA_F_TENTATIVE, tentative) __ADD(IFA_F_PERMANENT, permanent) @@ -1080,18 +1003,19 @@ int rtnl_addr_str2flags(const char *name) static struct nl_object_ops addr_obj_ops = { .oo_name = "route/addr", .oo_size = sizeof(struct rtnl_addr), + .oo_constructor = addr_constructor, .oo_free_data = addr_free_data, .oo_clone = addr_clone, - .oo_dump[NL_DUMP_BRIEF] = addr_dump_brief, - .oo_dump[NL_DUMP_FULL] = addr_dump_full, - .oo_dump[NL_DUMP_STATS] = addr_dump_stats, - .oo_dump[NL_DUMP_XML] = addr_dump_xml, - .oo_dump[NL_DUMP_ENV] = addr_dump_env, + .oo_dump = { + [NL_DUMP_LINE] = addr_dump_line, + [NL_DUMP_DETAILS] = addr_dump_details, + [NL_DUMP_STATS] = addr_dump_stats, + [NL_DUMP_ENV] = addr_dump_env, + }, .oo_compare = addr_compare, .oo_attrs2str = addr_attrs2str, .oo_id_attrs = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX | - ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN | - ADDR_ATTR_PEER), + ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN), }; static struct nl_af_group addr_groups[] = { diff --git a/lib/route/class.c b/lib/route/class.c index 7966b09..ddf2d2e 100644 --- a/lib/route/class.c +++ b/lib/route/class.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -36,7 +36,7 @@ static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, class = rtnl_class_alloc(); if (!class) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } class->ce_msgtype = n->nlmsg_type; @@ -53,26 +53,20 @@ static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } err = pp->pp_cb((struct nl_object *) class, pp); - if (err < 0) - goto errout_free; - - err = P_ACCEPT; - errout_free: rtnl_class_put(class); errout: return err; } -static int class_request_update(struct nl_cache *cache, - struct nl_handle *handle) +static int class_request_update(struct nl_cache *cache, struct nl_sock *sk) { struct tcmsg tchdr = { .tcm_family = AF_UNSPEC, .tcm_ifindex = cache->c_iarg1, }; - return nl_send_simple(handle, RTM_GETTCLASS, NLM_F_DUMP, &tchdr, + return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr, sizeof(tchdr)); } @@ -81,15 +75,15 @@ static int class_request_update(struct nl_cache *cache, * @{ */ -static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags) +static int class_build(struct rtnl_class *class, int type, int flags, + struct nl_msg **result) { struct rtnl_class_ops *cops; - struct nl_msg *msg; int err; - msg = tca_build_msg((struct rtnl_tca *) class, type, flags); - if (!msg) - goto errout; + err = tca_build_msg((struct rtnl_tca *) class, type, flags, result); + if (err < 0) + return err; cops = rtnl_class_lookup_ops(class); if (cops && cops->co_get_opts) { @@ -97,23 +91,24 @@ static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags) opts = cops->co_get_opts(class); if (opts) { - err = nla_put_nested(msg, TCA_OPTIONS, opts); + err = nla_put_nested(*result, TCA_OPTIONS, opts); nlmsg_free(opts); if (err < 0) goto errout; } } - return msg; + return 0; errout: - nlmsg_free(msg); - return NULL; + nlmsg_free(*result); + return err; } /** * Build a netlink message to add a new class * @arg class class to add * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting an addition of a class. * The netlink message header isn't fully equipped with all relevant @@ -123,16 +118,17 @@ errout: * Common message flags * - NLM_F_REPLACE - replace possibly existing classes * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags) +int rtnl_class_build_add_request(struct rtnl_class *class, int flags, + struct nl_msg **result) { - return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags); + return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result); } /** * Add a new class - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg class class to delete * @arg flags additional netlink message flags * @@ -145,22 +141,74 @@ struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags) * * @return 0 on success or a negative error code */ -int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class, - int flags) +int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags) { struct nl_msg *msg; int err; - msg = rtnl_class_build_add_request(class, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; + return wait_for_ack(sk); +} + +int rtnl_class_build_delete_request(struct rtnl_class *class, + struct nl_msg **result) +{ + struct nl_msg *msg; + struct tcmsg tchdr; + int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT; + + if ((class->ce_mask & required) != required) + BUG(); + + msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0); + if (!msg) + return -NLE_NOMEM; + + tchdr.tcm_family = AF_UNSPEC; + tchdr.tcm_handle = class->c_handle; + tchdr.tcm_parent = class->c_parent; + tchdr.tcm_ifindex = class->c_ifindex; + if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) { + nlmsg_free(msg); + return -NLE_MSGSIZE; + } + + *result = msg; + return 0; +} + +/** + * Delete a class + * @arg sk Netlink socket. + * @arg class class to delete + * + * Builds a netlink message by calling rtnl_class_build_delete_request(), + * sends the request to the kernel and waits for the ACK to be + * received and thus blocks until the request has been processed. + * + * @return 0 on success or a negative error code + */ +int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class) +{ + struct nl_msg *msg; + int err; + + if ((err = rtnl_class_build_delete_request(class, &msg)) < 0) + return err; + + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); - return nl_wait_for_ack(handle); + if (err < 0) + return err; + + return wait_for_ack(sk); } /** @} */ @@ -172,7 +220,7 @@ int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class, /** * Build a class cache including all classes attached to the specified interface - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg ifindex interface index of the link the classes are * attached to. * @@ -181,22 +229,49 @@ int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class, * * @return The cache or NULL if an error has occured. */ -struct nl_cache * rtnl_class_alloc_cache(struct nl_handle *handle, int ifindex) +int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex, + struct nl_cache **result) { struct nl_cache * cache; + int err; cache = nl_cache_alloc(&rtnl_class_ops); if (!cache) - return NULL; + return -NLE_NOMEM; cache->c_iarg1 = ifindex; - if (handle && nl_cache_refill(handle, cache) < 0) { + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { nl_cache_free(cache); - return NULL; + return err; } - return cache; + *result = cache; + return 0; +} + +/** + * Look up class by its handle in the provided cache + * @arg cache class cache + * @arg ifindex interface the class is attached to + * @arg handle class handle + * @return pointer to class inside the cache or NULL if no match was found. + */ +struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex, + uint32_t handle) +{ + struct rtnl_class *class; + + if (cache->c_ops != &rtnl_class_ops) + return NULL; + + nl_list_for_each_entry(class, &cache->c_items, ce_list) { + if (class->c_handle == handle && class->c_ifindex == ifindex) { + nl_object_get((struct nl_object *) class); + return class; + } + } + return NULL; } /** @} */ diff --git a/lib/route/class_api.c b/lib/route/class_api.c index c814486..374cf0f 100644 --- a/lib/route/class_api.c +++ b/lib/route/class_api.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -43,7 +43,7 @@ int rtnl_class_register(struct rtnl_class_ops *cops) for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next) if (!strcasecmp(cops->co_kind, o->co_kind)) - return nl_errno(EEXIST); + return -NLE_EXIST; cops->co_next = NULL; *op = cops; @@ -64,7 +64,7 @@ int rtnl_class_unregister(struct rtnl_class_ops *cops) break; if (!o) - return nl_errno(ENOENT); + return -NLE_OBJ_NOTFOUND; *op = cops->co_next; diff --git a/lib/route/class_obj.c b/lib/route/class_obj.c index 0601bdf..5c2e5be 100644 --- a/lib/route/class_obj.c +++ b/lib/route/class_obj.c @@ -55,62 +55,54 @@ errout: return err; } -static int class_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void class_dump_line(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_class *class = (struct rtnl_class *) obj; struct rtnl_class_ops *cops; - int line = tca_dump_brief((struct rtnl_tca *) class, "class", p, 0); + tca_dump_line((struct rtnl_tca *) class, "class", p); cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_dump[NL_DUMP_BRIEF]) - line = cops->co_dump[NL_DUMP_BRIEF](class, p, line); - dp_dump(p, "\n"); - - return line; + if (cops && cops->co_dump[NL_DUMP_LINE]) + cops->co_dump[NL_DUMP_LINE](class, p); + nl_dump(p, "\n"); } -static int class_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void class_dump_details(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_class *class = (struct rtnl_class *) obj; struct rtnl_class_ops *cops; - int line; - line = class_dump_brief(obj, p); - line = tca_dump_full((struct rtnl_tca *) class, p, line); + class_dump_line(obj, p); + tca_dump_details((struct rtnl_tca *) class, p); if (class->c_info) { char buf[32]; - dp_dump(p, "child-qdisc %s ", + nl_dump(p, "child-qdisc %s ", rtnl_tc_handle2str(class->c_info, buf, sizeof(buf))); } cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_dump[NL_DUMP_FULL]) - line = cops->co_dump[NL_DUMP_FULL](class, p, line); + if (cops && cops->co_dump[NL_DUMP_DETAILS]) + cops->co_dump[NL_DUMP_DETAILS](class, p); else if (!class->c_info) - dp_dump(p, "noop (no leaf qdisc)"); - - dp_dump(p, "\n"); + nl_dump(p, "noop (no leaf qdisc)"); - return line; + nl_dump(p, "\n"); } -static int class_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +static void class_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_class *class = (struct rtnl_class *) obj; struct rtnl_class_ops *cops; - int line; - line = class_dump_full(obj, p); - line = tca_dump_stats((struct rtnl_tca *) class, p, line); - dp_dump(p, "\n"); + class_dump_details(obj, p); + tca_dump_stats((struct rtnl_tca *) class, p); + nl_dump(p, "\n"); cops = rtnl_class_lookup_ops(class); if (cops && cops->co_dump[NL_DUMP_STATS]) - line = cops->co_dump[NL_DUMP_STATS](class, p, line); - - return line; + cops->co_dump[NL_DUMP_STATS](class, p); } /** @@ -277,9 +269,11 @@ struct nl_object_ops class_obj_ops = { .oo_size = sizeof(struct rtnl_class), .oo_free_data = class_free_data, .oo_clone = class_clone, - .oo_dump[NL_DUMP_BRIEF] = class_dump_brief, - .oo_dump[NL_DUMP_FULL] = class_dump_full, - .oo_dump[NL_DUMP_STATS] = class_dump_stats, + .oo_dump = { + [NL_DUMP_LINE] = class_dump_line, + [NL_DUMP_DETAILS] = class_dump_details, + [NL_DUMP_STATS] = class_dump_stats, + }, .oo_compare = tca_compare, .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), }; diff --git a/lib/route/classifier.c b/lib/route/cls.c index df6d3ae..cbf0345 100644 --- a/lib/route/classifier.c +++ b/lib/route/cls.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ /** @@ -38,13 +38,13 @@ static struct nl_cache_ops rtnl_cls_ops; static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *nlh, struct nl_parser_param *pp) { - int err; - struct rtnl_cls *cls; struct rtnl_cls_ops *cops; + struct rtnl_cls *cls; + int err; cls = rtnl_cls_alloc(); if (!cls) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } cls->ce_msgtype = nlh->nlmsg_type; @@ -57,25 +57,17 @@ static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, cls->c_protocol = ntohs(TC_H_MIN(cls->c_info)); cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_msg_parser) { - err = cops->co_msg_parser(cls); - if (err < 0) - goto errout_free; - } - - err = pp->pp_cb((struct nl_object *) cls, pp); - if (err < 0) + if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0) goto errout_free; - err = P_ACCEPT; - + err = pp->pp_cb((struct nl_object *) cls, pp); errout_free: rtnl_cls_put(cls); errout: return err; } -static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle) +static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) { struct tcmsg tchdr = { .tcm_family = AF_UNSPEC, @@ -83,44 +75,48 @@ static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle) .tcm_parent = cache->c_iarg2, }; - return nl_send_simple(handle, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, + return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, sizeof(tchdr)); } -static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags) +static int cls_build(struct rtnl_cls *cls, int type, int flags, + struct nl_msg **result) { - struct nl_msg *msg; struct rtnl_cls_ops *cops; int err, prio, proto; struct tcmsg *tchdr; - msg = tca_build_msg((struct rtnl_tca *) cls, type, flags); - if (!msg) - goto errout; + err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result); + if (err < 0) + return err; - tchdr = nlmsg_data(nlmsg_hdr(msg)); + tchdr = nlmsg_data(nlmsg_hdr(*result)); prio = rtnl_cls_get_prio(cls); proto = rtnl_cls_get_protocol(cls); - tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)), + tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)); cops = rtnl_cls_lookup_ops(cls); if (cops && cops->co_get_opts) { struct nl_msg *opts; - - opts = cops->co_get_opts(cls); - if (opts) { - err = nla_put_nested(msg, TCA_OPTIONS, opts); - nlmsg_free(opts); - if (err < 0) - goto errout; + + if (!(opts = nlmsg_alloc())) { + err = -NLE_NOMEM; + goto errout; } + + if (!(err = cops->co_get_opts(cls, opts))) + err = nla_put_nested(*result, TCA_OPTIONS, opts); + + nlmsg_free(opts); + if (err < 0) + goto errout; } - return msg; + return 0; errout: - nlmsg_free(msg); - return NULL; + nlmsg_free(*result); + return err; } /** @@ -132,6 +128,7 @@ errout: * Build a netlink message to add a new classifier * @arg cls classifier to add * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting an addition of a classifier * The netlink message header isn't fully equipped with all relevant @@ -140,16 +137,17 @@ errout: * the new classifier set via \c rtnl_cls_set_* functions. \a opts * may point to the clsasifier specific options. * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags) +int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags, + struct nl_msg **result) { - return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags); + return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result); } /** * Add a new classifier - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg cls classifier to add * @arg flags additional netlink message flags * @@ -159,43 +157,44 @@ struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags) +int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_cls_build_add_request(cls, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return nl_wait_for_ack(sk); } /** * Build a netlink message to change classifier attributes * @arg cls classifier to change * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a change of a neigh * attributes. The netlink message header isn't fully equipped with * all relevant fields and must thus be sent out via nl_send_auto_complete() * or supplemented as needed. * - * @return The netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags) +int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags, + struct nl_msg **result) { - return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags); + return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result); } /** * Change a classifier - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg cls classifier to change * @arg flags additional netlink message flags * @@ -205,45 +204,45 @@ struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls, - int flags) +int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_cls_build_change_request(cls, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return nl_wait_for_ack(sk); } /** * Build a netlink request message to delete a classifier * @arg cls classifier to delete * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a deletion of a classifier. * The netlink message header isn't fully equipped with all relevant * fields and must thus be sent out via nl_send_auto_complete() * or supplemented as needed. * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags) +int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags, + struct nl_msg **result) { - return cls_build(cls, RTM_DELTFILTER, flags); + return cls_build(cls, RTM_DELTFILTER, flags, result); } /** * Delete a classifier - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg cls classifier to delete * @arg flags additional netlink message flags * @@ -253,21 +252,20 @@ struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags) +int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_cls_build_delete_request(cls, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return nl_wait_for_ack(sk); } /** @} */ @@ -280,36 +278,37 @@ int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags) /** * Build a classifier cache including all classifiers attached to the * specified class/qdisc on eht specified interface. - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg ifindex interface index of the link the classes are * attached to. * @arg parent parent qdisc/class + * @arg result Pointer to store resulting cache. * * Allocates a new cache, initializes it properly and updates it to * include all classes attached to the specified interface. * * @note The caller is responsible for destroying and freeing the * cache after using it. - * @return The cache or NULL if an error has occured. + * @return 0 on success or a negative error code. */ -struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle, - int ifindex, uint32_t parent) +int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result) { struct nl_cache * cache; + int err; - cache = nl_cache_alloc(&rtnl_cls_ops); - if (cache == NULL) - return NULL; + if (!(cache = nl_cache_alloc(&rtnl_cls_ops))) + return -NLE_NOMEM; cache->c_iarg1 = ifindex; cache->c_iarg2 = parent; - if (handle && nl_cache_refill(handle, cache) < 0) { + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { nl_cache_free(cache); - return NULL; + return err; } - return cache; + *result = cache; + return 0; } /** @} */ diff --git a/lib/route/cls/basic.c b/lib/route/cls/basic.c new file mode 100644 index 0000000..1460b72 --- /dev/null +++ b/lib/route/cls/basic.c @@ -0,0 +1,211 @@ +/* + * lib/route/cls/basic.c Basic Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cls + * @defgroup basic Basic Classifier + * + * @par Introduction + * The basic classifier is the simplest form of a classifier. It does + * not have any special classification capabilities, instead it can be + * used to classify exclusively based on extended matches or to + * create a "catch-all" filter. + * + * @{ + */ + +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/route/classifier.h> +#include <netlink/route/classifier-modules.h> +#include <netlink/route/cls/basic.h> +#include <netlink/route/cls/ematch.h> + +struct rtnl_basic +{ + uint32_t b_classid; + struct rtnl_ematch_tree * b_ematch; + int b_mask; +}; + +/** @cond SKIP */ +#define BASIC_ATTR_CLASSID 0x001 +#define BASIC_ATTR_EMATCH 0x002 +/** @endcond */ + +static struct nla_policy basic_policy[TCA_FW_MAX+1] = { + [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, + [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, + [TCA_BASIC_ACT] = { .type = NLA_NESTED }, + [TCA_BASIC_POLICE] = { .type = NLA_NESTED }, +}; + +static int basic_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) +{ + return -NLE_OPNOTSUPP; +} + +static void basic_free_data(struct rtnl_cls *cls) +{ + struct rtnl_basic *basic = rtnl_cls_data(cls); + + rtnl_ematch_tree_free(basic->b_ematch); +} + +static int basic_msg_parser(struct rtnl_cls *cls) +{ + struct nlattr *tb[TCA_BASIC_MAX + 1]; + struct rtnl_basic *basic = rtnl_cls_data(cls); + int err; + + err = tca_parse(tb, TCA_BASIC_MAX, (struct rtnl_tca *) cls, basic_policy); + if (err < 0) + return err; + + if (tb[TCA_BASIC_CLASSID]) { + basic->b_classid = nla_get_u32(tb[TCA_BASIC_CLASSID]); + basic->b_mask |= BASIC_ATTR_CLASSID; + } + + if (tb[TCA_BASIC_EMATCHES]) { + if ((err = rtnl_ematch_parse(tb[TCA_BASIC_EMATCHES], + &basic->b_ematch)) < 0) + return err; + + if (basic->b_ematch) + basic->b_mask |= BASIC_ATTR_EMATCH; + } + + if (tb[TCA_BASIC_ACT]) { + /* XXX */ + } + + if (tb[TCA_BASIC_POLICE]) { + /* XXX */ + } + + return 0; +} + +static void basic_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + char buf[32]; + + if (b->b_mask & BASIC_ATTR_EMATCH) + nl_dump(p, " ematch"); + else + nl_dump(p, " match-all"); + + if (b->b_mask & BASIC_ATTR_CLASSID) + nl_dump(p, " classify-to %s", + rtnl_tc_handle2str(b->b_classid, buf, sizeof(buf))); +} + +static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + + if (b->b_mask & BASIC_ATTR_EMATCH) { + nl_dump(p, "\n"); + nl_dump_line(p, " ematch "); + rtnl_ematch_tree_dump(b->b_ematch, p); + } else + nl_dump(p, "no options.\n"); +} + +static int basic_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + + if (!(b->b_mask & BASIC_ATTR_CLASSID)) + return -NLE_MISSING_ATTR; + + NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_classid); + + return 0; + +nla_put_failure: + return -NLE_NOMEM; +} + +/** + * @name Attribute Modifications + * @{ + */ + +int rtnl_basic_set_classid(struct rtnl_cls *cls, uint32_t classid) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + + b->b_classid = classid; + b->b_mask |= BASIC_ATTR_CLASSID; + + return 0; +} + +uint32_t rtnl_basic_get_classid(struct rtnl_cls *cls) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + + return b->b_classid; +} + +int rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + + if (b->b_ematch) { + rtnl_ematch_tree_free(b->b_ematch); + b->b_mask &= ~BASIC_ATTR_EMATCH; + } + + b->b_ematch = tree; + + if (tree) + b->b_mask |= BASIC_ATTR_EMATCH; + + return 0; +} + +struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls) +{ + struct rtnl_basic *b = rtnl_cls_data(cls); + return b->b_ematch; +} + +/** @} */ + +static struct rtnl_cls_ops basic_ops = { + .co_kind = "basic", + .co_size = sizeof(struct rtnl_basic), + .co_msg_parser = basic_msg_parser, + .co_clone = basic_clone, + .co_free_data = basic_free_data, + .co_get_opts = basic_get_opts, + .co_dump = { + [NL_DUMP_LINE] = basic_dump_line, + [NL_DUMP_DETAILS] = basic_dump_details, + }, +}; + +static void __init basic_init(void) +{ + rtnl_cls_register(&basic_ops); +} + +static void __exit basic_exit(void) +{ + rtnl_cls_unregister(&basic_ops); +} + +/** @} */ diff --git a/lib/route/cls/cgroup.c b/lib/route/cls/cgroup.c new file mode 100644 index 0000000..e5f38b8 --- /dev/null +++ b/lib/route/cls/cgroup.c @@ -0,0 +1,141 @@ +/* + * lib/route/cls/cgroup.c Control Groups Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cls_api + * @defgroup cgroup Control Groups Classifier + * + * @{ + */ + +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/attr.h> +#include <netlink/utils.h> +#include <netlink/route/classifier.h> +#include <netlink/route/classifier-modules.h> +#include <netlink/route/cls/cgroup.h> +#include <netlink/route/cls/ematch.h> + +/** @cond SKIP */ +#define CGROUP_ATTR_EMATCH 0x001 +/** @endcond */ + +static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = { + [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, +}; + +static void cgroup_free_data(struct rtnl_cls *cls) +{ + struct rtnl_cgroup *cg = rtnl_cls_data(cls); + + rtnl_ematch_tree_free(cg->cg_ematch); +} + +static int cgroup_msg_parser(struct rtnl_cls *cls) +{ + struct rtnl_cgroup *cg = rtnl_cls_data(cls); + struct nlattr *tb[TCA_CGROUP_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_CGROUP_MAX, (struct rtnl_tca *) cls, + cgroup_policy); + if (err < 0) + return err; + + if (tb[TCA_CGROUP_EMATCHES]) { + if ((err = rtnl_ematch_parse(tb[TCA_CGROUP_EMATCHES], + &cg->cg_ematch)) < 0) + return err; + cg->cg_mask |= CGROUP_ATTR_EMATCH; + } + +#if 0 + TODO: + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, +#endif + + return 0; +} + +static void cgroup_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) +{ + struct rtnl_cgroup *cg = rtnl_cls_data(cls); + + if (cg->cg_mask & CGROUP_ATTR_EMATCH) + nl_dump(p, " ematch"); + else + nl_dump(p, " match-all"); +} + +static void cgroup_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) +{ + struct rtnl_cgroup *cg = rtnl_cls_data(cls); + + if (cg->cg_mask & CGROUP_ATTR_EMATCH) { + nl_dump(p, "\n"); + nl_dump_line(p, " ematch "); + rtnl_ematch_tree_dump(cg->cg_ematch, p); + } +} + +/** + * @name Attribute Modifications + * @{ + */ + +int rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) +{ + struct rtnl_cgroup *cg = rtnl_cls_data(cls); + + if (cg->cg_ematch) { + rtnl_ematch_tree_free(cg->cg_ematch); + cg->cg_mask &= ~CGROUP_ATTR_EMATCH; + } + + cg->cg_ematch = tree; + + if (tree) + cg->cg_mask |= CGROUP_ATTR_EMATCH; + + return 0; +} + +struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls) +{ + struct rtnl_cgroup *cg = rtnl_cls_data(cls); + return cg->cg_ematch; +} + +static struct rtnl_cls_ops cgroup_ops = { + .co_kind = "cgroup", + .co_size = sizeof(struct rtnl_cgroup), + .co_msg_parser = cgroup_msg_parser, + .co_free_data = cgroup_free_data, + .co_dump = { + [NL_DUMP_LINE] = cgroup_dump_line, + [NL_DUMP_DETAILS] = cgroup_dump_details, + }, +}; + +static void __init cgroup_init(void) +{ + rtnl_cls_register(&cgroup_ops); +} + +static void __exit cgroup_exit(void) +{ + rtnl_cls_unregister(&cgroup_ops); +} + +/** @} */ diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c new file mode 100644 index 0000000..cb77b16 --- /dev/null +++ b/lib/route/cls/ematch.c @@ -0,0 +1,410 @@ +/* + * lib/route/cls/ematch.c Extended Matches + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cls + * @defgroup ematch Extended Match + * + * @{ + */ + +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/route/classifier.h> +#include <netlink/route/classifier-modules.h> +#include <netlink/route/cls/ematch.h> + +/** + * @name Module Registration + * @{ + */ + +static NL_LIST_HEAD(ematch_ops_list); + +/** + * Register ematch module + * @arg ops Module operations. + * + * @return 0 on success or a negative error code. + */ +int rtnl_ematch_register(struct rtnl_ematch_ops *ops) +{ + if (rtnl_ematch_lookup_ops(ops->eo_kind)) + return -NLE_EXIST; + + nl_list_add_tail(&ops->eo_list, &ematch_ops_list); + + return 0; +} + +/** + * Unregister ematch module + * @arg ops Module operations. + * + * @return 0 on success or a negative error code. + */ +int rtnl_ematch_unregister(struct rtnl_ematch_ops *ops) +{ + struct rtnl_ematch_ops *o; + + nl_list_for_each_entry(o, &ematch_ops_list, eo_list) { + if (ops->eo_kind == o->eo_kind) { + nl_list_del(&o->eo_list); + return 0; + } + } + + return -NLE_OBJ_NOTFOUND; +} + +/** + * Lookup ematch module by kind + * @arg kind Module kind. + * + * @return Module operations or NULL if not found. + */ +struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind) +{ + struct rtnl_ematch_ops *ops; + + nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) + if (ops->eo_kind == kind) + return ops; + + return NULL; +} + +/** + * Lookup ematch module by name + * @arg name Name of ematch module. + * + * @return Module operations or NULL if not fuond. + */ +struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_name(const char *name) +{ + struct rtnl_ematch_ops *ops; + + nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) + if (!strcasecmp(ops->eo_name, name)) + return ops; + + return NULL; +} + +/** @} */ + +/** + * @name Match + */ + +struct rtnl_ematch *rtnl_ematch_alloc(struct rtnl_ematch_ops *ops) +{ + struct rtnl_ematch *e; + size_t len = sizeof(*e) + (ops ? ops->eo_datalen : 0); + + if (!(e = calloc(1, len))) + return NULL; + + NL_INIT_LIST_HEAD(&e->e_list); + NL_INIT_LIST_HEAD(&e->e_childs); + + if (ops) { + e->e_ops = ops; + e->e_kind = ops->eo_kind; + } + + return e; +} + +/** + * Add ematch to the end of the parent's list of children. + * @arg parent Parent ematch. + * @arg child Ematch to be added as new child of parent. + */ +void rtnl_ematch_add_child(struct rtnl_ematch *parent, + struct rtnl_ematch *child) +{ + nl_list_add_tail(&child->e_list, &parent->e_childs); +} + +/** + * Remove ematch from the list it is linked to. + * @arg ematch Ematch to be unlinked. + */ +void rtnl_ematch_unlink(struct rtnl_ematch *ematch) +{ + nl_list_del(&ematch->e_list); +} + +void rtnl_ematch_free(struct rtnl_ematch *ematch) +{ + if (!ematch) + return; + + free(ematch); +} + +void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags) +{ + ematch->e_flags |= flags; +} + +void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags) +{ + ematch->e_flags &= ~flags; +} + +uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch) +{ + return ematch->e_flags; +} + +void *rtnl_ematch_data(struct rtnl_ematch *ematch) +{ + return ematch->e_data; +} + +/** @} */ + +/** + * @name Tree + */ + +struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid) +{ + struct rtnl_ematch_tree *tree; + + if (!(tree = calloc(1, sizeof(*tree)))) + return NULL; + + NL_INIT_LIST_HEAD(&tree->et_list); + tree->et_progid = progid; + + return tree; +} + +static void free_ematch_list(struct nl_list_head *head) +{ + struct rtnl_ematch *pos, *next; + + nl_list_for_each_entry_safe(pos, next, head, e_list) { + if (!nl_list_empty(&pos->e_childs)) + free_ematch_list(&pos->e_childs); + rtnl_ematch_free(pos); + } +} + +void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree) +{ + if (!tree) + return; + + free_ematch_list(&tree->et_list); + free(tree); +} + +void rtnl_ematch_tree_add_tail(struct rtnl_ematch_tree *tree, + struct rtnl_ematch *ematch) +{ + nl_list_add_tail(&ematch->e_list, &tree->et_list); +} + +static inline uint32_t container_ref(struct rtnl_ematch *ematch) +{ + return *((uint32_t *) rtnl_ematch_data(ematch)); +} + +static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos, + struct nl_list_head *root) +{ + struct rtnl_ematch *ematch; + int i; + + for (i = pos; i < nmatches; i++) { + ematch = index[i]; + + nl_list_add_tail(&ematch->e_list, root); + + if (ematch->e_kind == TCF_EM_CONTAINER) + link_tree(index, nmatches, container_ref(ematch), + &ematch->e_childs); + + if (!(ematch->e_flags & TCF_EM_REL_MASK)) + return 0; + } + + /* Last entry in chain can't possibly have no relation */ + return -NLE_INVAL; +} + +static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = { + [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) }, + [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED }, +}; + +/** + * Parse ematch netlink attributes + * + * @return 0 on success or a negative error code. + */ +int rtnl_ematch_parse(struct nlattr *attr, struct rtnl_ematch_tree **result) +{ + struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1]; + struct tcf_ematch_tree_hdr *thdr; + struct rtnl_ematch_tree *tree; + struct rtnl_ematch **index; + int nmatches = 0, err, remaining; + + err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy); + if (err < 0) + return err; + + if (!tb[TCA_EMATCH_TREE_HDR]) + return -NLE_MISSING_ATTR; + + thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]); + + /* Ignore empty trees */ + if (thdr->nmatches == 0) + return 0; + + if (!tb[TCA_EMATCH_TREE_LIST]) + return -NLE_MISSING_ATTR; + + if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) / + nla_total_size(sizeof(struct tcf_ematch_hdr)))) + return -NLE_INVAL; + + if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *)))) + return -NLE_NOMEM; + + if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) { + err = -NLE_NOMEM; + goto errout; + } + + nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) { + struct rtnl_ematch_ops *ops; + struct tcf_ematch_hdr *hdr; + struct rtnl_ematch *ematch; + void *data; + size_t len; + + if (nla_len(a) < sizeof(*hdr)) { + err = -NLE_INVAL; + goto errout; + } + + if (nmatches >= thdr->nmatches) { + err = -NLE_RANGE; + goto errout; + } + + hdr = nla_data(a); + data = nla_data(a) + NLA_ALIGN(sizeof(*hdr)); + len = nla_len(a) - NLA_ALIGN(sizeof(*hdr)); + + ops = rtnl_ematch_lookup_ops(hdr->kind); + if (ops && ops->eo_datalen && len < ops->eo_datalen) { + err = -NLE_INVAL; + goto errout; + } + + if (!(ematch = rtnl_ematch_alloc(ops))) { + err = -NLE_NOMEM; + goto errout; + } + + ematch->e_id = hdr->matchid; + ematch->e_kind = hdr->kind; + ematch->e_flags = hdr->flags; + + if (ops && (err = ops->eo_parse(ematch, data, len)) < 0) + goto errout; + + if (hdr->kind == TCF_EM_CONTAINER && + container_ref(ematch) >= thdr->nmatches) { + err = -NLE_INVAL; + goto errout; + } + + index[nmatches++] = ematch; + } + + if (nmatches != thdr->nmatches) { + err = -NLE_INVAL; + goto errout; + } + + err = link_tree(index, nmatches, 0, &tree->et_list); + if (err < 0) + goto errout; + + free(index); + *result = tree; + + return 0; + +errout: + rtnl_ematch_tree_free(tree); + free(index); + return err; +} + +static void dump_ematch_sequence(struct nl_list_head *head, + struct nl_dump_params *p) +{ + struct rtnl_ematch *match; + + nl_list_for_each_entry(match, head, e_list) { + if (match->e_flags & TCF_EM_INVERT) + nl_dump(p, "NOT "); + + if (match->e_kind == TCF_EM_CONTAINER) { + nl_dump(p, "("); + dump_ematch_sequence(&match->e_childs, p); + nl_dump(p, ")"); + } else if (!match->e_ops) { + nl_dump(p, "[unknown ematch %d]", match->e_kind); + } else { + nl_dump(p, "%s(", match->e_ops->eo_name); + + if (match->e_ops->eo_dump) + match->e_ops->eo_dump(match, p); + + nl_dump(p, ")"); + } + + switch (match->e_flags & TCF_EM_REL_MASK) { + case TCF_EM_REL_AND: + nl_dump(p, " AND "); + break; + case TCF_EM_REL_OR: + nl_dump(p, " OR "); + break; + default: + /* end of first level ematch sequence */ + return; + } + } +} + +void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree, + struct nl_dump_params *p) +{ + dump_ematch_sequence(&tree->et_list, p); + nl_dump(p, "\n"); +} + +/** @} */ + +/** @} */ diff --git a/lib/route/cls/ematch/cmp.c b/lib/route/cls/ematch/cmp.c new file mode 100644 index 0000000..ec25320 --- /dev/null +++ b/lib/route/cls/ematch/cmp.c @@ -0,0 +1,116 @@ +/* + * lib/route/cls/ematch/cmp.c Simple packet data comparison ematch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup ematch + * @defgroup em_cmp Simple packet data comparison + * + * @{ + */ + +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/route/cls/ematch.h> +#include <linux/tc_ematch/tc_em_cmp.h> + +void rtnl_ematch_cmp_set(struct rtnl_ematch *ematch, + struct tcf_em_cmp *cfg) +{ + memcpy(rtnl_ematch_data(ematch), cfg, sizeof(*cfg)); +} + +struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *ematch) +{ + return rtnl_ematch_data(ematch); +} + +static const char *align_txt(struct tcf_em_cmp *cmp) +{ + switch (cmp->align) { + case TCF_EM_ALIGN_U8: + return "u8"; + case TCF_EM_ALIGN_U16: + return (cmp->flags & TCF_EM_CMP_TRANS) ? "h16" : "u16"; + case TCF_EM_ALIGN_U32: + return (cmp->flags & TCF_EM_CMP_TRANS) ? "h32" : "u32"; + default: + return (cmp->flags & TCF_EM_CMP_TRANS) ? "h?" : "u?"; + } +} + +static const char *layer_txt(struct tcf_em_cmp *cmp) +{ + switch (cmp->layer) { + case TCF_LAYER_LINK: + return "link"; + case TCF_LAYER_NETWORK: + return "network"; + case TCF_LAYER_TRANSPORT: + return "transport"; + default: + return "?"; + } +} + +static const char *relation_txt(struct tcf_em_cmp *cmp) +{ + switch (cmp->opnd) { + case TCF_EM_OPND_EQ: + return "eq"; + case TCF_EM_OPND_LT: + return "lt"; + case TCF_EM_OPND_GT: + return "gt"; + default: + return "?"; + } +} + +static int cmp_parse(struct rtnl_ematch *m, void *data, size_t len) +{ + memcpy(rtnl_ematch_data(m), data, len); + + return 0; +} + +static void cmp_dump(struct rtnl_ematch *m, struct nl_dump_params *p) +{ + struct tcf_em_cmp *cmp = rtnl_ematch_data(m); + + nl_dump(p, "%s at %s+%u ", + align_txt(cmp), layer_txt(cmp), cmp->off); + + if (cmp->mask) + nl_dump(p, "& 0x%x ", cmp->mask); + + nl_dump(p, "%s %u", relation_txt(cmp), cmp->val); +} + +static struct rtnl_ematch_ops cmp_ops = { + .eo_kind = TCF_EM_CMP, + .eo_name = "cmp", + .eo_datalen = sizeof(struct tcf_em_cmp), + .eo_parse = cmp_parse, + .eo_dump = cmp_dump, +}; + +static void __init cmp_init(void) +{ + rtnl_ematch_register(&cmp_ops); +} + +static void __exit cmp_exit(void) +{ + rtnl_ematch_unregister(&cmp_ops); +} + +/** @} */ diff --git a/lib/route/cls/ematch/container.c b/lib/route/cls/ematch/container.c new file mode 100644 index 0000000..54d836f --- /dev/null +++ b/lib/route/cls/ematch/container.c @@ -0,0 +1,39 @@ +/* + * lib/route/cls/ematch/container.c Container Ematch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/route/cls/ematch.h> + +static int container_parse(struct rtnl_ematch *m, void *data, size_t len) +{ + memcpy(m->e_data, data, sizeof(uint32_t)); + + return 0; +} + +static struct rtnl_ematch_ops container_ops = { + .eo_kind = TCF_EM_CONTAINER, + .eo_name = "container", + .eo_datalen = sizeof(uint32_t), + .eo_parse = container_parse, +}; + +static void __init container_init(void) +{ + rtnl_ematch_register(&container_ops); +} + +static void __exit container_exit(void) +{ + rtnl_ematch_unregister(&container_ops); +} diff --git a/lib/route/cls/fw.c b/lib/route/cls/fw.c index 7ca7619..8cf25b9 100644 --- a/lib/route/cls/fw.c +++ b/lib/route/cls/fw.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com> * Copyright (c) 2006 Siemens AG Oesterreich */ @@ -32,19 +32,6 @@ #define FW_ATTR_INDEV 0x008 /** @endcond */ -static inline struct rtnl_fw *fw_cls(struct rtnl_cls *cls) -{ - return (struct rtnl_fw *) cls->c_subdata; -} - -static inline struct rtnl_fw *fw_alloc(struct rtnl_cls *cls) -{ - if (!cls->c_subdata) - cls->c_subdata = calloc(1, sizeof(struct rtnl_fw)); - - return fw_cls(cls); -} - static struct nla_policy fw_policy[TCA_FW_MAX+1] = { [TCA_FW_CLASSID] = { .type = NLA_U32 }, [TCA_FW_INDEV] = { .type = NLA_STRING, @@ -53,34 +40,30 @@ static struct nla_policy fw_policy[TCA_FW_MAX+1] = { static int fw_msg_parser(struct rtnl_cls *cls) { - int err; + struct rtnl_fw *f = rtnl_cls_data(cls); struct nlattr *tb[TCA_FW_MAX + 1]; - struct rtnl_fw *f; + int err; err = tca_parse(tb, TCA_FW_MAX, (struct rtnl_tca *) cls, fw_policy); if (err < 0) return err; - f = fw_alloc(cls); - if (!f) - goto errout_nomem; - if (tb[TCA_FW_CLASSID]) { f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]); f->cf_mask |= FW_ATTR_CLASSID; } if (tb[TCA_FW_ACT]) { - f->cf_act = nla_get_data(tb[TCA_FW_ACT]); + f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]); if (!f->cf_act) - goto errout_nomem; + return -NLE_NOMEM; f->cf_mask |= FW_ATTR_ACTION; } if (tb[TCA_FW_POLICE]) { - f->cf_police = nla_get_data(tb[TCA_FW_POLICE]); + f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]); if (!f->cf_police) - goto errout_nomem; + return -NLE_NOMEM; f->cf_mask |= FW_ATTR_POLICE; } @@ -90,120 +73,68 @@ static int fw_msg_parser(struct rtnl_cls *cls) } return 0; - -errout_nomem: - err = nl_errno(ENOMEM); - - return err; } static void fw_free_data(struct rtnl_cls *cls) { - struct rtnl_fw *f = fw_cls(cls); - - if (!f) - return; + struct rtnl_fw *f = rtnl_cls_data(cls); nl_data_free(f->cf_act); nl_data_free(f->cf_police); - - free(cls->c_subdata); } static int fw_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) { - struct rtnl_fw *dst, *src = fw_cls(_src); - - if (!src) - return 0; + struct rtnl_fw *dst = rtnl_cls_data(_dst); + struct rtnl_fw *src = rtnl_cls_data(_src); - dst = fw_alloc(_dst); - if (!dst) - return nl_errno(ENOMEM); - - if (src->cf_act) - if (!(dst->cf_act = nl_data_clone(src->cf_act))) - goto errout; + if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act))) + return -NLE_NOMEM; - if (src->cf_police) - if (!(dst->cf_police = nl_data_clone(src->cf_police))) - goto errout; + if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police))) + return -NLE_NOMEM; return 0; -errout: - return nl_get_errno(); } -static int fw_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p, - int line) +static void fw_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) { - struct rtnl_fw *f = fw_cls(cls); + struct rtnl_fw *f = rtnl_cls_data(cls); char buf[32]; - if (!f) - goto ignore; - if (f->cf_mask & FW_ATTR_CLASSID) - dp_dump(p, " target %s", + nl_dump(p, " target %s", rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf))); - -ignore: - return line; } -static int fw_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p, - int line) +static void fw_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) { - struct rtnl_fw *f = fw_cls(cls); - - if (!f) - goto ignore; + struct rtnl_fw *f = rtnl_cls_data(cls); if (f->cf_mask & FW_ATTR_INDEV) - dp_dump(p, "indev %s ", f->cf_indev); - -ignore: - return line; + nl_dump(p, "indev %s ", f->cf_indev); } -static int fw_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p, - int line) +static int fw_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) { - struct rtnl_fw *f = fw_cls(cls); - - if (!f) - goto ignore; - -ignore: - return line; -} - -static struct nl_msg *fw_get_opts(struct rtnl_cls *cls) -{ - struct rtnl_fw *f; - struct nl_msg *msg; + struct rtnl_fw *f = rtnl_cls_data(cls); - f = fw_cls(cls); - if (!f) - return NULL; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - if (f->cf_mask & FW_ATTR_CLASSID) - nla_put_u32(msg, TCA_FW_CLASSID, f->cf_classid); + NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid); if (f->cf_mask & FW_ATTR_ACTION) - nla_put_data(msg, TCA_FW_ACT, f->cf_act); + NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act); if (f->cf_mask & FW_ATTR_POLICE) - nla_put_data(msg, TCA_FW_POLICE, f->cf_police); + NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police); if (f->cf_mask & FW_ATTR_INDEV) - nla_put_string(msg, TCA_FW_INDEV, f->cf_indev); + NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev); - return msg; + return 0; + +nla_put_failure: + return -NLE_NOMEM; } /** @@ -213,12 +144,8 @@ static struct nl_msg *fw_get_opts(struct rtnl_cls *cls) int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid) { - struct rtnl_fw *f; + struct rtnl_fw *f = rtnl_cls_data(cls); - f = fw_alloc(cls); - if (!f) - return nl_errno(ENOMEM); - f->cf_classid = classid; f->cf_mask |= FW_ATTR_CLASSID; @@ -229,13 +156,15 @@ int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid) static struct rtnl_cls_ops fw_ops = { .co_kind = "fw", + .co_size = sizeof(struct rtnl_fw), .co_msg_parser = fw_msg_parser, .co_free_data = fw_free_data, .co_clone = fw_clone, .co_get_opts = fw_get_opts, - .co_dump[NL_DUMP_BRIEF] = fw_dump_brief, - .co_dump[NL_DUMP_FULL] = fw_dump_full, - .co_dump[NL_DUMP_STATS] = fw_dump_stats, + .co_dump = { + [NL_DUMP_LINE] = fw_dump_line, + [NL_DUMP_DETAILS] = fw_dump_details, + }, }; static void __init fw_init(void) diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c index 596e63f..80b8851 100644 --- a/lib/route/cls/u32.c +++ b/lib/route/cls/u32.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com> * Copyright (c) 2005-2006 Siemens AG Oesterreich */ @@ -40,19 +40,6 @@ #define U32_ATTR_INDEV 0x100 /** @endcond */ -static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls) -{ - return (struct rtnl_u32 *) cls->c_subdata; -} - -static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls) -{ - if (!cls->c_subdata) - cls->c_subdata = calloc(1, sizeof(struct rtnl_u32)); - - return u32_cls(cls); -} - static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u) { return (struct tc_u32_sel *) u->cu_selector->d_data; @@ -79,25 +66,21 @@ static struct nla_policy u32_policy[TCA_U32_MAX+1] = { static int u32_msg_parser(struct rtnl_cls *cls) { - int err; + struct rtnl_u32 *u = rtnl_cls_data(cls); struct nlattr *tb[TCA_U32_MAX + 1]; - struct rtnl_u32 *u; + int err; err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy); if (err < 0) return err; - u = u32_alloc(cls); - if (!u) - goto errout_nomem; - if (tb[TCA_U32_DIVISOR]) { u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); u->cu_mask |= U32_ATTR_DIVISOR; } if (tb[TCA_U32_SEL]) { - u->cu_selector = nla_get_data(tb[TCA_U32_SEL]); + u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]); if (!u->cu_selector) goto errout_nomem; u->cu_mask |= U32_ATTR_SELECTOR; @@ -119,14 +102,14 @@ static int u32_msg_parser(struct rtnl_cls *cls) } if (tb[TCA_U32_ACT]) { - u->cu_act = nla_get_data(tb[TCA_U32_ACT]); + u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]); if (!u->cu_act) goto errout_nomem; u->cu_mask |= U32_ATTR_ACTION; } if (tb[TCA_U32_POLICE]) { - u->cu_police = nla_get_data(tb[TCA_U32_POLICE]); + u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]); if (!u->cu_police) goto errout_nomem; u->cu_mask |= U32_ATTR_POLICE; @@ -137,8 +120,7 @@ static int u32_msg_parser(struct rtnl_cls *cls) int pcnt_size; if (!tb[TCA_U32_SEL]) { - err = nl_error(EINVAL, "Missing TCA_U32_SEL required " - "for TCA_U32_PCNT"); + err = -NLE_MISSING_ATTR; goto errout; } @@ -146,11 +128,11 @@ static int u32_msg_parser(struct rtnl_cls *cls) pcnt_size = sizeof(struct tc_u32_pcnt) + (sel->nkeys * sizeof(uint64_t)); if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) { - err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT"); + err = -NLE_INVAL; goto errout; } - u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]); + u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]); if (!u->cu_pcnt) goto errout_nomem; u->cu_mask |= U32_ATTR_PCNT; @@ -164,79 +146,56 @@ static int u32_msg_parser(struct rtnl_cls *cls) return 0; errout_nomem: - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; errout: return err; } static void u32_free_data(struct rtnl_cls *cls) { - struct rtnl_u32 *u = u32_cls(cls); - - if (!u) - return; + struct rtnl_u32 *u = rtnl_cls_data(cls); nl_data_free(u->cu_selector); nl_data_free(u->cu_act); nl_data_free(u->cu_police); nl_data_free(u->cu_pcnt); - - free(cls->c_subdata); } static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) { - struct rtnl_u32 *dst, *src = u32_cls(_src); + struct rtnl_u32 *dst = rtnl_cls_data(_dst); + struct rtnl_u32 *src = rtnl_cls_data(_src); - if (!src) - return 0; + if (src->cu_selector && + !(dst->cu_selector = nl_data_clone(src->cu_selector))) + return -NLE_NOMEM; - dst = u32_alloc(_dst); - if (!dst) - return nl_errno(ENOMEM); + if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act))) + return -NLE_NOMEM; - if (src->cu_selector) - if (!(dst->cu_selector = nl_data_clone(src->cu_selector))) - goto errout; - - if (src->cu_act) - if (!(dst->cu_act = nl_data_clone(src->cu_act))) - goto errout; - - if (src->cu_police) - if (!(dst->cu_police = nl_data_clone(src->cu_police))) - goto errout; + if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police))) + return -NLE_NOMEM; - if (src->cu_pcnt) - if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt))) - goto errout; + if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt))) + return -NLE_NOMEM; return 0; -errout: - return nl_get_errno(); } -static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p, - int line) +static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) { - struct rtnl_u32 *u = u32_cls(cls); + struct rtnl_u32 *u = rtnl_cls_data(cls); char buf[32]; - if (!u) - goto ignore; - if (u->cu_mask & U32_ATTR_DIVISOR) - dp_dump(p, " divisor %u", u->cu_divisor); + nl_dump(p, " divisor %u", u->cu_divisor); else if (u->cu_mask & U32_ATTR_CLASSID) - dp_dump(p, " target %s", + nl_dump(p, " target %s", rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf))); - -ignore: - return line; } -static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, - struct rtnl_cls *cls, struct rtnl_u32 *u, int line) +static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, + struct rtnl_cls *cls, struct rtnl_u32 *u) { int i; struct tc_u32_key *key; @@ -246,23 +205,23 @@ static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, * exports the selector if no divisor is set but hash offset * and hash mask make only sense in hash filters with divisor * set */ - dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask); + nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask); } if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) { - dp_dump(p, " offset at %u", sel->off); + nl_dump(p, " offset at %u", sel->off); if (sel->flags & TC_U32_VAROFFSET) - dp_dump(p, " variable (at %u & 0x%x) >> %u", + nl_dump(p, " variable (at %u & 0x%x) >> %u", sel->offoff, ntohs(sel->offmask), sel->offshift); } if (sel->flags) { int flags = sel->flags; - dp_dump(p, " <"); + nl_dump(p, " <"); #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \ - flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); } + flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); } PRINT_FLAG(TERMINAL); PRINT_FLAG(OFFSET); @@ -270,66 +229,56 @@ static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, PRINT_FLAG(EAT); #undef PRINT_FLAG - dp_dump(p, ">"); + nl_dump(p, ">"); } for (i = 0; i < sel->nkeys; i++) { key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i; - dp_dump(p, "\n"); - dp_dump_line(p, line++, " match key at %s%u ", - key->offmask ? "nexthdr+" : "", key->off); + nl_dump(p, "\n"); + nl_dump_line(p, " match key at %s%u ", + key->offmask ? "nexthdr+" : "", key->off); if (key->offmask) - dp_dump(p, "[0x%u] ", key->offmask); + nl_dump(p, "[0x%u] ", key->offmask); - dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val)); + nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val)); if (p->dp_type == NL_DUMP_STATS && (u->cu_mask & U32_ATTR_PCNT)) { struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data; - dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]); + nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]); } } - - return line; } - -static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p, - int line) +static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) { - struct rtnl_u32 *u = u32_cls(cls); + struct rtnl_u32 *u = rtnl_cls_data(cls); struct tc_u32_sel *s; - if (!u) - goto ignore; - if (!(u->cu_mask & U32_ATTR_SELECTOR)) { - dp_dump(p, "no-selector\n"); - return line; + nl_dump(p, "no-selector\n"); + return; } s = u->cu_selector->d_data; - dp_dump(p, "nkeys %u ", s->nkeys); + nl_dump(p, "nkeys %u ", s->nkeys); if (u->cu_mask & U32_ATTR_HASH) - dp_dump(p, "ht key 0x%x hash 0x%u", + nl_dump(p, "ht key 0x%x hash 0x%u", TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash)); if (u->cu_mask & U32_ATTR_LINK) - dp_dump(p, "link %u ", u->cu_link); + nl_dump(p, "link %u ", u->cu_link); if (u->cu_mask & U32_ATTR_INDEV) - dp_dump(p, "indev %s ", u->cu_indev); - - line = print_selector(p, s, cls, u, line); - dp_dump(p, "\n"); + nl_dump(p, "indev %s ", u->cu_indev); -ignore: - return line; + print_selector(p, s, cls, u); + nl_dump(p, "\n"); #if 0 #define U32_ATTR_ACTION 0x040 @@ -340,64 +289,50 @@ ignore: #endif } -static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p, - int line) +static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p) { - struct rtnl_u32 *u = u32_cls(cls); - - if (!u) - goto ignore; + struct rtnl_u32 *u = rtnl_cls_data(cls); if (u->cu_mask & U32_ATTR_PCNT) { struct tc_u32_pcnt *pc = u->cu_pcnt->d_data; - dp_dump(p, "\n"); - dp_dump_line(p, line++, "%s successful hits\n"); - dp_dump_line(p, line++, "%s %8llu %8llu\n", + nl_dump(p, "\n"); + nl_dump_line(p, " hit %8llu count %8llu\n", pc->rhit, pc->rcnt); } - -ignore: - return line; } -static struct nl_msg *u32_get_opts(struct rtnl_cls *cls) +static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) { - struct rtnl_u32 *u; - struct nl_msg *msg; + struct rtnl_u32 *u = rtnl_cls_data(cls); - u = u32_cls(cls); - if (!u) - return NULL; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - if (u->cu_mask & U32_ATTR_DIVISOR) - nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor); + NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor); if (u->cu_mask & U32_ATTR_HASH) - nla_put_u32(msg, TCA_U32_HASH, u->cu_hash); + NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash); if (u->cu_mask & U32_ATTR_CLASSID) - nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid); + NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid); if (u->cu_mask & U32_ATTR_LINK) - nla_put_u32(msg, TCA_U32_LINK, u->cu_link); + NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link); if (u->cu_mask & U32_ATTR_SELECTOR) - nla_put_data(msg, TCA_U32_SEL, u->cu_selector); + NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector); if (u->cu_mask & U32_ATTR_ACTION) - nla_put_data(msg, TCA_U32_ACT, u->cu_act); + NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act); if (u->cu_mask & U32_ATTR_POLICE) - nla_put_data(msg, TCA_U32_POLICE, u->cu_police); + NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police); if (u->cu_mask & U32_ATTR_INDEV) - nla_put_string(msg, TCA_U32_INDEV, u->cu_indev); + NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev); - return msg; + return 0; + +nla_put_failure: + return -NLE_NOMEM; } /** @@ -415,12 +350,8 @@ void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash, int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) { - struct rtnl_u32 *u; + struct rtnl_u32 *u = rtnl_cls_data(cls); - u = u32_alloc(cls); - if (!u) - return nl_errno(ENOMEM); - u->cu_classid = classid; u->cu_mask |= U32_ATTR_CLASSID; @@ -437,15 +368,11 @@ int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags) { struct tc_u32_sel *sel; - struct rtnl_u32 *u; - - u = u32_alloc(cls); - if (!u) - return nl_errno(ENOMEM); + struct rtnl_u32 *u = rtnl_cls_data(cls); sel = u32_selector_alloc(u); if (!sel) - return nl_errno(ENOMEM); + return -NLE_NOMEM; sel->flags |= flags; u->cu_mask |= U32_ATTR_SELECTOR; @@ -471,16 +398,12 @@ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask) { struct tc_u32_sel *sel; - struct rtnl_u32 *u; + struct rtnl_u32 *u = rtnl_cls_data(cls); int err; - u = u32_alloc(cls); - if (!u) - return nl_errno(ENOMEM); - sel = u32_selector_alloc(u); if (!sel) - return nl_errno(ENOMEM); + return -NLE_NOMEM; err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); if (err < 0) @@ -523,7 +446,7 @@ int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask, { int shift = ((off & 3) == 0 ? 16 : 0); if (off % 2) - return nl_error(EINVAL, "Invalid offset alignment"); + return -NLE_INVAL; return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), htonl((uint32_t)mask << shift), @@ -580,13 +503,16 @@ int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr, static struct rtnl_cls_ops u32_ops = { .co_kind = "u32", + .co_size = sizeof(struct rtnl_u32), .co_msg_parser = u32_msg_parser, .co_free_data = u32_free_data, .co_clone = u32_clone, .co_get_opts = u32_get_opts, - .co_dump[NL_DUMP_BRIEF] = u32_dump_brief, - .co_dump[NL_DUMP_FULL] = u32_dump_full, - .co_dump[NL_DUMP_STATS] = u32_dump_stats, + .co_dump = { + [NL_DUMP_LINE] = u32_dump_line, + [NL_DUMP_DETAILS] = u32_dump_details, + [NL_DUMP_STATS] = u32_dump_stats, + }, }; static void __init u32_init(void) diff --git a/lib/route/cls_api.c b/lib/route/cls_api.c index f5a083a..73f05df 100644 --- a/lib/route/cls_api.c +++ b/lib/route/cls_api.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -44,7 +44,7 @@ int rtnl_cls_register(struct rtnl_cls_ops *cops) for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next) if (!strcasecmp(cops->co_kind, o->co_kind)) - return nl_errno(EEXIST); + return -NLE_EXIST; cops->co_next = NULL; *op = cops; @@ -65,7 +65,7 @@ int rtnl_cls_unregister(struct rtnl_cls_ops *cops) break; if (!o) - return nl_errno(ENOENT); + return -NLE_OBJ_NOTFOUND; *op = cops->co_next; diff --git a/lib/route/cls_obj.c b/lib/route/cls_obj.c index e12bc95..c8218c0 100644 --- a/lib/route/cls_obj.c +++ b/lib/route/cls_obj.c @@ -39,6 +39,8 @@ static void cls_free_data(struct nl_object *obj) cops = rtnl_cls_lookup_ops(cls); if (cops && cops->co_free_data) cops->co_free_data(cls); + + nl_data_free(cls->c_subdata); } static int cls_clone(struct nl_object *_dst, struct nl_object *_src) @@ -52,6 +54,13 @@ static int cls_clone(struct nl_object *_dst, struct nl_object *_src) if (err < 0) goto errout; + if (src->c_subdata) { + if (!(dst->c_subdata = nl_data_clone(src->c_subdata))) { + err = -NLE_NOMEM; + goto errout; + } + } + cops = rtnl_cls_lookup_ops(src); if (cops && cops->co_clone) err = cops->co_clone(dst, src); @@ -59,59 +68,50 @@ errout: return err; } -static int cls_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void cls_dump_line(struct nl_object *obj, struct nl_dump_params *p) { char buf[32]; struct rtnl_cls *cls = (struct rtnl_cls *) obj; struct rtnl_cls_ops *cops; - int line; - line = tca_dump_brief((struct rtnl_tca *) cls, "cls", p, 0); + tca_dump_line((struct rtnl_tca *) cls, "cls", p); - dp_dump(p, " prio %u protocol %s", cls->c_prio, + nl_dump(p, " prio %u protocol %s", cls->c_prio, nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf))); cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_dump[NL_DUMP_BRIEF]) - line = cops->co_dump[NL_DUMP_BRIEF](cls, p, line); - dp_dump(p, "\n"); - - return line; + if (cops && cops->co_dump[NL_DUMP_LINE]) + cops->co_dump[NL_DUMP_LINE](cls, p); + nl_dump(p, "\n"); } -static int cls_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void cls_dump_details(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_cls *cls = (struct rtnl_cls *) obj; struct rtnl_cls_ops *cops; - int line; - line = cls_dump_brief(obj, p); - line = tca_dump_full((struct rtnl_tca *) cls, p, line); + cls_dump_line(obj, p); + tca_dump_details((struct rtnl_tca *) cls, p); cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_dump[NL_DUMP_FULL]) - line = cops->co_dump[NL_DUMP_FULL](cls, p, line); + if (cops && cops->co_dump[NL_DUMP_DETAILS]) + cops->co_dump[NL_DUMP_DETAILS](cls, p); else - dp_dump(p, "no options\n"); - - return line; + nl_dump(p, "no options\n"); } -static int cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +static void cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_cls *cls = (struct rtnl_cls *) obj; struct rtnl_cls_ops *cops; - int line; - line = cls_dump_full(obj, p); - line = tca_dump_stats((struct rtnl_tca *) cls, p, line); - dp_dump(p, "\n"); + cls_dump_details(obj, p); + tca_dump_stats((struct rtnl_tca *) cls, p); + nl_dump(p, "\n"); cops = rtnl_cls_lookup_ops(cls); if (cops && cops->co_dump[NL_DUMP_STATS]) - line = cops->co_dump[NL_DUMP_STATS](cls, p, line); - - return line; + cops->co_dump[NL_DUMP_STATS](cls, p); } /** @@ -142,6 +142,11 @@ void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex) tca_set_ifindex((struct rtnl_tca *) f, ifindex); } +int rtnl_cls_get_ifindex(struct rtnl_cls *cls) +{ + return cls->c_ifindex; +} + void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle) { tca_set_handle((struct rtnl_tca *) f, handle); @@ -152,19 +157,36 @@ void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent) tca_set_parent((struct rtnl_tca *) f, parent); } -void rtnl_cls_set_kind(struct rtnl_cls *f, const char *kind) +uint32_t rtnl_cls_get_parent(struct rtnl_cls *cls) +{ + return cls->c_parent; +} + +int rtnl_cls_set_kind(struct rtnl_cls *cls, const char *kind) +{ + if (cls->ce_mask & TCA_ATTR_KIND) + return -NLE_EXIST; + + tca_set_kind((struct rtnl_tca *) cls, kind); + + /* Force allocation of data */ + rtnl_cls_data(cls); + + return 0; +} + +struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *cls) { - tca_set_kind((struct rtnl_tca *) f, kind); - f->c_ops = __rtnl_cls_lookup_ops(kind); + return cls->c_ops; } -void rtnl_cls_set_prio(struct rtnl_cls *cls, int prio) +void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio) { cls->c_prio = prio; cls->ce_mask |= CLS_ATTR_PRIO; } -int rtnl_cls_get_prio(struct rtnl_cls *cls) +uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls) { if (cls->ce_mask & CLS_ATTR_PRIO) return cls->c_prio; @@ -172,13 +194,13 @@ int rtnl_cls_get_prio(struct rtnl_cls *cls) return 0; } -void rtnl_cls_set_protocol(struct rtnl_cls *cls, int protocol) +void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol) { cls->c_protocol = protocol; cls->ce_mask |= CLS_ATTR_PROTOCOL; } -int rtnl_cls_get_protocol(struct rtnl_cls *cls) +uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls) { if (cls->ce_mask & CLS_ATTR_PROTOCOL) return cls->c_protocol; @@ -186,6 +208,32 @@ int rtnl_cls_get_protocol(struct rtnl_cls *cls) return ETH_P_ALL; } +void *rtnl_cls_data(struct rtnl_cls *cls) +{ + if (!cls->c_subdata) { + struct rtnl_cls_ops *ops = cls->c_ops; + + if (!ops) { + if (!cls->c_kind[0]) + BUG(); + + ops = __rtnl_cls_lookup_ops(cls->c_kind); + if (ops == NULL) + return NULL; + + cls->c_ops = ops; + } + + if (!ops->co_size) + BUG(); + + if (!(cls->c_subdata = nl_data_alloc(NULL, ops->co_size))) + return NULL; + } + + return nl_data_get(cls->c_subdata); +} + /** @} */ struct nl_object_ops cls_obj_ops = { @@ -193,9 +241,11 @@ struct nl_object_ops cls_obj_ops = { .oo_size = sizeof(struct rtnl_cls), .oo_free_data = cls_free_data, .oo_clone = cls_clone, - .oo_dump[NL_DUMP_BRIEF] = cls_dump_brief, - .oo_dump[NL_DUMP_FULL] = cls_dump_full, - .oo_dump[NL_DUMP_STATS] = cls_dump_stats, + .oo_dump = { + [NL_DUMP_LINE] = cls_dump_line, + [NL_DUMP_DETAILS] = cls_dump_details, + [NL_DUMP_STATS] = cls_dump_stats, + }, .oo_compare = tca_compare, .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), }; diff --git a/lib/route/link.c b/lib/route/link.c index ab89c24..cf488e5 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -78,7 +78,7 @@ * @code * // The first step is to retrieve a list of all available interfaces within * // the kernel and put them into a cache. - * struct nl_cache *cache = rtnl_link_alloc_cache(nl_handle); + * struct nl_cache *cache = rtnl_link_alloc_cache(sk); * * // In a second step, a specific link may be looked up by either interface * // index or interface name. @@ -112,12 +112,12 @@ * // Two ways exist to commit this change request, the first one is to * // build the required netlink message and send it out in one single * // step: - * rtnl_link_change(nl_handle, old, request); + * rtnl_link_change(sk, old, request); * * // An alternative way is to build the netlink message and send it * // out yourself using nl_send_auto_complete() * struct nl_msg *msg = rtnl_link_build_change_request(old, request); - * nl_send_auto_complete(nl_handle, nlmsg_hdr(msg)); + * nl_send_auto_complete(sk, nlmsg_hdr(msg)); * nlmsg_free(msg); * * // Don't forget to give back the link object ;-> @@ -215,21 +215,19 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src) if (src->l_addr) if (!(dst->l_addr = nl_addr_clone(src->l_addr))) - goto errout; + return -NLE_NOMEM; if (src->l_bcast) if (!(dst->l_bcast = nl_addr_clone(src->l_bcast))) - goto errout; + return -NLE_NOMEM; if (src->l_info_ops && src->l_info_ops->io_clone) { err = src->l_info_ops->io_clone(dst, src); if (err < 0) - goto errout; + return err; } return 0; -errout: - return nl_get_errno(); } static struct nla_policy link_policy[IFLA_MAX+1] = { @@ -265,7 +263,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, link = rtnl_link_alloc(); if (link == NULL) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -276,7 +274,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, goto errout; if (tb[IFLA_IFNAME] == NULL) { - err = nl_error(EINVAL, "Missing link name TLV"); + err = -NLE_MISSING_ATTR; goto errout; } @@ -332,18 +330,23 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } if (tb[IFLA_ADDRESS]) { - link->l_addr = nla_get_addr(tb[IFLA_ADDRESS], AF_UNSPEC); - if (link->l_addr == NULL) + link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC); + if (link->l_addr == NULL) { + err = -NLE_NOMEM; goto errout; + } nl_addr_set_family(link->l_addr, nl_addr_guess_family(link->l_addr)); link->ce_mask |= LINK_ATTR_ADDR; } if (tb[IFLA_BROADCAST]) { - link->l_bcast = nla_get_addr(tb[IFLA_BROADCAST], AF_UNSPEC); - if (link->l_bcast == NULL) + link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST], + AF_UNSPEC); + if (link->l_bcast == NULL) { + err = -NLE_NOMEM; goto errout; + } nl_addr_set_family(link->l_bcast, nl_addr_guess_family(link->l_bcast)); link->ce_mask |= LINK_ATTR_BRD; @@ -365,13 +368,8 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } if (tb[IFLA_MAP]) { - struct rtnl_link_ifmap *map = nla_data(tb[IFLA_MAP]); - link->l_map.lm_mem_start = map->mem_start; - link->l_map.lm_mem_end = map->mem_end; - link->l_map.lm_base_addr = map->base_addr; - link->l_map.lm_irq = map->irq; - link->l_map.lm_dma = map->dma; - link->l_map.lm_port = map->port; + nla_memcpy(&link->l_map, tb[IFLA_MAP], + sizeof(struct rtnl_link_ifmap)); link->ce_mask |= LINK_ATTR_MAP; } @@ -419,125 +417,109 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } err = pp->pp_cb((struct nl_object *) link, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; - errout: rtnl_link_put(link); return err; } -static int link_request_update(struct nl_cache *c, struct nl_handle *h) +static int link_request_update(struct nl_cache *cache, struct nl_sock *sk) { - return nl_rtgen_request(h, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); + return nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); } -static int link_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p) { char buf[128]; struct nl_cache *cache = dp_cache(obj); struct rtnl_link *link = (struct rtnl_link *) obj; - int line = 1; - dp_dump(p, "%s %s ", link->l_name, - nl_llproto2str(link->l_arptype, buf, sizeof(buf))); + nl_dump_line(p, "%s %s ", link->l_name, + nl_llproto2str(link->l_arptype, buf, sizeof(buf))); if (link->l_addr && !nl_addr_iszero(link->l_addr)) - dp_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); + nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf))); if (link->ce_mask & LINK_ATTR_MASTER) { struct rtnl_link *master = rtnl_link_get(cache, link->l_master); - dp_dump(p, "master %s ", master ? master->l_name : "inv"); + nl_dump(p, "master %s ", master ? master->l_name : "inv"); if (master) rtnl_link_put(master); } rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); if (buf[0]) - dp_dump(p, "<%s> ", buf); + nl_dump(p, "<%s> ", buf); if (link->ce_mask & LINK_ATTR_LINK) { struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); - dp_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); + nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE"); if (ll) rtnl_link_put(ll); } - if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_BRIEF]) - line = link->l_info_ops->io_dump[NL_DUMP_BRIEF](link, p, line); - - dp_dump(p, "\n"); + if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE]) + link->l_info_ops->io_dump[NL_DUMP_LINE](link, p); - return line; + nl_dump(p, "\n"); } -static int link_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_link *link = (struct rtnl_link *) obj; char buf[64]; - int line; - line = link_dump_brief(obj, p); - dp_new_line(p, line++); + link_dump_line(obj, p); - dp_dump(p, " mtu %u ", link->l_mtu); - dp_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); + nl_dump_line(p, " mtu %u ", link->l_mtu); + nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight); if (link->ce_mask & LINK_ATTR_QDISC) - dp_dump(p, "qdisc %s ", link->l_qdisc); + nl_dump(p, "qdisc %s ", link->l_qdisc); if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq) - dp_dump(p, "irq %u ", link->l_map.lm_irq); + nl_dump(p, "irq %u ", link->l_map.lm_irq); if (link->ce_mask & LINK_ATTR_IFINDEX) - dp_dump(p, "index %u ", link->l_index); - + nl_dump(p, "index %u ", link->l_index); - dp_dump(p, "\n"); - dp_new_line(p, line++); - dp_dump(p, " "); + nl_dump(p, "\n"); + nl_dump_line(p, " "); if (link->ce_mask & LINK_ATTR_BRD) - dp_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, + nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf, sizeof(buf))); if ((link->ce_mask & LINK_ATTR_OPERSTATE) && link->l_operstate != IF_OPER_UNKNOWN) { rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf)); - dp_dump(p, "state %s ", buf); + nl_dump(p, "state %s ", buf); } - dp_dump(p, "mode %s\n", + nl_dump(p, "mode %s\n", rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf))); - if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_FULL]) - line = link->l_info_ops->io_dump[NL_DUMP_FULL](link, p, line); - - return line; + if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS]) + link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p); } -static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_link *link = (struct rtnl_link *) obj; char *unit, fmt[64]; float res; - int line; - line = link_dump_full(obj, p); + link_dump_details(obj, p); - dp_dump_line(p, line++, " Stats: bytes packets errors " - " dropped fifo-err compressed\n"); + nl_dump_line(p, " Stats: bytes packets errors " + " dropped fifo-err compressed\n"); res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit); - strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); + strcpy(fmt, " RX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); fmt[9] = *unit == 'B' ? '9' : '7'; - dp_dump_line(p, line++, fmt, - res, unit, + nl_dump_line(p, fmt, res, unit, link->l_stats[RTNL_LINK_RX_PACKETS], link->l_stats[RTNL_LINK_RX_ERRORS], link->l_stats[RTNL_LINK_RX_DROPPED], @@ -546,21 +528,20 @@ static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit); - strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); + strcpy(fmt, " TX %X.2f %s %10llu %10llu %10llu %10llu %10llu\n"); fmt[9] = *unit == 'B' ? '9' : '7'; - dp_dump_line(p, line++, fmt, - res, unit, + nl_dump_line(p, fmt, res, unit, link->l_stats[RTNL_LINK_TX_PACKETS], link->l_stats[RTNL_LINK_TX_ERRORS], link->l_stats[RTNL_LINK_TX_DROPPED], link->l_stats[RTNL_LINK_TX_FIFO_ERR], link->l_stats[RTNL_LINK_TX_COMPRESSED]); - dp_dump_line(p, line++, " Errors: length over crc " - " frame missed multicast\n"); + nl_dump_line(p, " Errors: length over crc " + " frame missed multicast\n"); - dp_dump_line(p, line++, " RX %10" PRIu64 " %10" PRIu64 " %10" + nl_dump_line(p, " RX %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", link->l_stats[RTNL_LINK_RX_LEN_ERR], @@ -570,11 +551,11 @@ static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) link->l_stats[RTNL_LINK_RX_MISSED_ERR], link->l_stats[RTNL_LINK_MULTICAST]); - dp_dump_line(p, line++, " Errors: aborted carrier heartbeat " - " window collision\n"); + nl_dump_line(p, " aborted carrier heartbeat " + " window collision\n"); - dp_dump_line(p, line++, " TX %10" PRIu64 " %10" PRIu64 " %10" - PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", + nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10" + PRIu64 " %10" PRIu64 " %10" PRIu64 "\n", link->l_stats[RTNL_LINK_TX_ABORT_ERR], link->l_stats[RTNL_LINK_TX_CARRIER_ERR], link->l_stats[RTNL_LINK_TX_HBEAT_ERR], @@ -582,132 +563,56 @@ static int link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) link->l_stats[RTNL_LINK_TX_COLLISIONS]); if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) - line = link->l_info_ops->io_dump[NL_DUMP_STATS](link, p, line); - - return line; + link->l_info_ops->io_dump[NL_DUMP_STATS](link, p); } -static int link_dump_xml(struct nl_object *obj, struct nl_dump_params *p) +static void link_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_link *link = (struct rtnl_link *) obj; struct nl_cache *cache = dp_cache(obj); char buf[128]; - int i, line = 0; + int i; - dp_dump_line(p, line++, "<link name=\"%s\" index=\"%u\">\n", - link->l_name, link->l_index); - dp_dump_line(p, line++, " <family>%s</family>\n", + nl_dump_line(p, "LINK_NAME=%s\n", link->l_name); + nl_dump_line(p, "LINK_IFINDEX=%u\n", link->l_index); + nl_dump_line(p, "LINK_FAMILY=%s\n", nl_af2str(link->l_family, buf, sizeof(buf))); - dp_dump_line(p, line++, " <arptype>%s</arptype>\n", - nl_llproto2str(link->l_arptype, buf, sizeof(buf))); - dp_dump_line(p, line++, " <address>%s</address>\n", - nl_addr2str(link->l_addr, buf, sizeof(buf))); - dp_dump_line(p, line++, " <mtu>%u</mtu>\n", link->l_mtu); - dp_dump_line(p, line++, " <txqlen>%u</txqlen>\n", link->l_txqlen); - dp_dump_line(p, line++, " <weight>%u</weight>\n", link->l_weight); - - rtnl_link_flags2str(link->l_flags, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); - - if (link->ce_mask & LINK_ATTR_QDISC) - dp_dump_line(p, line++, " <qdisc>%s</qdisc>\n", link->l_qdisc); - - if (link->ce_mask & LINK_ATTR_LINK) { - struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); - dp_dump_line(p, line++, " <link>%s</link>\n", - ll ? ll->l_name : "none"); - if (ll) - rtnl_link_put(ll); - } - - if (link->ce_mask & LINK_ATTR_MASTER) { - struct rtnl_link *master = rtnl_link_get(cache, link->l_master); - dp_dump_line(p, line++, " <master>%s</master>\n", - master ? master->l_name : "none"); - if (master) - rtnl_link_put(master); - } - - if (link->ce_mask & LINK_ATTR_BRD) - dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n", - nl_addr2str(link->l_bcast, buf, sizeof(buf))); - - if (link->ce_mask & LINK_ATTR_STATS) { - dp_dump_line(p, line++, " <stats>\n"); - for (i = 0; i <= RTNL_LINK_STATS_MAX; i++) { - rtnl_link_stat2str(i, buf, sizeof(buf)); - dp_dump_line(p, line++, - " <%s>%" PRIu64 "</%s>\n", - buf, link->l_stats[i], buf); - } - dp_dump_line(p, line++, " </stats>\n"); - } - - if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_XML]) { - dp_dump_line(p, line++, " <info>\n"); - line = link->l_info_ops->io_dump[NL_DUMP_XML](link, p, line); - dp_dump_line(p, line++, " </info>\n"); - } - - dp_dump_line(p, line++, "</link>\n"); - -#if 0 - uint32_t l_change; /**< Change mask */ - struct rtnl_lifmap l_map; /**< Interface device mapping */ -#endif - - return line; -} - -static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_link *link = (struct rtnl_link *) obj; - struct nl_cache *cache = dp_cache(obj); - char buf[128]; - int i, line = 0; - - dp_dump_line(p, line++, "LINK_NAME=%s\n", link->l_name); - dp_dump_line(p, line++, "LINK_IFINDEX=%u\n", link->l_index); - dp_dump_line(p, line++, "LINK_FAMILY=%s\n", - nl_af2str(link->l_family, buf, sizeof(buf))); - dp_dump_line(p, line++, "LINK_TYPE=%s\n", + nl_dump_line(p, "LINK_TYPE=%s\n", nl_llproto2str(link->l_arptype, buf, sizeof(buf))); if (link->ce_mask & LINK_ATTR_ADDR) - dp_dump_line(p, line++, "LINK_ADDRESS=%s\n", + nl_dump_line(p, "LINK_ADDRESS=%s\n", nl_addr2str(link->l_addr, buf, sizeof(buf))); - dp_dump_line(p, line++, "LINK_MTU=%u\n", link->l_mtu); - dp_dump_line(p, line++, "LINK_TXQUEUELEN=%u\n", link->l_txqlen); - dp_dump_line(p, line++, "LINK_WEIGHT=%u\n", link->l_weight); + nl_dump_line(p, "LINK_MTU=%u\n", link->l_mtu); + nl_dump_line(p, "LINK_TXQUEUELEN=%u\n", link->l_txqlen); + nl_dump_line(p, "LINK_WEIGHT=%u\n", link->l_weight); rtnl_link_flags2str(link->l_flags & ~IFF_RUNNING, buf, sizeof(buf)); if (buf[0]) - dp_dump_line(p, line++, "LINK_FLAGS=%s\n", buf); + nl_dump_line(p, "LINK_FLAGS=%s\n", buf); if (link->ce_mask & LINK_ATTR_QDISC) - dp_dump_line(p, line++, "LINK_QDISC=%s\n", link->l_qdisc); + nl_dump_line(p, "LINK_QDISC=%s\n", link->l_qdisc); if (link->ce_mask & LINK_ATTR_LINK) { struct rtnl_link *ll = rtnl_link_get(cache, link->l_link); - dp_dump_line(p, line++, "LINK_LINK_IFINDEX=%d\n", link->l_link); + nl_dump_line(p, "LINK_LINK_IFINDEX=%d\n", link->l_link); if (ll) { - dp_dump_line(p, line++, "LINK_LINK_IFNAME=%s\n", - ll->l_name); + nl_dump_line(p, "LINK_LINK_IFNAME=%s\n", ll->l_name); rtnl_link_put(ll); } } if (link->ce_mask & LINK_ATTR_MASTER) { struct rtnl_link *master = rtnl_link_get(cache, link->l_master); - dp_dump_line(p, line++, "LINK_MASTER=%s\n", + nl_dump_line(p, "LINK_MASTER=%s\n", master ? master->l_name : "none"); if (master) rtnl_link_put(master); } if (link->ce_mask & LINK_ATTR_BRD) - dp_dump_line(p, line++, "LINK_BROADCAST=%s\n", + nl_dump_line(p, "LINK_BROADCAST=%s\n", nl_addr2str(link->l_bcast, buf, sizeof(buf))); if (link->ce_mask & LINK_ATTR_STATS) { @@ -720,15 +625,12 @@ static int link_dump_env(struct nl_object *obj, struct nl_dump_params *p) *c = toupper(*c); c++; } - dp_dump_line(p, line++, - "%s=%" PRIu64 "\n", buf, link->l_stats[i]); + nl_dump_line(p, "%s=%" PRIu64 "\n", buf, link->l_stats[i]); } } if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_ENV]) - line = link->l_info_ops->io_dump[NL_DUMP_ENV](link, p, line); - - return line; + link->l_info_ops->io_dump[NL_DUMP_ENV](link, p); } #if 0 @@ -800,7 +702,7 @@ static int link_compare(struct nl_object *_a, struct nl_object *_b, diff |= LINK_DIFF(ADDR, nl_addr_cmp(a->l_addr, b->l_addr)); diff |= LINK_DIFF(BRD, nl_addr_cmp(a->l_bcast, b->l_bcast)); - if (flags & LOOSE_FLAG_COMPARISON) + if (flags & LOOSE_COMPARISON) diff |= LINK_DIFF(FLAGS, (a->l_flags ^ b->l_flags) & b->l_flag_mask); else @@ -863,28 +765,17 @@ void rtnl_link_put(struct rtnl_link *link) /** * Allocate link cache and fill in all configured links. - * @arg handle Netlink handle. + * @arg sk Netlink socket. + * @arg result Pointer to store resulting cache. * * Allocates a new link cache, initializes it properly and updates it * to include all links currently configured in the kernel. * - * @note Free the memory after usage. - * @return Newly allocated cache or NULL if an error occured. + * @return 0 on success or a negative error code. */ -struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle) +int rtnl_link_alloc_cache(struct nl_sock *sk, struct nl_cache **result) { - struct nl_cache * cache; - - cache = nl_cache_alloc(&rtnl_link_ops); - if (cache == NULL) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - return cache; + return nl_cache_alloc_and_fill(&rtnl_link_ops, sk, result); } /** @@ -967,9 +858,9 @@ struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, * @note Not all attributes can be changed, see * \ref link_changeable "Changeable Attributes" for more details. */ -struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old, - struct rtnl_link *tmpl, - int flags) +int rtnl_link_build_change_request(struct rtnl_link *old, + struct rtnl_link *tmpl, int flags, + struct nl_msg **result) { struct nl_msg *msg; struct ifinfomsg ifi = { @@ -984,7 +875,7 @@ struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old, msg = nlmsg_alloc_simple(RTM_SETLINK, flags); if (!msg) - goto nla_put_failure; + return -NLE_NOMEM; if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -1028,16 +919,17 @@ struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old, nla_nest_end(msg, info); } - return msg; + *result = msg; + return 0; nla_put_failure: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** * Change link attributes - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg old link to be changed * @arg tmpl template with requested changes * @arg flags additional netlink message flags @@ -1050,22 +942,21 @@ nla_put_failure: * @note Not all attributes can be changed, see * \ref link_changeable "Changeable Attributes" for more details. */ -int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old, +int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *old, struct rtnl_link *tmpl, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_link_build_change_request(old, tmpl, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -1106,11 +997,11 @@ char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, * @arg cache link cache * @arg name link name * - * @return interface index or RTNL_LINK_NOT_FOUND if no match was found. + * @return interface index or 0 if no match was found. */ int rtnl_link_name2i(struct nl_cache *cache, const char *name) { - int ifindex = RTNL_LINK_NOT_FOUND; + int ifindex = 0; struct rtnl_link *link; link = rtnl_link_get_by_name(cache, name); @@ -1380,10 +1271,7 @@ void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex) int rtnl_link_get_ifindex(struct rtnl_link *link) { - if (link->ce_mask & LINK_ATTR_IFINDEX) - return link->l_index; - else - return RTNL_LINK_NOT_FOUND; + return link->l_index; } void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu) @@ -1436,10 +1324,7 @@ void rtnl_link_set_link(struct rtnl_link *link, int ifindex) int rtnl_link_get_link(struct rtnl_link *link) { - if (link->ce_mask & LINK_ATTR_LINK) - return link->l_link; - else - return RTNL_LINK_NOT_FOUND; + return link->l_link; } void rtnl_link_set_master(struct rtnl_link *link, int ifindex) @@ -1450,10 +1335,7 @@ void rtnl_link_set_master(struct rtnl_link *link, int ifindex) int rtnl_link_get_master(struct rtnl_link *link) { - if (link->ce_mask & LINK_ATTR_MASTER) - return link->l_master; - else - return RTNL_LINK_NOT_FOUND; + return link->l_master; } void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t operstate) @@ -1509,7 +1391,7 @@ int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) int err; if ((io = rtnl_link_info_ops_lookup(type)) == NULL) - return nl_error(ENOENT, "No such link info type exists"); + return -NLE_OPNOTSUPP; if (link->l_info_ops) release_link_info(link); @@ -1544,11 +1426,12 @@ static struct nl_object_ops link_obj_ops = { .oo_size = sizeof(struct rtnl_link), .oo_free_data = link_free_data, .oo_clone = link_clone, - .oo_dump[NL_DUMP_BRIEF] = link_dump_brief, - .oo_dump[NL_DUMP_FULL] = link_dump_full, - .oo_dump[NL_DUMP_STATS] = link_dump_stats, - .oo_dump[NL_DUMP_XML] = link_dump_xml, - .oo_dump[NL_DUMP_ENV] = link_dump_env, + .oo_dump = { + [NL_DUMP_LINE] = link_dump_line, + [NL_DUMP_DETAILS] = link_dump_details, + [NL_DUMP_STATS] = link_dump_stats, + [NL_DUMP_ENV] = link_dump_env, + }, .oo_compare = link_compare, .oo_attrs2str = link_attrs2str, .oo_id_attrs = LINK_ATTR_IFINDEX, diff --git a/lib/route/link/api.c b/lib/route/link/api.c index afe00b1..a0e7679 100644 --- a/lib/route/link/api.c +++ b/lib/route/link/api.c @@ -61,10 +61,10 @@ struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name) int rtnl_link_register_info(struct rtnl_link_info_ops *ops) { if (ops->io_name == NULL) - return nl_error(EINVAL, "No name specified"); + return -NLE_INVAL; if (rtnl_link_info_ops_lookup(ops->io_name)) - return nl_error(EEXIST, "Link info operations already exist"); + return -NLE_EXIST; NL_DBG(1, "Registered link info operations %s\n", ops->io_name); @@ -83,10 +83,10 @@ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops) break; if (!t) - return nl_error(ENOENT, "No such link info operations"); + return -NLE_OPNOTSUPP; if (t->io_refcnt > 0) - return nl_error(EBUSY, "Info operations in use"); + return -NLE_BUSY; NL_DBG(1, "Unregistered link info perations %s\n", ops->io_name); diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c index c148dca..c466afe 100644 --- a/lib/route/link/vlan.c +++ b/lib/route/link/vlan.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -73,7 +73,7 @@ static int vlan_alloc(struct rtnl_link *link) struct vlan_info *vi; if ((vi = calloc(1, sizeof(*vi))) == NULL) - return nl_errno(ENOMEM); + return -NLE_NOMEM; link->l_info = vi; @@ -119,12 +119,11 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data, nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) { if (nla_len(nla) < sizeof(*map)) - return nl_error(EINVAL, "Malformed mapping"); + return -NLE_INVAL; map = nla_data(nla); if (map->from < 0 || map->from > VLAN_PRIO_MAX) { - return nl_error(EINVAL, "VLAN prio %d out of " - "range", map->from); + return -NLE_INVAL; } vi->vi_ingress_qos[map->from] = map->to; @@ -140,7 +139,7 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data, nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) { if (nla_len(nla) < sizeof(*map)) - return nl_error(EINVAL, "Malformed mapping"); + return -NLE_INVAL; i++; } @@ -148,7 +147,7 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data, vi->vi_egress_size = (i + 32) & ~31; vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map)); if (vi->vi_egress_qos == NULL) - return nl_errno(ENOMEM); + return -NLE_NOMEM; i = 0; nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) { @@ -180,71 +179,60 @@ static void vlan_free(struct rtnl_link *link) link->l_info = NULL; } -static int vlan_dump_brief(struct rtnl_link *link, struct nl_dump_params *p, - int line) +static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p) { struct vlan_info *vi = link->l_info; - dp_dump(p, "vlan-id %d", vi->vi_vlan_id); - - return line; + nl_dump(p, "vlan-id %d", vi->vi_vlan_id); } -static int vlan_dump_full(struct rtnl_link *link, struct nl_dump_params *p, - int line) +static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p) { struct vlan_info *vi = link->l_info; int i, printed; char buf[64]; rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf)); - dp_dump_line(p, line++, " vlan-info id %d <%s>\n", - vi->vi_vlan_id, buf); + nl_dump_line(p, " vlan-info id %d <%s>\n", vi->vi_vlan_id, buf); if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) { - dp_dump_line(p, line++, + nl_dump_line(p, " ingress vlan prio -> qos/socket prio mapping:\n"); for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) { if (vi->vi_ingress_qos[i]) { - if (printed == 0) { - dp_new_line(p, line); - dp_dump(p, " "); - } - dp_dump(p, "%x -> %#08x, ", + if (printed == 0) + nl_dump_line(p, " "); + nl_dump(p, "%x -> %#08x, ", i, vi->vi_ingress_qos[i]); if (printed++ == 3) { - dp_dump(p, "\n"); + nl_dump(p, "\n"); printed = 0; } } } if (printed > 0 && printed != 4) - dp_dump(p, "\n"); + nl_dump(p, "\n"); } if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { - dp_dump_line(p, line++, + nl_dump_line(p, " egress qos/socket prio -> vlan prio mapping:\n"); for (i = 0, printed = 0; i < vi->vi_negress; i++) { - if (printed == 0) { - dp_new_line(p, line); - dp_dump(p, " "); - } - dp_dump(p, "%#08x -> %x, ", + if (printed == 0) + nl_dump_line(p, " "); + nl_dump(p, "%#08x -> %x, ", vi->vi_egress_qos[i].vm_from, vi->vi_egress_qos[i].vm_to); if (printed++ == 3) { - dp_dump(p, "\n"); + nl_dump(p, "\n"); printed = 0; } } if (printed > 0 && printed != 4) - dp_dump(p, "\n"); + nl_dump(p, "\n"); } - - return line; } static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src) @@ -260,7 +248,7 @@ static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src) vdst->vi_egress_qos = calloc(vsrc->vi_egress_size, sizeof(struct vlan_map)); if (!vdst->vi_egress_qos) - return nl_errno(ENOMEM); + return -NLE_NOMEM; memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos, vsrc->vi_egress_size * sizeof(struct vlan_map)); @@ -274,7 +262,7 @@ static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link) struct nlattr *data; if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - return nl_errno(ENOBUFS); + return -NLE_MSGSIZE; if (vi->vi_mask & VLAN_HAS_ID) NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id); @@ -337,8 +325,10 @@ static struct rtnl_link_info_ops vlan_info_ops = { .io_name = "vlan", .io_alloc = vlan_alloc, .io_parse = vlan_parse, - .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief, - .io_dump[NL_DUMP_FULL] = vlan_dump_full, + .io_dump = { + [NL_DUMP_LINE] = vlan_dump_line, + [NL_DUMP_DETAILS] = vlan_dump_details, + }, .io_clone = vlan_clone, .io_put_attrs = vlan_put_attrs, .io_free = vlan_free, @@ -349,7 +339,7 @@ int rtnl_link_vlan_set_id(struct rtnl_link *link, int id) struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; vi->vi_vlan_id = id; vi->vi_mask |= VLAN_HAS_ID; @@ -362,7 +352,7 @@ int rtnl_link_vlan_get_id(struct rtnl_link *link) struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; if (vi->vi_mask & VLAN_HAS_ID) return vi->vi_vlan_id; @@ -375,7 +365,7 @@ int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags) struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; vi->vi_flags_mask |= flags; vi->vi_flags |= flags; @@ -389,7 +379,7 @@ int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags) struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; vi->vi_flags_mask |= flags; vi->vi_flags &= ~flags; @@ -403,7 +393,7 @@ unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *link) struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; return vi->vi_flags; } @@ -414,11 +404,10 @@ int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from, struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; if (from < 0 || from > VLAN_PRIO_MAX) - return nl_error(EINVAL, "Invalid vlan prio 0..%d", - VLAN_PRIO_MAX); + return -NLE_INVAL; vi->vi_ingress_qos[from] = to; vi->vi_mask |= VLAN_HAS_INGRESS_QOS; @@ -430,10 +419,8 @@ uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link) { struct vlan_info *vi = link->l_info; - if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) { - nl_error(EOPNOTSUPP, "Not a VLAN link"); + if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) return NULL; - } if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) return vi->vi_ingress_qos; @@ -446,11 +433,10 @@ int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to) struct vlan_info *vi = link->l_info; if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) - return nl_error(EOPNOTSUPP, "Not a VLAN link"); + return -NLE_OPNOTSUPP; if (to < 0 || to > VLAN_PRIO_MAX) - return nl_error(EINVAL, "Invalid vlan prio 0..%d", - VLAN_PRIO_MAX); + return -NLE_INVAL; if (vi->vi_negress >= vi->vi_egress_size) { int new_size = vi->vi_egress_size + 32; @@ -458,7 +444,7 @@ int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to) ptr = realloc(vi->vi_egress_qos, new_size); if (!ptr) - return nl_errno(ENOMEM); + return -NLE_NOMEM; vi->vi_egress_qos = ptr; vi->vi_egress_size = new_size; @@ -477,15 +463,11 @@ struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link, { struct vlan_info *vi = link->l_info; - if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) { - nl_error(EOPNOTSUPP, "Not a VLAN link"); + if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) return NULL; - } - if (negress == NULL) { - nl_error(EINVAL, "Require pointer to store negress"); + if (negress == NULL) return NULL; - } if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) { *negress = vi->vi_negress; diff --git a/lib/route/neigh.c b/lib/route/neigh.c index 6f2f0d3..d4dc82c 100644 --- a/lib/route/neigh.c +++ b/lib/route/neigh.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -61,7 +61,7 @@ * @code * // The first step is to retrieve a list of all available neighbour within * // the kernel and put them into a cache. - * struct nl_cache *cache = rtnl_neigh_alloc_cache(handle); + * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk); * * // Neighbours can then be looked up by the interface and destination * // address: @@ -86,7 +86,7 @@ * // block until the operation has been completed. Alternatively the required * // netlink message can be built using rtnl_neigh_build_add_request() * // to be sent out using nl_send_auto_complete(). - * rtnl_neigh_add(nl_handle, neigh, NLM_F_REPLACE); + * rtnl_neigh_add(sk, neigh, NLM_F_CREATE); * * // Free the memory * rtnl_neigh_put(neigh); @@ -109,7 +109,7 @@ * // block until the operation has been completed. Alternatively the required * // netlink message can be built using rtnl_neigh_build_delete_request() * // to be sent out using nl_send_auto_complete(). - * rtnl_neigh_delete(handle, neigh, 0); + * rtnl_neigh_delete(sk, neigh, 0); * * // Free the memory * rtnl_neigh_put(neigh); @@ -139,7 +139,7 @@ * // block until the operation has been completed. Alternatively the required * // netlink message can be built using rtnl_neigh_build_change_request() * // to be sent out using nl_send_auto_complete(). - * rtnl_neigh_change(handle, neigh, 0); + * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE); * * // Free the memory * rtnl_neigh_put(neigh); @@ -187,15 +187,13 @@ static int neigh_clone(struct nl_object *_dst, struct nl_object *_src) if (src->n_lladdr) if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr))) - goto errout; + return -NLE_NOMEM; if (src->n_dst) if (!(dst->n_dst = nl_addr_clone(src->n_dst))) - goto errout; + return -NLE_NOMEM; return 0; -errout: - return nl_get_errno(); } static int neigh_compare(struct nl_object *_a, struct nl_object *_b, @@ -213,7 +211,7 @@ static int neigh_compare(struct nl_object *_a, struct nl_object *_b, diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr)); diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst)); - if (flags & LOOSE_FLAG_COMPARISON) { + if (flags & LOOSE_COMPARISON) { diff |= NEIGH_DIFF(STATE, (a->n_state ^ b->n_state) & b->n_state_mask); diff |= NEIGH_DIFF(FLAGS, @@ -261,7 +259,7 @@ static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, neigh = rtnl_neigh_alloc(); if (!neigh) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -283,18 +281,22 @@ static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, NEIGH_ATTR_TYPE); if (tb[NDA_LLADDR]) { - neigh->n_lladdr = nla_get_addr(tb[NDA_LLADDR], AF_UNSPEC); - if (!neigh->n_lladdr) + neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC); + if (!neigh->n_lladdr) { + err = -NLE_NOMEM; goto errout; + } nl_addr_set_family(neigh->n_lladdr, nl_addr_guess_family(neigh->n_lladdr)); neigh->ce_mask |= NEIGH_ATTR_LLADDR; } if (tb[NDA_DST]) { - neigh->n_dst = nla_get_addr(tb[NDA_DST], neigh->n_family); - if (!neigh->n_dst) + neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family); + if (!neigh->n_dst) { + err = -NLE_NOMEM; goto errout; + } neigh->ce_mask |= NEIGH_ATTR_DST; } @@ -315,23 +317,18 @@ static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } err = pp->pp_cb((struct nl_object *) neigh, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; - errout: rtnl_neigh_put(neigh); return err; } -static int neigh_request_update(struct nl_cache *c, struct nl_handle *h) +static int neigh_request_update(struct nl_cache *c, struct nl_sock *h) { return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP); } -static int neigh_dump_brief(struct nl_object *a, struct nl_dump_params *p) +static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p) { char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5]; struct rtnl_neigh *n = (struct rtnl_neigh *) a; @@ -340,162 +337,95 @@ static int neigh_dump_brief(struct nl_object *a, struct nl_dump_params *p) link_cache = nl_cache_mngt_require("route/link"); - dp_dump(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst))); + nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst))); if (link_cache) - dp_dump(p, "dev %s ", + nl_dump(p, "dev %s ", rtnl_link_i2name(link_cache, n->n_ifindex, state, sizeof(state))); else - dp_dump(p, "dev %d ", n->n_ifindex); + nl_dump(p, "dev %d ", n->n_ifindex); if (n->ce_mask & NEIGH_ATTR_LLADDR) - dp_dump(p, "lladdr %s ", + nl_dump(p, "lladdr %s ", nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr))); rtnl_neigh_state2str(n->n_state, state, sizeof(state)); rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags)); if (state[0]) - dp_dump(p, "<%s", state); + nl_dump(p, "<%s", state); if (flags[0]) - dp_dump(p, "%s%s", state[0] ? "," : "<", flags); + nl_dump(p, "%s%s", state[0] ? "," : "<", flags); if (state[0] || flags[0]) - dp_dump(p, ">"); - dp_dump(p, "\n"); - - return 1; + nl_dump(p, ">"); + nl_dump(p, "\n"); } -static int neigh_dump_full(struct nl_object *a, struct nl_dump_params *p) +static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p) { char rtn_type[32]; struct rtnl_neigh *n = (struct rtnl_neigh *) a; int hz = nl_get_hz(); - int line = neigh_dump_brief(a, p); + neigh_dump_line(a, p); - dp_dump_line(p, line++, " refcnt %u type %s confirmed %u used " + nl_dump_line(p, " refcnt %u type %s confirmed %u used " "%u updated %u\n", n->n_cacheinfo.nci_refcnt, nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)), n->n_cacheinfo.nci_confirmed/hz, n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz); - - return line; -} - -static int neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p) -{ - return neigh_dump_full(a, p); } -static int neigh_dump_xml(struct nl_object *obj, struct nl_dump_params *p) +static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p) { - struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "<neighbour>\n"); - dp_dump_line(p, line++, " <family>%s</family>\n", - nl_af2str(neigh->n_family, buf, sizeof(buf))); - - if (neigh->ce_mask & NEIGH_ATTR_LLADDR) - dp_dump_line(p, line++, " <lladdr>%s</lladdr>\n", - nl_addr2str(neigh->n_lladdr, buf, sizeof(buf))); - - if (neigh->ce_mask & NEIGH_ATTR_DST) - dp_dump_line(p, line++, " <dst>%s</dst>\n", - nl_addr2str(neigh->n_dst, buf, sizeof(buf))); - - if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) { - struct nl_cache *link_cache; - - link_cache = nl_cache_mngt_require("route/link"); - - if (link_cache) - dp_dump_line(p, line++, " <device>%s</device>\n", - rtnl_link_i2name(link_cache, - neigh->n_ifindex, - buf, sizeof(buf))); - else - dp_dump_line(p, line++, " <device>%u</device>\n", - neigh->n_ifindex); - } - - if (neigh->ce_mask & NEIGH_ATTR_PROBES) - dp_dump_line(p, line++, " <probes>%u</probes>\n", - neigh->n_probes); - - if (neigh->ce_mask & NEIGH_ATTR_TYPE) - dp_dump_line(p, line++, " <type>%s</type>\n", - nl_rtntype2str(neigh->n_type, buf, sizeof(buf))); - - rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); - - rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf)); - if (buf[0]) - dp_dump_line(p, line++, " <state>%s</state>\n", buf); - - dp_dump_line(p, line++, "</neighbour>\n"); - -#if 0 - struct rtnl_ncacheinfo n_cacheinfo; -#endif - - return line; + neigh_dump_details(a, p); } -static int neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p) +static void neigh_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj; char buf[128]; - int line = 0; - dp_dump_line(p, line++, "NEIGH_FAMILY=%s\n", + nl_dump_line(p, "NEIGH_FAMILY=%s\n", nl_af2str(neigh->n_family, buf, sizeof(buf))); if (neigh->ce_mask & NEIGH_ATTR_LLADDR) - dp_dump_line(p, line++, "NEIGHT_LLADDR=%s\n", + nl_dump_line(p, "NEIGHT_LLADDR=%s\n", nl_addr2str(neigh->n_lladdr, buf, sizeof(buf))); if (neigh->ce_mask & NEIGH_ATTR_DST) - dp_dump_line(p, line++, "NEIGH_DST=%s\n", + nl_dump_line(p, "NEIGH_DST=%s\n", nl_addr2str(neigh->n_dst, buf, sizeof(buf))); if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) { struct nl_cache *link_cache; - dp_dump_line(p, line++, "NEIGH_IFINDEX=%u\n", - neigh->n_ifindex); + nl_dump_line(p, "NEIGH_IFINDEX=%u\n", neigh->n_ifindex); link_cache = nl_cache_mngt_require("route/link"); if (link_cache) - dp_dump_line(p, line++, "NEIGH_IFNAME=%s\n", + nl_dump_line(p, "NEIGH_IFNAME=%s\n", rtnl_link_i2name(link_cache, neigh->n_ifindex, buf, sizeof(buf))); } if (neigh->ce_mask & NEIGH_ATTR_PROBES) - dp_dump_line(p, line++, "NEIGH_PROBES=%u\n", - neigh->n_probes); + nl_dump_line(p, "NEIGH_PROBES=%u\n", neigh->n_probes); if (neigh->ce_mask & NEIGH_ATTR_TYPE) - dp_dump_line(p, line++, "NEIGH_TYPE=%s\n", + nl_dump_line(p, "NEIGH_TYPE=%s\n", nl_rtntype2str(neigh->n_type, buf, sizeof(buf))); rtnl_neigh_flags2str(neigh->n_flags, buf, sizeof(buf)); if (buf[0]) - dp_dump_line(p, line++, "NEIGH_FLAGS=%s\n", buf); + nl_dump_line(p, "NEIGH_FLAGS=%s\n", buf); rtnl_neigh_state2str(neigh->n_state, buf, sizeof(buf)); if (buf[0]) - dp_dump_line(p, line++, "NEIGH_STATE=%s\n", buf); - - return line; + nl_dump_line(p, "NEIGH_STATE=%s\n", buf); } /** @@ -522,31 +452,17 @@ void rtnl_neigh_put(struct rtnl_neigh *neigh) /** * Build a neighbour cache including all neighbours currently configured in the kernel. - * @arg handle netlink handle + * @arg sk Netlink socket. + * @arg result Pointer to store resulting cache. * * Allocates a new neighbour cache, initializes it properly and updates it * to include all neighbours currently configured in the kernel. * - * @note The caller is responsible for destroying and freeing the - * cache after using it. - * @return The new cache or NULL if an error occured. + * @return 0 on success or a negative error code. */ -struct nl_cache *rtnl_neigh_alloc_cache(struct nl_handle *handle) +int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result) { - struct nl_cache *cache; - - cache = nl_cache_alloc(&rtnl_neigh_ops); - if (cache == NULL) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - NL_DBG(2, "Returning new cache %p\n", cache); - - return cache; + return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result); } /** @@ -579,22 +495,26 @@ struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex, * @{ */ -static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, - int flags) +static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags, + struct nl_msg **result) { struct nl_msg *msg; struct ndmsg nhdr = { .ndm_ifindex = tmpl->n_ifindex, - .ndm_family = nl_addr_get_family(tmpl->n_dst), .ndm_state = NUD_PERMANENT, }; + if (!(tmpl->ce_mask & NEIGH_ATTR_DST)) + return -NLE_MISSING_ATTR; + + nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst); + if (tmpl->ce_mask & NEIGH_ATTR_STATE) nhdr.ndm_state = tmpl->n_state; msg = nlmsg_alloc_simple(cmd, flags); if (!msg) - return NULL; + return -NLE_NOMEM; if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -604,17 +524,19 @@ static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, if (tmpl->ce_mask & NEIGH_ATTR_LLADDR) NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr); - return msg; + *result = msg; + return 0; nla_put_failure: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** * Build netlink request message to add a new neighbour * @arg tmpl template with data of new neighbour * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a addition of a new * neighbour. The netlink message header isn't fully equipped with @@ -628,16 +550,17 @@ nla_put_failure: * - Destination address (rtnl_neigh_set_dst()) * - Link layer address (rtnl_neigh_set_lladdr()) * - * @return The netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags) +int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags, + struct nl_msg **result) { - return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE | flags); + return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result); } /** * Add a new neighbour - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg tmpl template with requested changes * @arg flags additional netlink message flags * @@ -653,21 +576,20 @@ struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags) +int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags) { int err; struct nl_msg *msg; - msg = rtnl_neigh_build_add_request(tmpl, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -681,6 +603,7 @@ int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags) * Build a netlink request message to delete a neighbour * @arg neigh neighbour to delete * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a deletion of a neighbour. * The netlink message header isn't fully equipped with all relevant @@ -688,17 +611,17 @@ int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl, int flags) * or supplemented as needed. \a neigh must point to an existing * neighbour. * - * @return The netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, - int flags) +int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags, + struct nl_msg **result) { - return build_neigh_msg(neigh, RTM_DELNEIGH, flags); + return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result); } /** * Delete a neighbour - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg neigh neighbour to delete * @arg flags additional netlink message flags * @@ -708,81 +631,21 @@ struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_neigh_delete(struct nl_handle *handle, struct rtnl_neigh *neigh, +int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_neigh_build_delete_request(neigh, flags); - if (!msg) - return nl_errno(ENOMEM); - - err = nl_send_auto_complete(handle, msg); - if (err < 0) + if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0) return err; + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); - return nl_wait_for_ack(handle); -} - -/** @} */ - -/** - * @name Neighbour Modification - * @{ - */ - -/** - * Build a netlink request message to change neighbour attributes - * @arg neigh the neighbour to change - * @arg flags additional netlink message flags - * - * Builds a new netlink message requesting a change of a neigh - * attributes. The netlink message header isn't fully equipped with - * all relevant fields and must thus be sent out via nl_send_auto_complete() - * or supplemented as needed. - * - * @return The netlink message - * @note Not all attributes can be changed, see - * \ref neigh_changeable "Changeable Attributes" for a list. - */ -struct nl_msg *rtnl_neigh_build_change_request(struct rtnl_neigh *neigh, - int flags) -{ - return build_neigh_msg(neigh, RTM_NEWNEIGH, NLM_F_REPLACE | flags); -} - -/** - * Change neighbour attributes - * @arg handle netlink handle - * @arg neigh neighbour to be changed - * @arg flags additional netlink message flags - * - * Builds a netlink message by calling rtnl_neigh_build_change_request(), - * sends the request to the kernel and waits for the next ACK to be - * received and thus blocks until the request has been fullfilled. - * - * @return 0 on sucess or a negative error if an error occured. - * @note Not all attributes can be changed, see - * \ref neigh_changeable "Changeable Attributes" for a list. - */ -int rtnl_neigh_change(struct nl_handle *handle, struct rtnl_neigh *neigh, - int flags) -{ - int err; - struct nl_msg *msg; - - msg = rtnl_neigh_build_change_request(neigh, flags); - if (!msg) - return nl_errno(ENOMEM); - - err = nl_send_auto_complete(handle, msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -893,10 +756,7 @@ void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex) int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh) { - if (neigh->ce_mask & NEIGH_ATTR_IFINDEX) - return neigh->n_ifindex; - else - return RTNL_LINK_NOT_FOUND; + return neigh->n_ifindex; } static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos, @@ -905,8 +765,7 @@ static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos, if (!nocheck) { if (neigh->ce_mask & NEIGH_ATTR_FAMILY) { if (new->a_family != neigh->n_family) - return nl_error(EINVAL, - "Address family mismatch"); + return -NLE_AF_MISMATCH; } else { neigh->n_family = new->a_family; neigh->ce_mask |= NEIGH_ATTR_FAMILY; @@ -957,6 +816,11 @@ void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family) neigh->ce_mask |= NEIGH_ATTR_FAMILY; } +int rtnl_neigh_get_family(struct rtnl_neigh *neigh) +{ + return neigh->n_family; +} + void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type) { neigh->n_type = type; @@ -978,14 +842,15 @@ static struct nl_object_ops neigh_obj_ops = { .oo_size = sizeof(struct rtnl_neigh), .oo_free_data = neigh_free_data, .oo_clone = neigh_clone, - .oo_dump[NL_DUMP_BRIEF] = neigh_dump_brief, - .oo_dump[NL_DUMP_FULL] = neigh_dump_full, - .oo_dump[NL_DUMP_STATS] = neigh_dump_stats, - .oo_dump[NL_DUMP_XML] = neigh_dump_xml, - .oo_dump[NL_DUMP_ENV] = neigh_dump_env, + .oo_dump = { + [NL_DUMP_LINE] = neigh_dump_line, + [NL_DUMP_DETAILS] = neigh_dump_details, + [NL_DUMP_STATS] = neigh_dump_stats, + [NL_DUMP_ENV] = neigh_dump_env, + }, .oo_compare = neigh_compare, .oo_attrs2str = neigh_attrs2str, - .oo_id_attrs = (NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY), + .oo_id_attrs = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY), }; static struct nl_af_group neigh_groups[] = { diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c index 3191b5b..9599faa 100644 --- a/lib/route/neightbl.c +++ b/lib/route/neightbl.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -129,7 +129,7 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops, ntbl = rtnl_neightbl_alloc(); if (!ntbl) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -143,7 +143,7 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops, ntbl->nt_family = rtmsg->rtgen_family; if (tb[NDTA_NAME] == NULL) { - err = nl_error(EINVAL, "NDTA_NAME is missing"); + return -NLE_MISSING_ATTR; goto errout; } @@ -217,27 +217,22 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops, } err = pp->pp_cb((struct nl_object *) ntbl, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; errout: rtnl_neightbl_put(ntbl); return err; } -static int neightbl_request_update(struct nl_cache *c, struct nl_handle *h) +static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h) { return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP); } -static int neightbl_dump_brief(struct nl_object *arg, struct nl_dump_params *p) +static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p) { - int line = 1; struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg; - dp_dump(p, "%s", ntbl->nt_name); + nl_dump_line(p, "%s", ntbl->nt_name); if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) { struct nl_cache *link_cache; @@ -246,57 +241,52 @@ static int neightbl_dump_brief(struct nl_object *arg, struct nl_dump_params *p) if (link_cache) { char buf[32]; - dp_dump(p, "<%s> ", + nl_dump(p, "<%s> ", rtnl_link_i2name(link_cache, ntbl->nt_parms.ntp_ifindex, buf, sizeof(buf))); } else - dp_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex); + nl_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex); } else - dp_dump(p, " "); + nl_dump(p, " "); if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) - dp_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries); + nl_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries); if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) { char rt[32], rt2[32]; struct rtnl_neightbl_parms *pa = &ntbl->nt_parms; - dp_dump(p, "reachable-time %s retransmit-time %s", + nl_dump(p, "reachable-time %s retransmit-time %s", nl_msec2str(pa->ntp_reachable_time, rt, sizeof(rt)), nl_msec2str(pa->ntp_retrans_time, rt2, sizeof(rt2))); } - dp_dump(p, "\n"); - - return line; + nl_dump(p, "\n"); } -static int neightbl_dump_full(struct nl_object *arg, struct nl_dump_params *p) +static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *p) { char x[32], y[32], z[32]; struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg; - int line = neightbl_dump_brief(arg, p); + neightbl_dump_line(arg, p); if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) { - dp_new_line(p, line++); - dp_dump(p, " key-len %u entry-size %u last-flush %s\n", + nl_dump_line(p, " key-len %u entry-size %u last-flush %s\n", ntbl->nt_config.ndtc_key_len, ntbl->nt_config.ndtc_entry_size, nl_msec2str(ntbl->nt_config.ndtc_last_flush, x, sizeof(x))); - dp_new_line(p, line++); - dp_dump(p, " gc threshold %u/%u/%u interval %s " \ + nl_dump_line(p, " gc threshold %u/%u/%u interval %s " \ "chain-position %u\n", ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2, ntbl->nt_gc_thresh3, nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)), ntbl->nt_config.ndtc_hash_chain_gc); - dp_new_line(p, line++); - dp_dump(p, " hash-rand 0x%08X/0x%08X last-rand %s\n", + nl_dump_line(p, " hash-rand 0x%08X/0x%08X last-rand %s\n", ntbl->nt_config.ndtc_hash_rnd, ntbl->nt_config.ndtc_hash_mask, nl_msec2str(ntbl->nt_config.ndtc_last_rand, @@ -306,49 +296,43 @@ static int neightbl_dump_full(struct nl_object *arg, struct nl_dump_params *p) if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) { struct rtnl_neightbl_parms *pa = &ntbl->nt_parms; - dp_new_line(p, line++); - dp_dump(p, " refcnt %u pending-queue-limit %u " \ + nl_dump_line(p, " refcnt %u pending-queue-limit %u " \ "proxy-delayed-queue-limit %u\n", pa->ntp_refcnt, pa->ntp_queue_len, pa->ntp_proxy_qlen); - dp_new_line(p, line++); - dp_dump(p, " num-userspace-probes %u num-unicast-probes " \ + nl_dump_line(p, " num-userspace-probes %u num-unicast-probes " \ "%u num-multicast-probes %u\n", pa->ntp_app_probes, pa->ntp_ucast_probes, pa->ntp_mcast_probes); - dp_new_line(p, line++); - dp_dump(p, " min-age %s base-reachable-time %s " \ + nl_dump_line(p, " min-age %s base-reachable-time %s " \ "stale-check-interval %s\n", nl_msec2str(pa->ntp_locktime, x, sizeof(x)), nl_msec2str(pa->ntp_base_reachable_time, y, sizeof(y)), nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z))); - dp_new_line(p, line++); - dp_dump(p, " initial-probe-delay %s answer-delay %s " \ + nl_dump_line(p, " initial-probe-delay %s answer-delay %s " \ "proxy-answer-delay %s\n", nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)), nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)), nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z))); } - - return line; } -static int neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p) +static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p) { struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg; - int line = neightbl_dump_full(arg, p); + + neightbl_dump_details(arg, p); if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS)) - return line; + return; - dp_new_line(p, line++); - dp_dump(p, " lookups %lld hits %lld failed %lld " \ + nl_dump_line(p, " lookups %lld hits %lld failed %lld " \ "allocations %lld destroys %lld\n", ntbl->nt_stats.ndts_lookups, ntbl->nt_stats.ndts_hits, @@ -356,18 +340,15 @@ static int neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p) ntbl->nt_stats.ndts_allocs, ntbl->nt_stats.ndts_destroys); - dp_new_line(p, line++); - dp_dump(p, " hash-grows %lld forced-gc-runs %lld " \ + nl_dump_line(p, " hash-grows %lld forced-gc-runs %lld " \ "periodic-gc-runs %lld\n", ntbl->nt_stats.ndts_hash_grows, ntbl->nt_stats.ndts_forced_gc_runs, ntbl->nt_stats.ndts_periodic_gc_runs); - dp_dump(p, " rcv-unicast-probes %lld rcv-multicast-probes %lld\n", + nl_dump_line(p, " rcv-unicast-probes %lld rcv-multicast-probes %lld\n", ntbl->nt_stats.ndts_rcv_probes_ucast, ntbl->nt_stats.ndts_rcv_probes_mcast); - - return line; } /** @@ -394,30 +375,18 @@ void rtnl_neightbl_put(struct rtnl_neightbl *neightbl) /** * Build a neighbour table cache including all neighbour tables currently configured in the kernel. - * @arg handle netlink handle + * @arg sk Netlink socket. + * @arg result Pointer to store resulting cache. * * Allocates a new neighbour table cache, initializes it properly and * updates it to include all neighbour tables currently configured in * the kernel. * - * @note The caller is responsible for destroying and freeing the - * cache after using it. - * @return The new cache or NULL if an error occured. + * @return 0 on success or a negative error code. */ -struct nl_cache * rtnl_neightbl_alloc_cache(struct nl_handle *handle) +int rtnl_neightbl_alloc_cache(struct nl_sock *sk, struct nl_cache **result) { - struct nl_cache * cache; - - cache = nl_cache_alloc(&rtnl_neightbl_ops); - if (cache == NULL) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - return cache; + return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sk, result); } /** @@ -464,6 +433,7 @@ struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache, * Builds a netlink change request message to change neighbour table attributes * @arg old neighbour table to change * @arg tmpl template with requested changes + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a change of neighbour table * attributes. The netlink message header isn't fully equipped with all @@ -473,98 +443,115 @@ struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache, * kernel and \a tmpl must contain the attributes to be changed set via * \c rtnl_neightbl_set_* functions. * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg * rtnl_neightbl_build_change_request(struct rtnl_neightbl *old, - struct rtnl_neightbl *tmpl) +int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old, + struct rtnl_neightbl *tmpl, + struct nl_msg **result) { - struct nl_msg *m; + struct nl_msg *m, *parms = NULL; struct ndtmsg ndt = { .ndtm_family = old->nt_family, }; m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0); - nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO); + if (!m) + return -NLE_NOMEM; - nla_put_string(m, NDTA_NAME, old->nt_name); + if (nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + NLA_PUT_STRING(m, NDTA_NAME, old->nt_name); if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH1) - nla_put_u32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1); + NLA_PUT_U32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1); if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2) - nla_put_u32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2); + NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2); if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2) - nla_put_u32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2); + NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2); if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL) - nla_put_u64(m, NDTA_GC_INTERVAL, + NLA_PUT_U64(m, NDTA_GC_INTERVAL, tmpl->nt_gc_interval); if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) { struct rtnl_neightbl_parms *p = &tmpl->nt_parms; - struct nl_msg *parms = nlmsg_alloc(); + + parms = nlmsg_alloc(); + if (!parms) + goto nla_put_failure; if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) - nla_put_u32(parms, NDTPA_IFINDEX, + NLA_PUT_U32(parms, NDTPA_IFINDEX, old->nt_parms.ntp_ifindex); if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN) - nla_put_u32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len); + NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len); if (p->ntp_mask & NEIGHTBLPARM_ATTR_APP_PROBES) - nla_put_u32(parms, NDTPA_APP_PROBES, p->ntp_app_probes); + NLA_PUT_U32(parms, NDTPA_APP_PROBES, p->ntp_app_probes); if (p->ntp_mask & NEIGHTBLPARM_ATTR_UCAST_PROBES) - nla_put_u32(parms, NDTPA_UCAST_PROBES, + NLA_PUT_U32(parms, NDTPA_UCAST_PROBES, p->ntp_ucast_probes); if (p->ntp_mask & NEIGHTBLPARM_ATTR_MCAST_PROBES) - nla_put_u32(parms, NDTPA_MCAST_PROBES, + NLA_PUT_U32(parms, NDTPA_MCAST_PROBES, p->ntp_mcast_probes); if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN) - nla_put_u32(parms, NDTPA_PROXY_QLEN, + NLA_PUT_U32(parms, NDTPA_PROXY_QLEN, p->ntp_proxy_qlen); if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME) - nla_put_u64(parms, NDTPA_BASE_REACHABLE_TIME, + NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME, p->ntp_base_reachable_time); if (p->ntp_mask & NEIGHTBLPARM_ATTR_RETRANS_TIME) - nla_put_u64(parms, NDTPA_RETRANS_TIME, + NLA_PUT_U64(parms, NDTPA_RETRANS_TIME, p->ntp_retrans_time); if (p->ntp_mask & NEIGHTBLPARM_ATTR_GC_STALETIME) - nla_put_u64(parms, NDTPA_GC_STALETIME, + NLA_PUT_U64(parms, NDTPA_GC_STALETIME, p->ntp_gc_stale_time); if (p->ntp_mask & NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME) - nla_put_u64(parms, NDTPA_DELAY_PROBE_TIME, + NLA_PUT_U64(parms, NDTPA_DELAY_PROBE_TIME, p->ntp_proxy_delay); if (p->ntp_mask & NEIGHTBLPARM_ATTR_ANYCAST_DELAY) - nla_put_u64(parms, NDTPA_ANYCAST_DELAY, + NLA_PUT_U64(parms, NDTPA_ANYCAST_DELAY, p->ntp_anycast_delay); if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY) - nla_put_u64(parms, NDTPA_PROXY_DELAY, + NLA_PUT_U64(parms, NDTPA_PROXY_DELAY, p->ntp_proxy_delay); if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME) - nla_put_u64(parms, NDTPA_LOCKTIME, p->ntp_locktime); + NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime); + + if (nla_put_nested(m, NDTA_PARMS, parms) < 0) + goto nla_put_failure; - nla_put_nested(m, NDTA_PARMS, parms); nlmsg_free(parms); } - - return m; + + *result = m; + return 0; + +nla_put_failure: + if (parms) + nlmsg_free(parms); + nlmsg_free(m); + return -NLE_MSGSIZE; } /** * Change neighbour table attributes - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg old neighbour table to be changed * @arg tmpl template with requested changes * @@ -575,19 +562,21 @@ struct nl_msg * rtnl_neightbl_build_change_request(struct rtnl_neightbl *old, * * @return 0 on success or a negative error code */ -int rtnl_neightbl_change(struct nl_handle *handle, struct rtnl_neightbl *old, +int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old, struct rtnl_neightbl *tmpl) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_neightbl_build_change_request(old, tmpl); - err = nl_send_auto_complete(handle, msg); - if (err < 0) + if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0) return err; + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); - return nl_wait_for_ack(handle); + if (err < 0) + return err; + + return wait_for_ack(sk); } /** @} */ @@ -790,9 +779,11 @@ void rtnl_neightbl_set_locktime(struct rtnl_neightbl *ntbl, uint64_t ms) static struct nl_object_ops neightbl_obj_ops = { .oo_name = "route/neightbl", .oo_size = sizeof(struct rtnl_neightbl), - .oo_dump[NL_DUMP_BRIEF] = neightbl_dump_brief, - .oo_dump[NL_DUMP_FULL] = neightbl_dump_full, - .oo_dump[NL_DUMP_STATS] = neightbl_dump_stats, + .oo_dump = { + [NL_DUMP_LINE] = neightbl_dump_line, + [NL_DUMP_DETAILS] = neightbl_dump_details, + [NL_DUMP_STATS] = neightbl_dump_stats, + }, .oo_compare = neightbl_compare, }; diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c index 7486769..788e255 100644 --- a/lib/route/nexthop.c +++ b/lib/route/nexthop.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -21,6 +21,14 @@ #include <netlink/route/rtnl.h> #include <netlink/route/route.h> +/** @cond SKIP */ +#define NH_ATTR_FLAGS 0x000001 +#define NH_ATTR_WEIGHT 0x000002 +#define NH_ATTR_IFINDEX 0x000004 +#define NH_ATTR_GATEWAY 0x000008 +#define NH_ATTR_REALMS 0x000010 +/** @endcond */ + /** * @name Allocation/Freeing * @{ @@ -31,10 +39,8 @@ struct rtnl_nexthop *rtnl_route_nh_alloc(void) struct rtnl_nexthop *nh; nh = calloc(1, sizeof(*nh)); - if (!nh) { - nl_errno(ENOMEM); + if (!nh) return NULL; - } nl_init_list_head(&nh->rtnh_list); @@ -53,7 +59,7 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src) nh->rtnh_flag_mask = src->rtnh_flag_mask; nh->rtnh_weight = src->rtnh_weight; nh->rtnh_ifindex = src->rtnh_ifindex; - nh->rtnh_mask = src->rtnh_mask; + nh->ce_mask = src->ce_mask; if (src->rtnh_gateway) { nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway); @@ -74,78 +80,251 @@ void rtnl_route_nh_free(struct rtnl_nexthop *nh) /** @} */ +int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b, + uint32_t attrs, int loose) +{ + int diff = 0; + +#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR) + + diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex); + diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight); + diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms); + diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway, + b->rtnh_gateway)); + + if (loose) + diff |= NH_DIFF(FLAGS, + (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask); + else + diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags); + +#undef NH_DIFF + + return diff; +} + +static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump(dp, "via"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway, + buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump(dp, " dev %s", + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump(dp, " dev %d", nh->rtnh_ifindex); + } + + nl_dump(dp, " "); +} + +static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump(dp, "nexthop"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, + buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump(dp, " dev %s", + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump(dp, " dev %d", nh->rtnh_ifindex); + } + + if (nh->ce_mask & NH_ATTR_WEIGHT) + nl_dump(dp, " weight %u", nh->rtnh_weight); + + if (nh->ce_mask & NH_ATTR_REALMS) + nl_dump(dp, " realm %04x:%04x", + RTNL_REALM_FROM(nh->rtnh_realms), + RTNL_REALM_TO(nh->rtnh_realms)); + + if (nh->ce_mask & NH_ATTR_FLAGS) + nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags, + buf, sizeof(buf))); +} + +static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + struct nl_cache *link_cache; + char buf[128]; + + link_cache = nl_cache_mngt_require("route/link"); + + if (nh->ce_mask & NH_ATTR_GATEWAY) + nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar, + nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); + + if(nh->ce_mask & NH_ATTR_IFINDEX) { + if (link_cache) { + nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar, + rtnl_link_i2name(link_cache, + nh->rtnh_ifindex, + buf, sizeof(buf))); + } else + nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar, + nh->rtnh_ifindex); + } + + if (nh->ce_mask & NH_ATTR_WEIGHT) + nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar, + nh->rtnh_weight); + + if (nh->ce_mask & NH_ATTR_REALMS) + nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar, + RTNL_REALM_FROM(nh->rtnh_realms), + RTNL_REALM_TO(nh->rtnh_realms)); + + if (nh->ce_mask & NH_ATTR_FLAGS) + nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar, + rtnl_route_nh_flags2str(nh->rtnh_flags, + buf, sizeof(buf))); +} +void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp) +{ + switch (dp->dp_type) { + case NL_DUMP_LINE: + nh_dump_line(nh, dp); + break; + + case NL_DUMP_DETAILS: + case NL_DUMP_STATS: + if (dp->dp_ivar == NH_DUMP_FROM_DETAILS) + nh_dump_details(nh, dp); + break; + + case NL_DUMP_ENV: + nh_dump_env(nh, dp); + break; + + default: + break; + } +} + /** * @name Attributes + * @{ */ -void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, int weight) +void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight) { nh->rtnh_weight = weight; - nh->rtnh_mask |= NEXTHOP_HAS_WEIGHT; + nh->ce_mask |= NH_ATTR_WEIGHT; } -int rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) +uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_WEIGHT) - return nh->rtnh_weight; - else - return 0; + return nh->rtnh_weight; } void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex) { nh->rtnh_ifindex = ifindex; - nh->rtnh_mask |= NEXTHOP_HAS_IFINDEX; + nh->ce_mask |= NH_ATTR_IFINDEX; } int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_IFINDEX) - return nh->rtnh_ifindex; - else - return -1; + return nh->rtnh_ifindex; } void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr) { struct nl_addr *old = nh->rtnh_gateway; - nh->rtnh_gateway = nl_addr_get(addr); + if (addr) { + nh->rtnh_gateway = nl_addr_get(addr); + nh->ce_mask |= NH_ATTR_GATEWAY; + } else { + nh->ce_mask &= ~NH_ATTR_GATEWAY; + nh->rtnh_gateway = NULL; + } + if (old) nl_addr_put(old); - - nh->rtnh_mask |= NEXTHOP_HAS_GATEWAY; } struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY) - return nh->rtnh_gateway; - else - return NULL; + return nh->rtnh_gateway; } void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags) { nh->rtnh_flag_mask |= flags; nh->rtnh_flags |= flags; - nh->rtnh_mask |= NEXTHOP_HAS_FLAGS; + nh->ce_mask |= NH_ATTR_FLAGS; } void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags) { nh->rtnh_flag_mask |= flags; nh->rtnh_flags &= ~flags; - nh->rtnh_mask |= NEXTHOP_HAS_FLAGS; + nh->ce_mask |= NH_ATTR_FLAGS; } unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh) { - if (nh->rtnh_mask & NEXTHOP_HAS_FLAGS) - return nh->rtnh_flags; - else - return 0; + return nh->rtnh_flags; +} + +void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms) +{ + nh->rtnh_realms = realms; + nh->ce_mask |= NH_ATTR_REALMS; +} + +uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh) +{ + return nh->rtnh_realms; +} + +/** @} */ + +/** + * @name Nexthop Flags Translations + * @{ + */ + +static struct trans_tbl nh_flags[] = { + __ADD(RTNH_F_DEAD, dead) + __ADD(RTNH_F_PERVASIVE, pervasive) + __ADD(RTNH_F_ONLINK, onlink) +}; + +char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len) +{ + return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); +} + +int rtnl_route_nh_str2flags(const char *name) +{ + return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); } /** @} */ + /** @} */ diff --git a/lib/route/pktloc.c b/lib/route/pktloc.c new file mode 100644 index 0000000..f0d0155 --- /dev/null +++ b/lib/route/pktloc.c @@ -0,0 +1,168 @@ +/* + * lib/route/pktloc.c Packet Location Aliasing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup tc + * @defgroup pktloc Packet Location Aliasing + * Packet Location Aliasing + * + * The packet location aliasing interface eases the use of offset definitions + * inside packets by allowing them to be referenced by name. Known positions + * of protocol fields are stored in a configuration file and associated with + * a name for later reference. The configuration file is distributed with the + * library and provides a well defined set of definitions for most common + * protocol fields. + * + * @subsection pktloc_examples Examples + * @par Example 1.1 Looking up a packet location + * @code + * struct rtnl_pktloc *loc; + * + * rtnl_pktloc_lookup("ip.src", &loc); + * @endcode + * @{ + */ + +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/route/pktloc.h> + +#include "pktloc_syntax.h" +#include "pktloc_grammar.h" + +/** @cond */ +#define PKTLOC_NAME_HT_SIZ 256 + +static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ]; + +/* djb2 */ +unsigned int pktloc_hash(const char *str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash % PKTLOC_NAME_HT_SIZ; +} + + +void rtnl_pktloc_add(struct rtnl_pktloc *loc) +{ + nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); +} + +extern int pktloc_parse(void *scanner); + +/** @endcond */ + +static void rtnl_pktloc_free(struct rtnl_pktloc *loc) +{ + if (!loc) + return; + + free(loc->name); + free(loc); +} + +static int read_pktlocs(void) +{ + YY_BUFFER_STATE buf; + yyscan_t scanner = NULL; + static time_t last_read; + struct stat st = {0}; + char *path; + int i, err; + FILE *fd; + + asprintf(&path, "%s/pktloc", SYSCONFDIR); + + /* if stat fails, just try to read the file */ + if (stat(path, &st) == 0) { + /* Don't re-read file if file is unchanged */ + if (last_read == st.st_mtime) + return 0; + } + + if (!(fd = fopen(path, "r"))) + return -NLE_PKTLOC_FILE; + + for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) { + struct rtnl_pktloc *loc, *n; + + nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list) + rtnl_pktloc_free(loc); + + nl_init_list_head(&pktloc_name_ht[i]); + } + + if ((err = pktloc_lex_init(&scanner)) < 0) + return -NLE_FAILURE; + + buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner); + pktloc__switch_to_buffer(buf, scanner); + + if ((err = pktloc_parse(scanner)) < 0) + return -NLE_FAILURE; + + if (scanner) + pktloc_lex_destroy(scanner); + + free(path); + last_read = st.st_mtime; + + return 0; +} + +/** + * Lookup packet location alias + * @arg name Name of packet location. + * + * Tries to find a matching packet location alias for the supplied + * packet location name. + * + * The file containing the packet location definitions is automatically + * re-read if its modification time has changed since the last call. + * + * @return 0 on success or a negative error code. + * @retval NLE_PKTLOC_FILE Unable to open packet location file. + * @retval NLE_OBJ_NOTFOUND No matching packet location alias found. + */ +int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result) +{ + struct rtnl_pktloc *loc; + int hash, err; + + if ((err = read_pktlocs()) < 0) + return err; + + hash = pktloc_hash(name); + nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { + if (!strcasecmp(loc->name, name)) { + *result = loc; + return 0; + } + } + + return -NLE_OBJ_NOTFOUND; +} + +static int __init pktloc_init(void) +{ + int i; + + for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) + nl_init_list_head(&pktloc_name_ht[i]); + + return 0; +} diff --git a/lib/route/pktloc_grammar.l b/lib/route/pktloc_grammar.l new file mode 100644 index 0000000..f710430 --- /dev/null +++ b/lib/route/pktloc_grammar.l @@ -0,0 +1,42 @@ +%{ + #include <netlink-local.h> + #include <netlink-tc.h> + #include <netlink/netlink.h> + #include <netlink/utils.h> + #include <netlink/route/pktloc.h> + #include "pktloc_syntax.h" +%} + +%option 8bit +%option reentrant +%option warn +%option noyywrap +%option nounput +%option bison-bridge +%option bison-locations +%option prefix="pktloc_" + +%% + +[ \t\r\n]+ + +"#".* + +[[:digit:]]+ | +0[xX][[:xdigit:]]+ { + yylval->i = strtoul(yytext, NULL, 0); + return NUMBER; + } + +"+" { return yylval->i = yytext[0]; } + +[lL][iI][nN][kK] { yylval->i = TCF_LAYER_LINK; return LAYER; } +[nN][eE][tT] { yylval->i = TCF_LAYER_NETWORK; return LAYER; } +[tT][cC][pP] { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; } + +[^ \t\r\n+]+ { + yylval->s = strdup(yytext); + if (yylval->s == NULL) + return ERROR; + return NAME; + } diff --git a/lib/route/pktloc_syntax.y b/lib/route/pktloc_syntax.y new file mode 100644 index 0000000..05d609a --- /dev/null +++ b/lib/route/pktloc_syntax.y @@ -0,0 +1,108 @@ +%{ +#include <netlink-local.h> +#include <netlink-tc.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/route/pktloc.h> +%} + +%locations +%error-verbose +%define api.pure +%name-prefix "pktloc_" + +%parse-param {void *scanner} +%lex-param {void *scanner} + +%union { + struct rtnl_pktloc *l; + uint32_t i; + char *s; +} + +%{ +extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *); +extern void rtnl_pktloc_add(struct rtnl_pktloc *); + +static void yyerror(YYLTYPE *locp, void *scanner, const char *msg) +{ + /* FIXME */ +} +%} + +%token <i> ERROR NUMBER LAYER +%token <s> NAME + +%type <i> mask layer +%type <l> location + +%destructor { free($$); } NAME + +%start input + +%% + +input: + def + { } + ; + +def: + /* empty */ + { } + | location def + { } + ; + +location: + NAME NAME layer NUMBER mask + { + struct rtnl_pktloc *loc; + + if (!(loc = calloc(1, sizeof(*loc)))) { + /* FIXME */ + } + + if (!strcasecmp($2, "u8")) + loc->align = TCF_EM_ALIGN_U8; + else if (!strcasecmp($2, "h8")) { + loc->align = TCF_EM_ALIGN_U8; + loc->flags = TCF_EM_CMP_TRANS; + } else if (!strcasecmp($2, "u16")) + loc->align = TCF_EM_ALIGN_U16; + else if (!strcasecmp($2, "h16")) { + loc->align = TCF_EM_ALIGN_U16; + loc->flags = TCF_EM_CMP_TRANS; + } else if (!strcasecmp($2, "u32")) + loc->align = TCF_EM_ALIGN_U32; + else if (!strcasecmp($2, "h32")) { + loc->align = TCF_EM_ALIGN_U32; + loc->flags = TCF_EM_CMP_TRANS; + } + + free($2); + + loc->name = $1; + loc->layer = $3; + loc->offset = $4; + loc->mask = $5; + + rtnl_pktloc_add(loc); + + $$ = loc; + } + ; + +layer: + /* empty */ + { $$ = TCF_LAYER_NETWORK; } + | LAYER '+' + { $$ = $1; } + ; + +mask: + /* empty */ + { $$ = 0; } + | NUMBER + { $$ = $1; } + ; diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c index 8eda51b..cfeaf05 100644 --- a/lib/route/qdisc.c +++ b/lib/route/qdisc.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -98,13 +98,13 @@ static struct nl_cache_ops rtnl_qdisc_ops; static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *n, struct nl_parser_param *pp) { - int err = -ENOMEM; + int err; struct rtnl_qdisc *qdisc; struct rtnl_qdisc_ops *qops; qdisc = rtnl_qdisc_alloc(); if (!qdisc) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -122,25 +122,20 @@ static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } err = pp->pp_cb((struct nl_object *) qdisc, pp); - if (err < 0) - goto errout_free; - - err = P_ACCEPT; - errout_free: rtnl_qdisc_put(qdisc); errout: return err; } -static int qdisc_request_update(struct nl_cache *c, struct nl_handle *h) +static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk) { struct tcmsg tchdr = { .tcm_family = AF_UNSPEC, .tcm_ifindex = c->c_iarg1, }; - return nl_send_simple(h, RTM_GETQDISC, NLM_F_DUMP, &tchdr, + return nl_send_simple(sk, RTM_GETQDISC, NLM_F_DUMP, &tchdr, sizeof(tchdr)); } @@ -149,15 +144,15 @@ static int qdisc_request_update(struct nl_cache *c, struct nl_handle *h) * @{ */ -static struct nl_msg *qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags) +static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags, + struct nl_msg **result) { struct rtnl_qdisc_ops *qops; - struct nl_msg *msg; int err; - msg = tca_build_msg((struct rtnl_tca *) qdisc, type, flags); - if (!msg) - goto errout; + err = tca_build_msg((struct rtnl_tca *) qdisc, type, flags, result); + if (err < 0) + return err; qops = rtnl_qdisc_lookup_ops(qdisc); if (qops && qops->qo_get_opts) { @@ -165,24 +160,33 @@ static struct nl_msg *qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags) opts = qops->qo_get_opts(qdisc); if (opts) { - err = nla_put_nested(msg, TCA_OPTIONS, opts); + err = nla_put_nested(*result, TCA_OPTIONS, opts); nlmsg_free(opts); if (err < 0) goto errout; } } + /* Some qdiscs don't accept properly nested messages (e.g. netem). To + * accomodate for this, they can complete the message themselves. + */ + else if (qops && qops->qo_build_msg) { + err = qops->qo_build_msg(qdisc, *result); + if (err < 0) + goto errout; + } - return msg; + return 0; errout: - nlmsg_free(msg); + nlmsg_free(*result); - return NULL; + return err; } /** * Build a netlink message to add a new qdisc * @arg qdisc qdisc to add * @arg flags additional netlink message flags + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting an addition of a qdisc. * The netlink message header isn't fully equipped with all relevant @@ -192,23 +196,17 @@ errout: * Common message flags used: * - NLM_F_REPLACE - replace a potential existing qdisc * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, - int flags) +int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags, + struct nl_msg **result) { - struct nl_msg *msg; - - msg = qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags); - if (!msg) - nl_errno(ENOMEM); - - return msg; + return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags, result); } /** * Add a new qdisc - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg qdisc qdisc to delete * @arg flags additional netlink message flags * @@ -221,22 +219,21 @@ struct nl_msg *rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, * * @return 0 on success or a negative error code */ -int rtnl_qdisc_add(struct nl_handle *handle, struct rtnl_qdisc *qdisc, +int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, int flags) { struct nl_msg *msg; int err; - msg = rtnl_qdisc_build_add_request(qdisc, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -250,23 +247,25 @@ int rtnl_qdisc_add(struct nl_handle *handle, struct rtnl_qdisc *qdisc, * Build a netlink message to change attributes of a existing qdisc * @arg qdisc qdisc to change * @arg new new qdisc attributes + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting an change of qdisc * attributes. The netlink message header isn't fully equipped * with all relevant fields and must be sent out via * nl_send_auto_complete() or supplemented as needed. * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, - struct rtnl_qdisc *new) +int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, + struct nl_msg **result) { - return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE); + return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE, result); } /** * Change attributes of a qdisc - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg qdisc qdisc to change * @arg new new qdisc attributes * @@ -276,22 +275,21 @@ struct nl_msg *rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, * * @return 0 on success or a negative error code */ -int rtnl_qdisc_change(struct nl_handle *handle, struct rtnl_qdisc *qdisc, +int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc, struct rtnl_qdisc *new) { struct nl_msg *msg; int err; - msg = rtnl_qdisc_build_change_request(qdisc, new); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_qdisc_build_change_request(qdisc, new, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -304,15 +302,17 @@ int rtnl_qdisc_change(struct nl_handle *handle, struct rtnl_qdisc *qdisc, /** * Build a netlink request message to delete a qdisc * @arg qdisc qdisc to delete + * @arg result Pointer to store resulting message. * * Builds a new netlink message requesting a deletion of a qdisc. * The netlink message header isn't fully equipped with all relevant * fields and must thus be sent out via nl_send_auto_complete() * or supplemented as needed. * - * @return New netlink message + * @return 0 on success or a negative error code. */ -struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc) +int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc, + struct nl_msg **result) { struct nl_msg *msg; struct tcmsg tchdr; @@ -323,20 +323,24 @@ struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc) msg = nlmsg_alloc_simple(RTM_DELQDISC, 0); if (!msg) - return NULL; - - tchdr.tcm_family = AF_UNSPEC, - tchdr.tcm_handle = qdisc->q_handle, - tchdr.tcm_parent = qdisc->q_parent, - tchdr.tcm_ifindex = qdisc->q_ifindex, - nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO); + return -NLE_NOMEM; + + tchdr.tcm_family = AF_UNSPEC; + tchdr.tcm_handle = qdisc->q_handle; + tchdr.tcm_parent = qdisc->q_parent; + tchdr.tcm_ifindex = qdisc->q_ifindex; + if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) { + nlmsg_free(msg); + return -NLE_MSGSIZE; + } - return msg; + *result = msg; + return 0; } /** * Delete a qdisc - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg qdisc qdisc to delete * * Builds a netlink message by calling rtnl_qdisc_build_delete_request(), @@ -345,21 +349,20 @@ struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc) * * @return 0 on success or a negative error code */ -int rtnl_qdisc_delete(struct nl_handle *handle, struct rtnl_qdisc *qdisc) +int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc) { struct nl_msg *msg; int err; - msg = rtnl_qdisc_build_delete_request(qdisc); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -372,29 +375,17 @@ int rtnl_qdisc_delete(struct nl_handle *handle, struct rtnl_qdisc *qdisc) /** * Build a qdisc cache including all qdiscs currently configured in * the kernel - * @arg handle netlink handle + * @arg sk Netlink socket. + * @arg result Pointer to store resulting message. * * Allocates a new cache, initializes it properly and updates it to * include all qdiscs currently configured in the kernel. * - * @note The caller is responsible for destroying and freeing the - * cache after using it. - * @return The cache or NULL if an error has occured. + * @return 0 on success or a negative error code. */ -struct nl_cache * rtnl_qdisc_alloc_cache(struct nl_handle *handle) +int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result) { - struct nl_cache * cache; - - cache = nl_cache_alloc(&rtnl_qdisc_ops); - if (cache == NULL) - return NULL; - - if (handle && nl_cache_refill(handle, cache) < 0) { - nl_cache_free(cache); - return NULL; - } - - return cache; + return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sk, result); } /** diff --git a/lib/route/qdisc_api.c b/lib/route/qdisc_api.c index ef4d07a..089f212 100644 --- a/lib/route/qdisc_api.c +++ b/lib/route/qdisc_api.c @@ -46,7 +46,7 @@ int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops) for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next) if (!strcasecmp(qops->qo_kind, o->qo_kind)) - return nl_errno(EEXIST); + return -NLE_EXIST; qops->qo_next = NULL; *op = qops; @@ -67,7 +67,7 @@ int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops) break; if (!o) - return nl_errno(ENOENT); + return -NLE_OBJ_NOTFOUND; *op = qops->qo_next; diff --git a/lib/route/qdisc_obj.c b/lib/route/qdisc_obj.c index bbbb954..dc52ae8 100644 --- a/lib/route/qdisc_obj.c +++ b/lib/route/qdisc_obj.c @@ -56,54 +56,49 @@ errout: return err; } -static int qdisc_dump_brief(struct nl_object *obj, struct nl_dump_params *p) +static void qdisc_dump_line(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj; struct rtnl_qdisc_ops *qops; - - int line = tca_dump_brief((struct rtnl_tca *) qdisc, "qdisc", p, 0); + + tca_dump_line((struct rtnl_tca *) qdisc, "qdisc", p); qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_dump[NL_DUMP_BRIEF]) - line = qops->qo_dump[NL_DUMP_BRIEF](qdisc, p, line); + if (qops && qops->qo_dump[NL_DUMP_LINE]) + qops->qo_dump[NL_DUMP_LINE](qdisc, p); - dp_dump(p, "\n"); - - return line; + nl_dump(p, "\n"); } -static int qdisc_dump_full(struct nl_object *arg, struct nl_dump_params *p) +static void qdisc_dump_details(struct nl_object *arg, struct nl_dump_params *p) { struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg; struct rtnl_qdisc_ops *qops; - int line = qdisc_dump_brief(arg, p); + qdisc_dump_line(arg, p); - line = tca_dump_full((struct rtnl_tca *) qdisc, p, line); - dp_dump(p, "refcnt %u ", qdisc->q_info); + tca_dump_details((struct rtnl_tca *) qdisc, p); + nl_dump(p, "refcnt %u ", qdisc->q_info); qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_dump[NL_DUMP_FULL]) - line = qops->qo_dump[NL_DUMP_FULL](qdisc, p, line); + if (qops && qops->qo_dump[NL_DUMP_DETAILS]) + qops->qo_dump[NL_DUMP_DETAILS](qdisc, p); - dp_dump(p, "\n"); - return line; + nl_dump(p, "\n"); } -static int qdisc_dump_stats(struct nl_object *arg, struct nl_dump_params *p) +static void qdisc_dump_stats(struct nl_object *arg, struct nl_dump_params *p) { struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg; struct rtnl_qdisc_ops *qops; - int line = qdisc_dump_full(arg, p); - line = tca_dump_stats((struct rtnl_tca *) qdisc, p, line ); - dp_dump(p, "\n"); + qdisc_dump_details(arg, p); + tca_dump_stats((struct rtnl_tca *) qdisc, p); + nl_dump(p, "\n"); qops = rtnl_qdisc_lookup_ops(qdisc); if (qops && qops->qo_dump[NL_DUMP_STATS]) - line = qops->qo_dump[NL_DUMP_STATS](qdisc, p, line); - - return line; + qops->qo_dump[NL_DUMP_STATS](qdisc, p); } /** @@ -263,9 +258,11 @@ struct nl_object_ops qdisc_obj_ops = { .oo_size = sizeof(struct rtnl_qdisc), .oo_free_data = qdisc_free_data, .oo_clone = qdisc_clone, - .oo_dump[NL_DUMP_BRIEF] = qdisc_dump_brief, - .oo_dump[NL_DUMP_FULL] = qdisc_dump_full, - .oo_dump[NL_DUMP_STATS] = qdisc_dump_stats, + .oo_dump = { + [NL_DUMP_LINE] = qdisc_dump_line, + [NL_DUMP_DETAILS] = qdisc_dump_details, + [NL_DUMP_STATS] = qdisc_dump_stats, + }, .oo_compare = tca_compare, .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), }; diff --git a/lib/route/route.c b/lib/route/route.c index 0644bd7..c85c225 100644 --- a/lib/route/route.c +++ b/lib/route/route.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -27,199 +27,31 @@ static struct nl_cache_ops rtnl_route_ops; -static struct nla_policy route_policy[RTA_MAX+1] = { - [RTA_IIF] = { .type = NLA_STRING, - .maxlen = IFNAMSIZ, }, - [RTA_OIF] = { .type = NLA_U32 }, - [RTA_PRIORITY] = { .type = NLA_U32 }, - [RTA_FLOW] = { .type = NLA_U32 }, - [RTA_MP_ALGO] = { .type = NLA_U32 }, - [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, - [RTA_METRICS] = { .type = NLA_NESTED }, - [RTA_MULTIPATH] = { .type = NLA_NESTED }, -}; - -static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci, - struct rtnl_route *route) -{ - struct rtnl_rtcacheinfo nci = { - .rtci_clntref = ci->rta_clntref, - .rtci_last_use = ci->rta_lastuse, - .rtci_expires = ci->rta_expires, - .rtci_error = ci->rta_error, - .rtci_used = ci->rta_used, - .rtci_id = ci->rta_id, - .rtci_ts = ci->rta_ts, - .rtci_tsage = ci->rta_tsage, - }; - - rtnl_route_set_cacheinfo(route, &nci); -} - static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *nlh, struct nl_parser_param *pp) { - struct rtmsg *rtm; struct rtnl_route *route; - struct nlattr *tb[RTA_MAX + 1]; - struct nl_addr *src = NULL, *dst = NULL, *addr; int err; - route = rtnl_route_alloc(); - if (!route) { - err = nl_errno(ENOMEM); - goto errout; - } - - route->ce_msgtype = nlh->nlmsg_type; - - err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, - route_policy); - if (err < 0) - goto errout; - - rtm = nlmsg_data(nlh); - rtnl_route_set_family(route, rtm->rtm_family); - rtnl_route_set_tos(route, rtm->rtm_tos); - rtnl_route_set_table(route, rtm->rtm_table); - rtnl_route_set_type(route, rtm->rtm_type); - rtnl_route_set_scope(route, rtm->rtm_scope); - rtnl_route_set_protocol(route, rtm->rtm_protocol); - rtnl_route_set_flags(route, rtm->rtm_flags); - - if (tb[RTA_DST]) { - dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family); - if (dst == NULL) - goto errout_errno; - } else { - dst = nl_addr_alloc(0); - nl_addr_set_family(dst, rtm->rtm_family); - } - - nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); - err = rtnl_route_set_dst(route, dst); - if (err < 0) - goto errout; - - nl_addr_put(dst); - - if (tb[RTA_SRC]) { - src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family); - if (src == NULL) - goto errout_errno; - } else if (rtm->rtm_src_len) - src = nl_addr_alloc(0); - - if (src) { - nl_addr_set_prefixlen(src, rtm->rtm_src_len); - rtnl_route_set_src(route, src); - nl_addr_put(src); - } - - if (tb[RTA_IIF]) - rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF])); - - if (tb[RTA_OIF]) - rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF])); - - if (tb[RTA_GATEWAY]) { - addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family); - if (addr == NULL) - goto errout_errno; - rtnl_route_set_gateway(route, addr); - nl_addr_put(addr); - } - - if (tb[RTA_PRIORITY]) - rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY])); - - if (tb[RTA_PREFSRC]) { - addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family); - if (addr == NULL) - goto errout_errno; - rtnl_route_set_pref_src(route, addr); - nl_addr_put(addr); - } - - if (tb[RTA_METRICS]) { - struct nlattr *mtb[RTAX_MAX + 1]; - int i; - - err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); - if (err < 0) - goto errout; - - for (i = 1; i <= RTAX_MAX; i++) { - if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { - uint32_t m = nla_get_u32(mtb[i]); - if (rtnl_route_set_metric(route, i, m) < 0) - goto errout_errno; - } - } - } - - if (tb[RTA_MULTIPATH]) { - struct rtnl_nexthop *nh; - struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]); - size_t tlen = nla_len(tb[RTA_MULTIPATH]); - - while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { - nh = rtnl_route_nh_alloc(); - if (!nh) - goto errout; - - rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); - rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); - rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); - - if (rtnh->rtnh_len > sizeof(*rtnh)) { - struct nlattr *ntb[RTA_MAX + 1]; - nla_parse(ntb, RTA_MAX, (struct nlattr *) - RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof(*rtnh), - route_policy); - - if (ntb[RTA_GATEWAY]) { - nh->rtnh_gateway = nla_get_addr( - ntb[RTA_GATEWAY], - route->rt_family); - nh->rtnh_mask = NEXTHOP_HAS_GATEWAY; - } - } - - rtnl_route_add_nexthop(route, nh); - tlen -= RTNH_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); - } - } - - if (tb[RTA_FLOW]) - rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW])); - - if (tb[RTA_CACHEINFO]) - copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route); - - if (tb[RTA_MP_ALGO]) - rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO])); + if ((err = rtnl_route_parse(nlh, &route)) < 0) + return err; err = pp->pp_cb((struct nl_object *) route, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; -errout: rtnl_route_put(route); return err; - -errout_errno: - err = nl_get_errno(); - goto errout; } -static int route_request_update(struct nl_cache *c, struct nl_handle *h) +static int route_request_update(struct nl_cache *c, struct nl_sock *h) { - return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP); + struct rtmsg rhdr = { + .rtm_family = c->c_iarg1, + }; + + if (c->c_iarg2 & ROUTE_CACHE_CONTENT) + rhdr.rtm_flags |= RTM_F_CLONED; + + return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr)); } /** @@ -229,7 +61,9 @@ static int route_request_update(struct nl_cache *c, struct nl_handle *h) /** * Build a route cache holding all routes currently configured in the kernel - * @arg handle netlink handle + * @arg sk Netlink socket. + * @arg family Address family of routes to cover or AF_UNSPEC + * @arg flags Flags * * Allocates a new cache, initializes it properly and updates it to * contain all routes currently configured in the kernel. @@ -238,20 +72,25 @@ static int route_request_update(struct nl_cache *c, struct nl_handle *h) * cache after using it. * @return The cache or NULL if an error has occured. */ -struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) +int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags, + struct nl_cache **result) { struct nl_cache *cache; + int err; - cache = nl_cache_alloc(&rtnl_route_ops); - if (!cache) - return NULL; + if (!(cache = nl_cache_alloc(&rtnl_route_ops))) + return -NLE_NOMEM; - if (handle && nl_cache_refill(handle, cache) < 0) { + cache->c_iarg1 = family; + cache->c_iarg2 = flags; + + if (sk && (err = nl_cache_refill(sk, cache)) < 0) { free(cache); - return NULL; + return err; } - return cache; + *result = cache; + return 0; } /** @} */ @@ -261,152 +100,67 @@ struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle) * @{ */ -static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd, - int flags) +static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags, + struct nl_msg **result) { struct nl_msg *msg; - struct nl_addr *addr; - int scope, i, oif, nmetrics = 0; - struct nlattr *metrics; - struct rtmsg rtmsg = { - .rtm_family = rtnl_route_get_family(tmpl), - .rtm_dst_len = rtnl_route_get_dst_len(tmpl), - .rtm_src_len = rtnl_route_get_src_len(tmpl), - .rtm_tos = rtnl_route_get_tos(tmpl), - .rtm_table = rtnl_route_get_table(tmpl), - .rtm_type = rtnl_route_get_type(tmpl), - .rtm_protocol = rtnl_route_get_protocol(tmpl), - .rtm_flags = rtnl_route_get_flags(tmpl), - }; - - if (rtmsg.rtm_family == AF_UNSPEC) { - nl_error(EINVAL, "Cannot build route message, address " \ - "family is unknown."); - return NULL; - } - - scope = rtnl_route_get_scope(tmpl); - if (scope == RT_SCOPE_NOWHERE) { - if (rtmsg.rtm_type == RTN_LOCAL) - scope = RT_SCOPE_HOST; - else { - /* XXX Change to UNIVERSE if gw || nexthops */ - scope = RT_SCOPE_LINK; - } - } - - rtmsg.rtm_scope = scope; - - msg = nlmsg_alloc_simple(cmd, flags); - if (msg == NULL) - return NULL; - - if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) - goto nla_put_failure; - - addr = rtnl_route_get_dst(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_DST, addr); - - addr = rtnl_route_get_src(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_SRC, addr); - - addr = rtnl_route_get_gateway(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_GATEWAY, addr); - - addr = rtnl_route_get_pref_src(tmpl); - if (addr) - NLA_PUT_ADDR(msg, RTA_PREFSRC, addr); - - NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl)); - - oif = rtnl_route_get_oif(tmpl); - if (oif != RTNL_LINK_NOT_FOUND) - NLA_PUT_U32(msg, RTA_OIF, oif); - - for (i = 1; i <= RTAX_MAX; i++) - if (rtnl_route_get_metric(tmpl, i) != UINT_MAX) - nmetrics++; - - if (nmetrics > 0) { - unsigned int val; - - metrics = nla_nest_start(msg, RTA_METRICS); - if (metrics == NULL) - goto nla_put_failure; + int err; - for (i = 1; i <= RTAX_MAX; i++) { - val = rtnl_route_get_metric(tmpl, i); - if (val != UINT_MAX) - NLA_PUT_U32(msg, i, val); - } + if (!(msg = nlmsg_alloc_simple(cmd, flags))) + return -NLE_NOMEM; - nla_nest_end(msg, metrics); + if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) { + nlmsg_free(msg); + return err; } -#if 0 - RTA_IIF, - RTA_MULTIPATH, - RTA_PROTOINFO, - RTA_FLOW, - RTA_CACHEINFO, - RTA_SESSION, - RTA_MP_ALGO, -#endif - - return msg; - -nla_put_failure: - nlmsg_free(msg); - return NULL; + *result = msg; + return 0; } -struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags) +int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags, + struct nl_msg **result) { - return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags); + return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags, + result); } -int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route, - int flags) +int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; - msg = rtnl_route_build_add_request(route, flags); - if (!msg) - return nl_get_errno(); + if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } -struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags) +int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags, + struct nl_msg **result) { - return build_route_msg(tmpl, RTM_DELROUTE, flags); + return build_route_msg(tmpl, RTM_DELROUTE, flags, result); } -int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route, - int flags) +int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags) { struct nl_msg *msg; int err; - msg = rtnl_route_build_del_request(route, flags); - if (!msg) - return nl_get_errno(); + if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); nlmsg_free(msg); if (err < 0) return err; - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c index 78e7712..7f26bfd 100644 --- a/lib/route/route_obj.c +++ b/lib/route/route_obj.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -20,14 +20,11 @@ * routing table RT_TABLE_MAIN * scope RT_SCOPE_NOWHERE * tos 0 - * realms 0 * protocol RTPROT_STATIC * prio 0 * family AF_UNSPEC * type RTN_UNICAST - * oif RTNL_LINK_NOT_FOUND * iif NULL - * mpalgo IP_MP_ALG_NONE * @endcode * * @{ @@ -41,6 +38,7 @@ #include <netlink/route/rtnl.h> #include <netlink/route/route.h> #include <netlink/route/link.h> +#include <netlink/route/nexthop.h> /** @cond SKIP */ #define ROUTE_ATTR_FAMILY 0x000001 @@ -61,15 +59,18 @@ #define ROUTE_ATTR_MULTIPATH 0x008000 #define ROUTE_ATTR_REALMS 0x010000 #define ROUTE_ATTR_CACHEINFO 0x020000 -#define ROUTE_ATTR_MP_ALGO 0x040000 /** @endcond */ -static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p); - static void route_constructor(struct nl_object *c) { struct rtnl_route *r = (struct rtnl_route *) c; + r->rt_family = AF_UNSPEC; + r->rt_scope = RT_SCOPE_NOWHERE; + r->rt_table = RT_TABLE_MAIN; + r->rt_protocol = RTPROT_STATIC; + r->rt_type = RTN_UNICAST; + nl_init_list_head(&r->rt_nexthops); } @@ -83,11 +84,10 @@ static void route_free_data(struct nl_object *c) nl_addr_put(r->rt_dst); nl_addr_put(r->rt_src); - nl_addr_put(r->rt_gateway); nl_addr_put(r->rt_pref_src); nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) { - rtnl_route_remove_nexthop(nh); + rtnl_route_remove_nexthop(r, nh); rtnl_route_nh_free(nh); } } @@ -100,366 +100,258 @@ static int route_clone(struct nl_object *_dst, struct nl_object *_src) if (src->rt_dst) if (!(dst->rt_dst = nl_addr_clone(src->rt_dst))) - goto errout; + return -NLE_NOMEM; if (src->rt_src) if (!(dst->rt_src = nl_addr_clone(src->rt_src))) - goto errout; + return -NLE_NOMEM; - if (src->rt_gateway) - if (!(dst->rt_gateway = nl_addr_clone(src->rt_gateway))) - goto errout; - if (src->rt_pref_src) if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src))) - goto errout; + return -NLE_NOMEM; nl_init_list_head(&dst->rt_nexthops); nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) { new = rtnl_route_nh_clone(nh); if (!new) - goto errout; + return -NLE_NOMEM; rtnl_route_add_nexthop(dst, new); } return 0; -errout: - return nl_get_errno(); } -static int route_dump_brief(struct nl_object *a, struct nl_dump_params *p) +static void route_dump_line(struct nl_object *a, struct nl_dump_params *p) { struct rtnl_route *r = (struct rtnl_route *) a; struct nl_cache *link_cache; + int cache = 0, flags; char buf[64]; link_cache = nl_cache_mngt_require("route/link"); + if (r->rt_flags & RTM_F_CLONED) + cache = 1; + + nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf))); + + if (cache) + nl_dump(p, "cache "); + if (!(r->ce_mask & ROUTE_ATTR_DST) || nl_addr_get_len(r->rt_dst) == 0) - dp_dump(p, "default "); + nl_dump(p, "default "); else - dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf))); + nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_OIF) { - if (link_cache) - dp_dump(p, "dev %s ", - rtnl_link_i2name(link_cache, r->rt_oif, - buf, sizeof(buf))); - else - dp_dump(p, "dev %d ", r->rt_oif); - } + if (r->ce_mask & ROUTE_ATTR_TABLE && !cache) + nl_dump(p, "table %s ", + rtnl_route_table2str(r->rt_table, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf, - sizeof(buf))); - else if (r->ce_mask & ROUTE_ATTR_MULTIPATH) - dp_dump(p, "via nexthops "); + if (r->ce_mask & ROUTE_ATTR_TYPE) + nl_dump(p, "type %s ", + nl_rtntype2str(r->rt_type, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump(p, "scope %s ", - rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); + if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0) + nl_dump(p, "tos %#x ", r->rt_tos); - if (r->ce_mask & ROUTE_ATTR_FLAGS && r->rt_flags) { - int flags = r->rt_flags; + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + p->dp_ivar = NH_DUMP_FROM_ONELINE; + rtnl_route_nh_dump(nh, p); + } + } + + flags = r->rt_flags & ~(RTM_F_CLONED); + if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) { + + nl_dump(p, "<"); - dp_dump(p, "<"); - #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \ - flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); } + flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } PRINT_FLAG(DEAD); PRINT_FLAG(ONLINK); PRINT_FLAG(PERVASIVE); #undef PRINT_FLAG #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \ - flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); } + flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); } PRINT_FLAG(NOTIFY); - PRINT_FLAG(CLONED); PRINT_FLAG(EQUALIZE); PRINT_FLAG(PREFIX); #undef PRINT_FLAG - dp_dump(p, ">"); - } +#define PRINT_FLAG(f) if (flags & RTCF_##f) { \ + flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); } + PRINT_FLAG(NOTIFY); + PRINT_FLAG(REDIRECTED); + PRINT_FLAG(DOREDIRECT); + PRINT_FLAG(DIRECTSRC); + PRINT_FLAG(DNAT); + PRINT_FLAG(BROADCAST); + PRINT_FLAG(MULTICAST); + PRINT_FLAG(LOCAL); +#undef PRINT_FLAG - dp_dump(p, "\n"); + nl_dump(p, ">"); + } - return 1; + nl_dump(p, "\n"); } -static int route_dump_full(struct nl_object *a, struct nl_dump_params *p) +static void route_dump_details(struct nl_object *a, struct nl_dump_params *p) { struct rtnl_route *r = (struct rtnl_route *) a; struct nl_cache *link_cache; char buf[128]; - int i, line; + int i; link_cache = nl_cache_mngt_require("route/link"); - line = route_dump_brief(a, p); - if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { - struct rtnl_nexthop *nh; - - nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { - dp_dump_line(p, line++, " via "); - - if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY) - dp_dump(p, "%s ", - nl_addr2str(nh->rtnh_gateway, - buf, sizeof(buf))); - if (link_cache) { - dp_dump(p, "dev %s ", - rtnl_link_i2name(link_cache, - nh->rtnh_ifindex, - buf, sizeof(buf))); - } else - dp_dump(p, "dev %d ", nh->rtnh_ifindex); - - dp_dump(p, "weight %u <%s>\n", nh->rtnh_weight, - rtnl_route_nh_flags2str(nh->rtnh_flags, - buf, sizeof(buf))); - } - } - - dp_dump_line(p, line++, " "); + route_dump_line(a, p); + nl_dump_line(p, " "); if (r->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump(p, "preferred-src %s ", + nl_dump(p, "preferred-src %s ", nl_addr2str(r->rt_pref_src, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_TABLE) - dp_dump(p, "table %s ", - rtnl_route_table2str(r->rt_table, buf, sizeof(buf))); - - if (r->ce_mask & ROUTE_ATTR_TYPE) - dp_dump(p, "type %s ", - nl_rtntype2str(r->rt_type, buf, sizeof(buf))); + if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE) + nl_dump(p, "scope %s ", + rtnl_scope2str(r->rt_scope, buf, sizeof(buf))); if (r->ce_mask & ROUTE_ATTR_PRIO) - dp_dump(p, "metric %#x ", r->rt_prio); - - if (r->ce_mask & ROUTE_ATTR_FAMILY) - dp_dump(p, "family %s ", - nl_af2str(r->rt_family, buf, sizeof(buf))); + nl_dump(p, "priority %#x ", r->rt_prio); if (r->ce_mask & ROUTE_ATTR_PROTOCOL) - dp_dump(p, "protocol %s ", + nl_dump(p, "protocol %s ", rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf))); - dp_dump(p, "\n"); - - if ((r->ce_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS | - ROUTE_ATTR_REALMS)) || - ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && - r->rt_cacheinfo.rtci_error)) { - dp_dump_line(p, line++, " "); - - if (r->ce_mask & ROUTE_ATTR_IIF) - dp_dump(p, "iif %s ", r->rt_iif); + if (r->ce_mask & ROUTE_ATTR_IIF) { + if (link_cache) { + nl_dump(p, "iif %s ", + rtnl_link_i2name(link_cache, r->rt_iif, + buf, sizeof(buf))); + } else + nl_dump(p, "iif %d ", r->rt_iif); + } - if (r->ce_mask & ROUTE_ATTR_SRC) - dp_dump(p, "src %s ", - nl_addr2str(r->rt_src, buf, sizeof(buf))); + if (r->ce_mask & ROUTE_ATTR_SRC) + nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf))); - if (r->ce_mask & ROUTE_ATTR_TOS) - dp_dump(p, "tos %#x ", r->rt_tos); + nl_dump(p, "\n"); - if (r->ce_mask & ROUTE_ATTR_REALMS) - dp_dump(p, "realm %04x:%04x ", - RTNL_REALM_FROM(r->rt_realms), - RTNL_REALM_TO(r->rt_realms)); + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; - if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && - r->rt_cacheinfo.rtci_error) - dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error, - strerror(-r->rt_cacheinfo.rtci_error)); + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + nl_dump_line(p, " "); + p->dp_ivar = NH_DUMP_FROM_DETAILS; + rtnl_route_nh_dump(nh, p); + nl_dump(p, "\n"); + } + } - dp_dump(p, "\n"); + if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) { + nl_dump_line(p, " cacheinfo error %d (%s)\n", + r->rt_cacheinfo.rtci_error, + strerror(-r->rt_cacheinfo.rtci_error)); } if (r->ce_mask & ROUTE_ATTR_METRICS) { - dp_dump_line(p, line++, " "); + nl_dump_line(p, " metrics ["); for (i = 0; i < RTAX_MAX; i++) if (r->rt_metrics_mask & (1 << i)) - dp_dump(p, "%s %u ", + nl_dump(p, "%s %u ", rtnl_route_metric2str(i+1, buf, sizeof(buf)), r->rt_metrics[i]); - dp_dump(p, "\n"); + nl_dump(p, "]\n"); } - - return line; } -static int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_route *route = (struct rtnl_route *) obj; - int line; - line = route_dump_full(obj, p); + route_dump_details(obj, p); if (route->ce_mask & ROUTE_ATTR_CACHEINFO) { struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo; - dp_dump_line(p, line++, " used %u refcnt %u ", - ci->rtci_used, ci->rtci_clntref); - dp_dump_line(p, line++, "last-use %us expires %us\n", + + nl_dump_line(p, " used %u refcnt %u last-use %us " + "expires %us\n", + ci->rtci_used, ci->rtci_clntref, ci->rtci_last_use / nl_get_hz(), ci->rtci_expires / nl_get_hz()); } - - return line; } -static int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p) +static void route_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_route *route = (struct rtnl_route *) obj; + struct nl_cache *link_cache; char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "<route>\n"); - dp_dump_line(p, line++, " <family>%s</family>\n", + + link_cache = nl_cache_mngt_require("route/link"); + + nl_dump_line(p, "ROUTE_FAMILY=%s\n", nl_af2str(route->rt_family, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_DST) - dp_dump_line(p, line++, " <dst>%s</dst>\n", + nl_dump_line(p, "ROUTE_DST=%s\n", nl_addr2str(route->rt_dst, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_SRC) - dp_dump_line(p, line++, " <src>%s</src>\n", + nl_dump_line(p, "ROUTE_SRC=%s\n", nl_addr2str(route->rt_src, buf, sizeof(buf))); - if (route->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump_line(p, line++, " <gateway>%s</gateway>\n", - nl_addr2str(route->rt_gateway, buf, sizeof(buf))); - if (route->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump_line(p, line++, " <prefsrc>%s</prefsrc>\n", + nl_dump_line(p, "ROUTE_PREFSRC=%s\n", nl_addr2str(route->rt_pref_src, buf, sizeof(buf))); - if (route->ce_mask & ROUTE_ATTR_IIF) - dp_dump_line(p, line++, " <iif>%s</iif>\n", route->rt_iif); - - if (route->ce_mask & ROUTE_ATTR_REALMS) - dp_dump_line(p, line++, " <realms>%u</realms>\n", - route->rt_realms); + if (route->ce_mask & ROUTE_ATTR_IIF) { + if (link_cache) { + nl_dump_line(p, "ROUTE_IIF=%s", + rtnl_link_i2name(link_cache, route->rt_iif, + buf, sizeof(buf))); + } else + nl_dump_line(p, "ROUTE_IIF=%d", route->rt_iif); + } if (route->ce_mask & ROUTE_ATTR_TOS) - dp_dump_line(p, line++, " <tos>%u</tos>\n", route->rt_tos); + nl_dump_line(p, "ROUTE_TOS=%u\n", route->rt_tos); if (route->ce_mask & ROUTE_ATTR_TABLE) - dp_dump_line(p, line++, " <table>%u</table>\n", + nl_dump_line(p, "ROUTE_TABLE=%u\n", route->rt_table); if (route->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump_line(p, line++, " <scope>%s</scope>\n", + nl_dump_line(p, "ROUTE_SCOPE=%s\n", rtnl_scope2str(route->rt_scope, buf, sizeof(buf))); if (route->ce_mask & ROUTE_ATTR_PRIO) - dp_dump_line(p, line++, " <metric>%u</metric>\n", + nl_dump_line(p, "ROUTE_PRIORITY=%u\n", route->rt_prio); - if (route->ce_mask & ROUTE_ATTR_OIF) { - struct nl_cache *link_cache; - - link_cache = nl_cache_mngt_require("route/link"); - if (link_cache) - dp_dump_line(p, line++, " <oif>%s</oif>\n", - rtnl_link_i2name(link_cache, - route->rt_oif, - buf, sizeof(buf))); - else - dp_dump_line(p, line++, " <oif>%u</oif>\n", - route->rt_oif); - } - if (route->ce_mask & ROUTE_ATTR_TYPE) - dp_dump_line(p, line++, " <type>%s</type>\n", + nl_dump_line(p, "ROUTE_TYPE=%s\n", nl_rtntype2str(route->rt_type, buf, sizeof(buf))); - dp_dump_line(p, line++, "</route>\n"); - -#if 0 - uint8_t rt_protocol; - uint32_t rt_flags; - uint32_t rt_metrics[RTAX_MAX]; - uint32_t rt_metrics_mask; - struct rtnl_nexthop * rt_nexthops; - struct rtnl_rtcacheinfo rt_cacheinfo; - uint32_t rt_mp_algo; - -#endif - - return line; -} - -static int route_dump_env(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_route *route = (struct rtnl_route *) obj; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n", - nl_af2str(route->rt_family, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_DST) - dp_dump_line(p, line++, "ROUTE_DST=%s\n", - nl_addr2str(route->rt_dst, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_SRC) - dp_dump_line(p, line++, "ROUTE_SRC=%s\n", - nl_addr2str(route->rt_src, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_GATEWAY) - dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n", - nl_addr2str(route->rt_gateway, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_PREF_SRC) - dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n", - nl_addr2str(route->rt_pref_src, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_IIF) - dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif); - - if (route->ce_mask & ROUTE_ATTR_REALMS) - dp_dump_line(p, line++, "ROUTE_REALM=%u\n", - route->rt_realms); - - if (route->ce_mask & ROUTE_ATTR_TOS) - dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos); - - if (route->ce_mask & ROUTE_ATTR_TABLE) - dp_dump_line(p, line++, "ROUTE_TABLE=%u\n", - route->rt_table); - - if (route->ce_mask & ROUTE_ATTR_SCOPE) - dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n", - rtnl_scope2str(route->rt_scope, buf, sizeof(buf))); - - if (route->ce_mask & ROUTE_ATTR_PRIO) - dp_dump_line(p, line++, "ROUTE_METRIC=%u\n", - route->rt_prio); - - if (route->ce_mask & ROUTE_ATTR_OIF) { - struct nl_cache *link_cache; + if (route->ce_mask & ROUTE_ATTR_MULTIPATH) { + struct rtnl_nexthop *nh; + int index = 1; - dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n", - route->rt_oif); + if (route->rt_nr_nh > 0) + nl_dump_line(p, "ROUTE_NR_NH=%u\n", route->rt_nr_nh); - link_cache = nl_cache_mngt_require("route/link"); - if (link_cache) - dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n", - rtnl_link_i2name(link_cache, - route->rt_oif, - buf, sizeof(buf))); + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + p->dp_ivar = index++; + rtnl_route_nh_dump(nh, p); + } } - - if (route->ce_mask & ROUTE_ATTR_TYPE) - dp_dump_line(p, line++, "ROUTE_TYPE=%s\n", - nl_rtntype2str(route->rt_type, buf, sizeof(buf))); - - return line; } static int route_compare(struct nl_object *_a, struct nl_object *_b, @@ -467,7 +359,8 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b, { struct rtnl_route *a = (struct rtnl_route *) _a; struct rtnl_route *b = (struct rtnl_route *) _b; - int diff = 0; + struct rtnl_nexthop *nh_a, *nh_b; + int i, diff = 0, found; #define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR) @@ -477,29 +370,89 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b, diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol); diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope); diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type); - diff |= ROUTE_DIFF(OIF, a->rt_oif != b->rt_oif); diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio); - diff |= ROUTE_DIFF(REALMS, a->rt_realms != b->rt_realms); - diff |= ROUTE_DIFF(MP_ALGO, a->rt_mp_algo != b->rt_mp_algo); diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst)); diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src)); - diff |= ROUTE_DIFF(IIF, strcmp(a->rt_iif, b->rt_iif)); + diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif); diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src, b->rt_pref_src)); - diff |= ROUTE_DIFF(GATEWAY, nl_addr_cmp(a->rt_gateway, - b->rt_gateway)); - /* FIXME: Compare metrics, multipath config */ + if (flags & LOOSE_COMPARISON) { + nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_a, &a->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, + nh_b->ce_mask, 1)) { + found = 1; + break; + } + } + + if (!found) + goto nh_mismatch; + } + + for (i = 0; i < RTAX_MAX - 1; i++) { + if (a->rt_metrics_mask & (1 << i) && + (!(b->rt_metrics_mask & (1 << i)) || + a->rt_metrics[i] != b->rt_metrics[i])) + ROUTE_DIFF(METRICS, 1); + } - if (flags & LOOSE_FLAG_COMPARISON) diff |= ROUTE_DIFF(FLAGS, (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask); - else + } else { + if (a->rt_nr_nh != a->rt_nr_nh) + goto nh_mismatch; + + /* search for a dup in each nh of a */ + nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_b, &b->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) + found = 1; + break; + } + if (!found) + goto nh_mismatch; + } + + /* search for a dup in each nh of b, covers case where a has + * dupes itself */ + nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) { + found = 0; + nl_list_for_each_entry(nh_a, &a->rt_nexthops, + rtnh_list) { + if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) + found = 1; + break; + } + if (!found) + goto nh_mismatch; + } + + for (i = 0; i < RTAX_MAX - 1; i++) { + if ((a->rt_metrics_mask & (1 << i)) ^ + (b->rt_metrics_mask & (1 << i))) + diff |= ROUTE_DIFF(METRICS, 1); + else + diff |= ROUTE_DIFF(METRICS, + a->rt_metrics[i] != b->rt_metrics[i]); + } + diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags); - -#undef ROUTE_DIFF + } +out: return diff; + +nh_mismatch: + diff |= ROUTE_DIFF(MULTIPATH, 1); + goto out; + +#undef ROUTE_DIFF } static struct trans_tbl route_attrs[] = { @@ -521,7 +474,6 @@ static struct trans_tbl route_attrs[] = { __ADD(ROUTE_ATTR_MULTIPATH, multipath) __ADD(ROUTE_ATTR_REALMS, realms) __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo) - __ADD(ROUTE_ATTR_MP_ALGO, mp_algo) }; static char *route_attrs2str(int attrs, char *buf, size_t len) @@ -557,100 +509,82 @@ void rtnl_route_put(struct rtnl_route *route) * @{ */ -void rtnl_route_set_table(struct rtnl_route *route, int table) +void rtnl_route_set_table(struct rtnl_route *route, uint32_t table) { route->rt_table = table; route->ce_mask |= ROUTE_ATTR_TABLE; } -int rtnl_route_get_table(struct rtnl_route *route) +uint32_t rtnl_route_get_table(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_TABLE) - return route->rt_table; - else - return RT_TABLE_MAIN; + return route->rt_table; } -void rtnl_route_set_scope(struct rtnl_route *route, int scope) +void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope) { route->rt_scope = scope; route->ce_mask |= ROUTE_ATTR_SCOPE; } -int rtnl_route_get_scope(struct rtnl_route *route) +uint8_t rtnl_route_get_scope(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_SCOPE) - return route->rt_scope; - else - return RT_SCOPE_NOWHERE; + return route->rt_scope; } -void rtnl_route_set_tos(struct rtnl_route *route, int tos) +void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos) { route->rt_tos = tos; route->ce_mask |= ROUTE_ATTR_TOS; } -int rtnl_route_get_tos(struct rtnl_route *route) +uint8_t rtnl_route_get_tos(struct rtnl_route *route) { return route->rt_tos; } -void rtnl_route_set_realms(struct rtnl_route *route, realm_t realms) -{ - route->rt_realms = realms; - route->ce_mask |= ROUTE_ATTR_REALMS; -} - -realm_t rtnl_route_get_realms(struct rtnl_route *route) +void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol) { - return route->rt_realms; -} - -void rtnl_route_set_protocol(struct rtnl_route *route, int proto) -{ - route->rt_protocol = proto; + route->rt_protocol = protocol; route->ce_mask |= ROUTE_ATTR_PROTOCOL; } -int rtnl_route_get_protocol(struct rtnl_route *route) +uint8_t rtnl_route_get_protocol(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_PROTOCOL) - return route->rt_protocol; - else - return RTPROT_STATIC; + return route->rt_protocol; } -void rtnl_route_set_prio(struct rtnl_route *route, int prio) +void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio) { route->rt_prio = prio; route->ce_mask |= ROUTE_ATTR_PRIO; } -int rtnl_route_get_prio(struct rtnl_route *route) +uint32_t rtnl_route_get_priority(struct rtnl_route *route) { return route->rt_prio; } -void rtnl_route_set_family(struct rtnl_route *route, int family) +int rtnl_route_set_family(struct rtnl_route *route, uint8_t family) { + if (family != AF_INET && family != AF_INET6 && family != AF_DECnet) + return -NLE_AF_NOSUPPORT; + route->rt_family = family; route->ce_mask |= ROUTE_ATTR_FAMILY; + + return 0; } -int rtnl_route_get_family(struct rtnl_route *route) +uint8_t rtnl_route_get_family(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_FAMILY) - return route->rt_family; - else - return AF_UNSPEC; + return route->rt_family; } int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr) { if (route->ce_mask & ROUTE_ATTR_FAMILY) { if (addr->a_family != route->rt_family) - return nl_error(EINVAL, "Address family mismatch"); + return -NLE_AF_MISMATCH; } else route->rt_family = addr->a_family; @@ -670,19 +604,14 @@ struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route) return route->rt_dst; } -int rtnl_route_get_dst_len(struct rtnl_route *route) -{ - if (route->ce_mask & ROUTE_ATTR_DST) - return nl_addr_get_prefixlen(route->rt_dst); - else - return 0; -} - int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr) { + if (addr->a_family == AF_INET) + return -NLE_SRCRT_NOSUPPORT; + if (route->ce_mask & ROUTE_ATTR_FAMILY) { if (addr->a_family != route->rt_family) - return nl_error(EINVAL, "Address family mismatch"); + return -NLE_AF_MISMATCH; } else route->rt_family = addr->a_family; @@ -701,66 +630,37 @@ struct nl_addr *rtnl_route_get_src(struct rtnl_route *route) return route->rt_src; } -int rtnl_route_get_src_len(struct rtnl_route *route) +int rtnl_route_set_type(struct rtnl_route *route, uint8_t type) { - if (route->ce_mask & ROUTE_ATTR_SRC) - return nl_addr_get_prefixlen(route->rt_src); - else - return 0; -} - -int rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr) -{ - if (route->ce_mask & ROUTE_ATTR_FAMILY) { - if (addr->a_family != route->rt_family) - return nl_error(EINVAL, "Address family mismatch"); - } else - route->rt_family = addr->a_family; + if (type > RTN_MAX) + return -NLE_RANGE; - if (route->rt_gateway) - nl_addr_put(route->rt_gateway); - - nl_addr_get(addr); - route->rt_gateway = addr; - route->ce_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY); - - return 0; -} - -struct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route) -{ - return route->rt_gateway; -} - -void rtnl_route_set_type(struct rtnl_route *route, int type) -{ route->rt_type = type; route->ce_mask |= ROUTE_ATTR_TYPE; + + return 0; } -int rtnl_route_get_type(struct rtnl_route *route) +uint8_t rtnl_route_get_type(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_TYPE) - return route->rt_type; - else - return RTN_UNICAST; + return route->rt_type; } -void rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags) +void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags) { route->rt_flag_mask |= flags; route->rt_flags |= flags; route->ce_mask |= ROUTE_ATTR_FLAGS; } -void rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags) +void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags) { route->rt_flag_mask |= flags; route->rt_flags &= ~flags; route->ce_mask |= ROUTE_ATTR_FLAGS; } -unsigned int rtnl_route_get_flags(struct rtnl_route *route) +uint32_t rtnl_route_get_flags(struct rtnl_route *route) { return route->rt_flags; } @@ -768,11 +668,16 @@ unsigned int rtnl_route_get_flags(struct rtnl_route *route) int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value) { if (metric > RTAX_MAX || metric < 1) - return nl_error(EINVAL, "Metric out of range (1..%d)", - RTAX_MAX); + return -NLE_RANGE; route->rt_metrics[metric - 1] = value; - route->rt_metrics_mask |= (1 << (metric - 1)); + + if (!(route->rt_metrics_mask & (1 << (metric - 1)))) { + route->rt_nmetrics++; + route->rt_metrics_mask |= (1 << (metric - 1)); + } + + route->ce_mask |= ROUTE_ATTR_METRICS; return 0; } @@ -780,30 +685,35 @@ int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value) int rtnl_route_unset_metric(struct rtnl_route *route, int metric) { if (metric > RTAX_MAX || metric < 1) - return nl_error(EINVAL, "Metric out of range (1..%d)", - RTAX_MAX); + return -NLE_RANGE; - route->rt_metrics_mask &= ~(1 << (metric - 1)); + if (route->rt_metrics_mask & (1 << (metric - 1))) { + route->rt_nmetrics--; + route->rt_metrics_mask &= ~(1 << (metric - 1)); + } return 0; } -unsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric) +int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value) { if (metric > RTAX_MAX || metric < 1) - return UINT_MAX; + return -NLE_RANGE; if (!(route->rt_metrics_mask & (1 << (metric - 1)))) - return UINT_MAX; + return -NLE_OBJ_NOTFOUND; - return route->rt_metrics[metric - 1]; + if (value) + *value = route->rt_metrics[metric - 1]; + + return 0; } int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr) { if (route->ce_mask & ROUTE_ATTR_FAMILY) { if (addr->a_family != route->rt_family) - return nl_error(EINVAL, "Address family mismatch"); + return -NLE_AF_MISMATCH; } else route->rt_family = addr->a_family; @@ -822,42 +732,27 @@ struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route) return route->rt_pref_src; } -void rtnl_route_set_oif(struct rtnl_route *route, int ifindex) +void rtnl_route_set_iif(struct rtnl_route *route, int ifindex) { - route->rt_oif = ifindex; - route->ce_mask |= ROUTE_ATTR_OIF; -} - -int rtnl_route_get_oif(struct rtnl_route *route) -{ - if (route->ce_mask & ROUTE_ATTR_OIF) - return route->rt_oif; - else - return RTNL_LINK_NOT_FOUND; -} - -void rtnl_route_set_iif(struct rtnl_route *route, const char *name) -{ - strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1); + route->rt_iif = ifindex; route->ce_mask |= ROUTE_ATTR_IIF; } -char *rtnl_route_get_iif(struct rtnl_route *route) +int rtnl_route_get_iif(struct rtnl_route *route) { - if (route->ce_mask & ROUTE_ATTR_IIF) - return route->rt_iif; - else - return NULL; + return route->rt_iif; } void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) { nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops); + route->rt_nr_nh++; route->ce_mask |= ROUTE_ATTR_MULTIPATH; } -void rtnl_route_remove_nexthop(struct rtnl_nexthop *nh) +void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh) { + route->rt_nr_nh--; nl_list_del(&nh->rtnh_list); } @@ -866,44 +761,437 @@ struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route) return &route->rt_nexthops; } -void rtnl_route_set_cacheinfo(struct rtnl_route *route, - struct rtnl_rtcacheinfo *ci) +int rtnl_route_get_nnexthops(struct rtnl_route *route) { - memcpy(&route->rt_cacheinfo, ci, sizeof(*ci)); - route->ce_mask |= ROUTE_ATTR_CACHEINFO; + return route->rt_nr_nh; } -uint32_t rtnl_route_get_mp_algo(struct rtnl_route *route) +void rtnl_route_foreach_nexthop(struct rtnl_route *r, + void (*cb)(struct rtnl_nexthop *, void *), + void *arg) { - if (route->ce_mask & ROUTE_ATTR_MP_ALGO) - return route->rt_mp_algo; - else - return IP_MP_ALG_NONE; + struct rtnl_nexthop *nh; + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH) { + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + cb(nh, arg); + } + } } -void rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo) +struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n) { - route->rt_mp_algo = algo; - route->ce_mask |= ROUTE_ATTR_MP_ALGO; + struct rtnl_nexthop *nh; + int i; + + if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) { + i = 0; + nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) { + if (i == n) return nh; + i++; + } + } + return NULL; } /** @} */ +/** + * @name Utilities + * @{ + */ + +/** + * Guess scope of a route object. + * @arg route Route object. + * + * Guesses the scope of a route object, based on the following rules: + * @code + * 1) Local route -> local scope + * 2) At least one nexthop not directly connected -> universe scope + * 3) All others -> link scope + * @endcode + * + * @return Scope value. + */ +int rtnl_route_guess_scope(struct rtnl_route *route) +{ + if (route->rt_type == RTN_LOCAL) + return RT_SCOPE_HOST; + + if (!nl_list_empty(&route->rt_nexthops)) { + struct rtnl_nexthop *nh; + + /* + * Use scope uiniverse if there is at least one nexthop which + * is not directly connected + */ + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + if (nh->rtnh_gateway) + return RT_SCOPE_UNIVERSE; + } + } + + return RT_SCOPE_LINK; +} + +/** @} */ + +static struct nla_policy route_policy[RTA_MAX+1] = { + [RTA_IIF] = { .type = NLA_U32 }, + [RTA_OIF] = { .type = NLA_U32 }, + [RTA_PRIORITY] = { .type = NLA_U32 }, + [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, + [RTA_METRICS] = { .type = NLA_NESTED }, + [RTA_MULTIPATH] = { .type = NLA_NESTED }, +}; + +static int parse_multipath(struct rtnl_route *route, struct nlattr *attr) +{ + struct rtnl_nexthop *nh = NULL; + struct rtnexthop *rtnh = nla_data(attr); + size_t tlen = nla_len(attr); + int err; + + while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { + nh = rtnl_route_nh_alloc(); + if (!nh) + return -NLE_NOMEM; + + rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops); + rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex); + rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags); + + if (rtnh->rtnh_len > sizeof(*rtnh)) { + struct nlattr *ntb[RTA_MAX + 1]; + + err = nla_parse(ntb, RTA_MAX, (struct nlattr *) + RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh), + route_policy); + if (err < 0) + goto errout; + + if (ntb[RTA_GATEWAY]) { + struct nl_addr *addr; + + addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY], + route->rt_family); + if (!addr) { + err = -NLE_NOMEM; + goto errout; + } + + rtnl_route_nh_set_gateway(nh, addr); + nl_addr_put(addr); + } + + if (ntb[RTA_FLOW]) { + uint32_t realms; + + realms = nla_get_u32(ntb[RTA_FLOW]); + rtnl_route_nh_set_realms(nh, realms); + } + } + + rtnl_route_add_nexthop(route, nh); + tlen -= RTNH_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + err = 0; +errout: + if (err && nh) + rtnl_route_nh_free(nh); + + return err; +} + +int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result) +{ + struct rtmsg *rtm; + struct rtnl_route *route; + struct nlattr *tb[RTA_MAX + 1]; + struct nl_addr *src = NULL, *dst = NULL, *addr; + struct rtnl_nexthop *old_nh = NULL; + int err, family; + + route = rtnl_route_alloc(); + if (!route) { + err = -NLE_NOMEM; + goto errout; + } + + route->ce_msgtype = nlh->nlmsg_type; + + err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy); + if (err < 0) + goto errout; + + rtm = nlmsg_data(nlh); + route->rt_family = family = rtm->rtm_family; + route->rt_tos = rtm->rtm_tos; + route->rt_table = rtm->rtm_table; + route->rt_type = rtm->rtm_type; + route->rt_scope = rtm->rtm_scope; + route->rt_protocol = rtm->rtm_protocol; + route->rt_flags = rtm->rtm_flags; + + route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | + ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE | + ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL | + ROUTE_ATTR_FLAGS; + + if (tb[RTA_DST]) { + if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family))) + goto errout_nomem; + } else { + if (!(dst = nl_addr_alloc(0))) + goto errout_nomem; + nl_addr_set_family(dst, rtm->rtm_family); + } + + nl_addr_set_prefixlen(dst, rtm->rtm_dst_len); + err = rtnl_route_set_dst(route, dst); + if (err < 0) + goto errout; + + nl_addr_put(dst); + + if (tb[RTA_SRC]) { + if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family))) + goto errout_nomem; + } else if (rtm->rtm_src_len) + if (!(src = nl_addr_alloc(0))) + goto errout_nomem; + + if (src) { + nl_addr_set_prefixlen(src, rtm->rtm_src_len); + rtnl_route_set_src(route, src); + nl_addr_put(src); + } + + if (tb[RTA_IIF]) + rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF])); + + if (tb[RTA_PRIORITY]) + rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY])); + + if (tb[RTA_PREFSRC]) { + if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family))) + goto errout_nomem; + rtnl_route_set_pref_src(route, addr); + nl_addr_put(addr); + } + + if (tb[RTA_METRICS]) { + struct nlattr *mtb[RTAX_MAX + 1]; + int i; + + err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); + if (err < 0) + goto errout; + + for (i = 1; i <= RTAX_MAX; i++) { + if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) { + uint32_t m = nla_get_u32(mtb[i]); + if (rtnl_route_set_metric(route, i, m) < 0) + goto errout; + } + } + } + + if (tb[RTA_MULTIPATH]) + if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0) + goto errout; + + if (tb[RTA_CACHEINFO]) { + nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO], + sizeof(route->rt_cacheinfo)); + route->ce_mask |= ROUTE_ATTR_CACHEINFO; + } + + if (tb[RTA_OIF]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF])); + } + + if (tb[RTA_GATEWAY]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family))) + goto errout_nomem; + + rtnl_route_nh_set_gateway(old_nh, addr); + nl_addr_put(addr); + } + + if (tb[RTA_FLOW]) { + if (!old_nh && !(old_nh = rtnl_route_nh_alloc())) + goto errout; + + rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW])); + } + + if (old_nh) { + if (route->rt_nr_nh == 0) { + /* If no nexthops have been provided via RTA_MULTIPATH + * we add it as regular nexthop to maintain backwards + * compatibility */ + rtnl_route_add_nexthop(route, old_nh); + } else { + /* Kernel supports new style nexthop configuration, + * verify that it is a duplicate and discard nexthop. */ + struct rtnl_nexthop *first; + + first = nl_list_first_entry(&route->rt_nexthops, + struct rtnl_nexthop, + rtnh_list); + if (!first) + BUG(); + + if (rtnl_route_nh_compare(old_nh, first, + old_nh->ce_mask, 0)) { + err = -NLE_INVAL; + goto errout; + } + + rtnl_route_nh_free(old_nh); + } + } + + *result = route; + return 0; + +errout: + rtnl_route_put(route); + return err; + +errout_nomem: + err = -NLE_NOMEM; + goto errout; +} + +int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route) +{ + int i; + struct nlattr *metrics; + struct rtmsg rtmsg = { + .rtm_family = route->rt_family, + .rtm_tos = route->rt_tos, + .rtm_table = route->rt_table, + .rtm_protocol = route->rt_protocol, + .rtm_scope = route->rt_scope, + .rtm_type = route->rt_type, + .rtm_flags = route->rt_flags, + }; + + if (route->rt_dst == NULL) + return -NLE_MISSING_ATTR; + + rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst); + if (route->rt_src) + rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src); + + + if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE) + rtmsg.rtm_scope = rtnl_route_guess_scope(route); + + if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + /* Additional table attribute replacing the 8bit in the header, was + * required to allow more than 256 tables. */ + NLA_PUT_U32(msg, RTA_TABLE, route->rt_table); + + if (nl_addr_get_len(route->rt_dst)) + NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst); + NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio); + + if (route->ce_mask & ROUTE_ATTR_SRC) + NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src); + + if (route->ce_mask & ROUTE_ATTR_PREF_SRC) + NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src); + + if (route->ce_mask & ROUTE_ATTR_IIF) + NLA_PUT_U32(msg, RTA_IIF, route->rt_iif); + + if (route->rt_nmetrics > 0) { + uint32_t val; + + metrics = nla_nest_start(msg, RTA_METRICS); + if (metrics == NULL) + goto nla_put_failure; + + for (i = 1; i <= RTAX_MAX; i++) { + if (!rtnl_route_get_metric(route, i, &val)) + NLA_PUT_U32(msg, i, val); + } + + nla_nest_end(msg, metrics); + } + + if (rtnl_route_get_nnexthops(route) > 0) { + struct nlattr *multipath; + struct rtnl_nexthop *nh; + + if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH))) + goto nla_put_failure; + + nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) { + struct rtnexthop *rtnh; + + rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO); + if (!rtnh) + goto nla_put_failure; + + rtnh->rtnh_flags = nh->rtnh_flags; + rtnh->rtnh_hops = nh->rtnh_weight; + rtnh->rtnh_ifindex = nh->rtnh_ifindex; + + if (nh->rtnh_gateway) + NLA_PUT_ADDR(msg, RTA_GATEWAY, + nh->rtnh_gateway); + + if (nh->rtnh_realms) + NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms); + + rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) - + (void *) rtnh; + } + + nla_nest_end(msg, multipath); + } + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** @cond SKIP */ struct nl_object_ops route_obj_ops = { .oo_name = "route/route", .oo_size = sizeof(struct rtnl_route), .oo_constructor = route_constructor, .oo_free_data = route_free_data, .oo_clone = route_clone, - .oo_dump[NL_DUMP_BRIEF] = route_dump_brief, - .oo_dump[NL_DUMP_FULL] = route_dump_full, - .oo_dump[NL_DUMP_STATS] = route_dump_stats, - .oo_dump[NL_DUMP_XML] = route_dump_xml, - .oo_dump[NL_DUMP_ENV] = route_dump_env, + .oo_dump = { + [NL_DUMP_LINE] = route_dump_line, + [NL_DUMP_DETAILS] = route_dump_details, + [NL_DUMP_STATS] = route_dump_stats, + [NL_DUMP_ENV] = route_dump_env, + }, .oo_compare = route_compare, .oo_attrs2str = route_attrs2str, .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | ROUTE_ATTR_TABLE | ROUTE_ATTR_DST), }; +/** @endcond */ /** @} */ diff --git a/lib/route/route_utils.c b/lib/route/route_utils.c index a12d169..41ae65c 100644 --- a/lib/route/route_utils.c +++ b/lib/route/route_utils.c @@ -63,6 +63,11 @@ static void __init init_routing_table_names(void) add_routing_table_name(RT_TABLE_LOCAL, "local"); }; +static void __exit release_routing_table_names(void) +{ + __trans_list_clear(&table_names); +} + int rtnl_route_read_table_names(const char *path) { __trans_list_clear(&table_names); @@ -104,6 +109,11 @@ static void __init init_proto_names(void) add_proto_name(RTPROT_STATIC, "static"); }; +static void __exit release_proto_names(void) +{ + __trans_list_clear(&proto_names); +} + int rtnl_route_read_protocol_names(const char *path) { __trans_list_clear(&proto_names); @@ -157,27 +167,4 @@ int rtnl_route_str2metric(const char *name) /** @} */ -/** - * @name Nexthop Flags Translations - * @{ - */ - -static struct trans_tbl nh_flags[] = { - __ADD(RTNH_F_DEAD, dead) - __ADD(RTNH_F_PERVASIVE, pervasive) - __ADD(RTNH_F_ONLINK, onlink) -}; - -char * rtnl_route_nh_flags2str(int flags, char *buf, size_t len) -{ - return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags)); -} - -int rtnl_route_nh_str2flags(const char *name) -{ - return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags)); -} - -/** @} */ - /** @} */ diff --git a/lib/route/rtnl.c b/lib/route/rtnl.c index 81ddf94..2533674 100644 --- a/lib/route/rtnl.c +++ b/lib/route/rtnl.c @@ -6,12 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup nlfam - * @defgroup rtnl Routing Netlink + * @defgroup rtnl Routing Family * @{ */ @@ -27,7 +26,7 @@ /** * Send routing netlink request message - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg type Netlink message type. * @arg family Address family. * @arg flags Additional netlink message flags. @@ -37,13 +36,13 @@ * * @return 0 on success or a negative error code. */ -int nl_rtgen_request(struct nl_handle *handle, int type, int family, int flags) +int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags) { struct rtgenmsg gmsg = { .rtgen_family = family, }; - return nl_send_simple(handle, type, flags, &gmsg, sizeof(gmsg)); + return nl_send_simple(sk, type, flags, &gmsg, sizeof(gmsg)); } /** @} */ diff --git a/lib/route/rule.c b/lib/route/rule.c index 60defd7..126e96d 100644 --- a/lib/route/rule.c +++ b/lib/route/rule.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -60,15 +60,13 @@ static int rule_clone(struct nl_object *_dst, struct nl_object *_src) if (src->r_src) if (!(dst->r_src = nl_addr_clone(src->r_src))) - goto errout; + return -NLE_NOMEM; if (src->r_dst) if (!(dst->r_dst = nl_addr_clone(src->r_dst))) - goto errout; + return -NLE_NOMEM; return 0; -errout: - return nl_get_errno(); } static struct nla_policy rule_policy[RTA_MAX+1] = { @@ -85,11 +83,11 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct rtnl_rule *rule; struct rtmsg *r; struct nlattr *tb[RTA_MAX+1]; - int err = 1; + int err = 1, family; rule = rtnl_rule_alloc(); if (!rule) { - err = nl_errno(ENOMEM); + err = -NLE_NOMEM; goto errout; } @@ -100,14 +98,15 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, if (err < 0) goto errout; - rule->r_family = r->rtm_family; + rule->r_family = family = r->rtm_family; rule->r_type = r->rtm_type; rule->r_dsfield = r->rtm_tos; rule->r_src_len = r->rtm_src_len; rule->r_dst_len = r->rtm_dst_len; rule->r_table = r->rtm_table; rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TYPE | RULE_ATTR_DSFIELD | - RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE); + RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE | + RULE_ATTR_TABLE); if (tb[RTA_PRIORITY]) { rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]); @@ -115,21 +114,15 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } if (tb[RTA_SRC]) { - rule->r_src = nla_get_addr(tb[RTA_SRC], r->rtm_family); - if (!rule->r_src) { - err = nl_errno(ENOMEM); - goto errout; - } + if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family))) + goto errout_enomem; nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len); rule->ce_mask |= RULE_ATTR_SRC; } if (tb[RTA_DST]) { - rule->r_dst = nla_get_addr(tb[RTA_DST], r->rtm_family); - if (!rule->r_dst) { - err = nl_errno(ENOMEM); - goto errout; - } + if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family))) + goto errout_enomem; nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len); rule->ce_mask |= RULE_ATTR_DST; } @@ -150,216 +143,135 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } if (tb[RTA_GATEWAY]) { - rule->r_srcmap = nla_get_addr(tb[RTA_GATEWAY], r->rtm_family); - if (!rule->r_srcmap) { - err = nl_errno(ENOMEM); - goto errout; - } + rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family); + if (!rule->r_srcmap) + goto errout_enomem; rule->ce_mask |= RULE_ATTR_SRCMAP; } - err = pp->pp_cb((struct nl_object *) rule, pp); - if (err < 0) - goto errout; - - err = P_ACCEPT; + if (tb[RTA_TABLE]) { + rule->r_table = nla_get_u32(tb[RTA_TABLE]); + rule->ce_mask |= RULE_ATTR_TABLE; + } + err = pp->pp_cb((struct nl_object *) rule, pp); errout: rtnl_rule_put(rule); return err; + +errout_enomem: + err = -NLE_NOMEM; + goto errout; } -static int rule_request_update(struct nl_cache *c, struct nl_handle *h) +static int rule_request_update(struct nl_cache *c, struct nl_sock *h) { return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP); } -static int rule_dump_brief(struct nl_object *o, struct nl_dump_params *p) +static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p) { struct rtnl_rule *r = (struct rtnl_rule *) o; char buf[128]; - if (r->ce_mask & RULE_ATTR_PRIO) - dp_dump(p, "%d:\t", r->r_prio); - else - dp_dump(p, "0:\t"); + nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0); + nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf))); if (r->ce_mask & RULE_ATTR_SRC) - dp_dump(p, "from %s ", + nl_dump(p, "from %s ", nl_addr2str(r->r_src, buf, sizeof(buf))); else if (r->ce_mask & RULE_ATTR_SRC_LEN && r->r_src_len) - dp_dump(p, "from 0/%d ", r->r_src_len); + nl_dump(p, "from 0/%d ", r->r_src_len); if (r->ce_mask & RULE_ATTR_DST) - dp_dump(p, "to %s ", + nl_dump(p, "to %s ", nl_addr2str(r->r_dst, buf, sizeof(buf))); else if (r->ce_mask & RULE_ATTR_DST_LEN && r->r_dst_len) - dp_dump(p, "to 0/%d ", r->r_dst_len); + nl_dump(p, "to 0/%d ", r->r_dst_len); if (r->ce_mask & RULE_ATTR_DSFIELD && r->r_dsfield) - dp_dump(p, "tos %d ", r->r_dsfield); + nl_dump(p, "tos %d ", r->r_dsfield); if (r->ce_mask & RULE_ATTR_MARK) - dp_dump(p, "mark %" PRIx64 , r->r_mark); + nl_dump(p, "mark %" PRIx64 , r->r_mark); if (r->ce_mask & RULE_ATTR_IIF) - dp_dump(p, "iif %s ", r->r_iif); + nl_dump(p, "iif %s ", r->r_iif); if (r->ce_mask & RULE_ATTR_TABLE) - dp_dump(p, "lookup %s ", + nl_dump(p, "lookup %s ", rtnl_route_table2str(r->r_table, buf, sizeof(buf))); if (r->ce_mask & RULE_ATTR_REALMS) - dp_dump(p, "realms %s ", + nl_dump(p, "realms %s ", rtnl_realms2str(r->r_realms, buf, sizeof(buf))); - dp_dump(p, "action %s\n", + nl_dump(p, "action %s\n", nl_rtntype2str(r->r_type, buf, sizeof(buf))); - - return 1; } -static int rule_dump_full(struct nl_object *obj, struct nl_dump_params *p) +static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_rule *rule = (struct rtnl_rule *) obj; char buf[128]; - int line; - line = rule_dump_brief(obj, p); - - dp_dump_line(p, line++, " family %s", - nl_af2str(rule->r_family, buf, sizeof(buf))); + rule_dump_line(obj, p); if (rule->ce_mask & RULE_ATTR_SRCMAP) - dp_dump(p, " srcmap %s", + nl_dump_line(p, " srcmap %s\n", nl_addr2str(rule->r_srcmap, buf, sizeof(buf))); - - dp_dump(p, "\n"); - - return line; } -static int rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p) { - return rule_dump_full(obj, p); + rule_dump_details(obj, p); } -static int rule_dump_xml(struct nl_object *obj, struct nl_dump_params *p) +static void rule_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_rule *rule = (struct rtnl_rule *) obj; char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "<rule>\n"); - dp_dump_line(p, line++, " <priority>%u</priority>\n", - rule->r_prio); - dp_dump_line(p, line++, " <family>%s</family>\n", + nl_dump_line(p, "RULE_PRIORITY=%u\n", rule->r_prio); + nl_dump_line(p, "RULE_FAMILY=%s\n", nl_af2str(rule->r_family, buf, sizeof(buf))); if (rule->ce_mask & RULE_ATTR_DST) - dp_dump_line(p, line++, " <dst>%s</dst>\n", + nl_dump_line(p, "RULE_DST=%s\n", nl_addr2str(rule->r_dst, buf, sizeof(buf))); if (rule->ce_mask & RULE_ATTR_DST_LEN) - dp_dump_line(p, line++, " <dstlen>%u</dstlen>\n", - rule->r_dst_len); + nl_dump_line(p, "RULE_DSTLEN=%u\n", rule->r_dst_len); if (rule->ce_mask & RULE_ATTR_SRC) - dp_dump_line(p, line++, " <src>%s</src>\n", + nl_dump_line(p, "RULE_SRC=%s\n", nl_addr2str(rule->r_src, buf, sizeof(buf))); if (rule->ce_mask & RULE_ATTR_SRC_LEN) - dp_dump_line(p, line++, " <srclen>%u</srclen>\n", - rule->r_src_len); + nl_dump_line(p, "RULE_SRCLEN=%u\n", rule->r_src_len); if (rule->ce_mask & RULE_ATTR_IIF) - dp_dump_line(p, line++, " <iif>%s</iif>\n", rule->r_iif); + nl_dump_line(p, "RULE_IIF=%s\n", rule->r_iif); if (rule->ce_mask & RULE_ATTR_TABLE) - dp_dump_line(p, line++, " <table>%u</table>\n", - rule->r_table); + nl_dump_line(p, "RULE_TABLE=%u\n", rule->r_table); if (rule->ce_mask & RULE_ATTR_REALMS) - dp_dump_line(p, line++, " <realms>%u</realms>\n", - rule->r_realms); + nl_dump_line(p, "RULE_REALM=%u\n", rule->r_realms); if (rule->ce_mask & RULE_ATTR_MARK) - dp_dump_line(p, line++, " <mark>%" PRIx64 "</mark>\n", - rule->r_mark); + nl_dump_line(p, "RULE_MARK=0x%" PRIx64 "\n", rule->r_mark); if (rule->ce_mask & RULE_ATTR_DSFIELD) - dp_dump_line(p, line++, " <dsfield>%u</dsfield>\n", - rule->r_dsfield); + nl_dump_line(p, "RULE_DSFIELD=%u\n", rule->r_dsfield); if (rule->ce_mask & RULE_ATTR_TYPE) - dp_dump_line(p, line++, "<type>%s</type>\n", + nl_dump_line(p, "RULE_TYPE=%s\n", nl_rtntype2str(rule->r_type, buf, sizeof(buf))); if (rule->ce_mask & RULE_ATTR_SRCMAP) - dp_dump_line(p, line++, "<srcmap>%s</srcmap>\n", + nl_dump_line(p, "RULE_SRCMAP=%s\n", nl_addr2str(rule->r_srcmap, buf, sizeof(buf))); - - dp_dump_line(p, line++, "</rule>\n"); - - return line; -} - -static int rule_dump_env(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_rule *rule = (struct rtnl_rule *) obj; - char buf[128]; - int line = 0; - - dp_dump_line(p, line++, "RULE_PRIORITY=%u\n", - rule->r_prio); - dp_dump_line(p, line++, "RULE_FAMILY=%s\n", - nl_af2str(rule->r_family, buf, sizeof(buf))); - - if (rule->ce_mask & RULE_ATTR_DST) - dp_dump_line(p, line++, "RULE_DST=%s\n", - nl_addr2str(rule->r_dst, buf, sizeof(buf))); - - if (rule->ce_mask & RULE_ATTR_DST_LEN) - dp_dump_line(p, line++, "RULE_DSTLEN=%u\n", - rule->r_dst_len); - - if (rule->ce_mask & RULE_ATTR_SRC) - dp_dump_line(p, line++, "RULE_SRC=%s\n", - nl_addr2str(rule->r_src, buf, sizeof(buf))); - - if (rule->ce_mask & RULE_ATTR_SRC_LEN) - dp_dump_line(p, line++, "RULE_SRCLEN=%u\n", - rule->r_src_len); - - if (rule->ce_mask & RULE_ATTR_IIF) - dp_dump_line(p, line++, "RULE_IIF=%s\n", rule->r_iif); - - if (rule->ce_mask & RULE_ATTR_TABLE) - dp_dump_line(p, line++, "RULE_TABLE=%u\n", - rule->r_table); - - if (rule->ce_mask & RULE_ATTR_REALMS) - dp_dump_line(p, line++, "RULE_REALM=%u\n", - rule->r_realms); - - if (rule->ce_mask & RULE_ATTR_MARK) - dp_dump_line(p, line++, "RULE_MARK=0x%" PRIx64 "\n", - rule->r_mark); - - if (rule->ce_mask & RULE_ATTR_DSFIELD) - dp_dump_line(p, line++, "RULE_DSFIELD=%u\n", - rule->r_dsfield); - - if (rule->ce_mask & RULE_ATTR_TYPE) - dp_dump_line(p, line++, "RULE_TYPE=%s\n", - nl_rtntype2str(rule->r_type, buf, sizeof(buf))); - - if (rule->ce_mask & RULE_ATTR_SRCMAP) - dp_dump_line(p, line++, "RULE_SRCMAP=%s\n", - nl_addr2str(rule->r_srcmap, buf, sizeof(buf))); - - return line; } static int rule_compare(struct nl_object *_a, struct nl_object *_b, @@ -434,51 +346,34 @@ void rtnl_rule_put(struct rtnl_rule *rule) */ /** - * Build a rule cache including all rules of the specified family currently configured in the kernel. - * @arg handle netlink handle - * @arg family address family + * Build a rule cache including all rules currently configured in the kernel. + * @arg sk Netlink socket. + * @arg family Address family or AF_UNSPEC. + * @arg result Pointer to store resulting cache. * * Allocates a new rule cache, initializes it properly and updates it - * to include all rules of the specified address family currently - * configured in the kernel. + * to include all rules currently configured in the kernel. * - * @note The caller is responsible for destroying and freeing the - * cache after using it. (nl_cache_destroy_and_free()) - * @return The new cache or NULL if an error occured. + * @return 0 on success or a negative error code. */ -struct nl_cache * rtnl_rule_alloc_cache_by_family(struct nl_handle *handle, - int family) +int rtnl_rule_alloc_cache(struct nl_sock *sock, int family, + struct nl_cache **result) { struct nl_cache * cache; + int err; - cache = nl_cache_alloc(&rtnl_rule_ops); - if (cache == NULL) - return NULL; + if (!(cache = nl_cache_alloc(&rtnl_rule_ops))) + return -NLE_NOMEM; - /* XXX RULE_CACHE_FAMILY(cache) = family; */ + cache->c_iarg1 = family; - if (handle && nl_cache_refill(handle, cache) < 0) { + if (sock && (err = nl_cache_refill(sock, cache)) < 0) { free(cache); - return NULL; + return err; } - return cache; -} - -/** - * Build a rule cache including all rules currently configured in the kernel. - * @arg handle netlink handle - * - * Allocates a new rule cache, initializes it properly and updates it - * to include all rules currently configured in the kernel. - * - * @note The caller is responsible for destroying and freeing the - * cache after using it. (nl_cache_destroy_and_free()) - * @return The new cache or NULL if an error occured. - */ -struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *handle) -{ - return rtnl_rule_alloc_cache_by_family(handle, AF_UNSPEC); + *result = cache; + return 0; } /** @} */ @@ -488,7 +383,8 @@ struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *handle) * @{ */ -static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags) +static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags, + struct nl_msg **result) { struct nl_msg *msg; struct rtmsg rtm = { @@ -518,7 +414,7 @@ static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags) msg = nlmsg_alloc_simple(cmd, flags); if (!msg) - goto nla_put_failure; + return -NLE_NOMEM; if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -541,11 +437,12 @@ static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags) if (tmpl->ce_mask & RULE_ATTR_IIF) NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif); - return msg; + *result = msg; + return 0; nla_put_failure: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** @@ -561,14 +458,16 @@ nla_put_failure: * * @return The netlink message */ -struct nl_msg *rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags) +int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags, + struct nl_msg **result) { - return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags); + return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags, + result); } /** * Add a new rule - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg tmpl template with requested changes * @arg flags additional netlink message flags * @@ -578,21 +477,20 @@ struct nl_msg *rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl, int flags) +int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_rule_build_add_request(tmpl, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -615,14 +513,15 @@ int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl, int flags) * * @return The netlink message */ -struct nl_msg *rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags) +int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags, + struct nl_msg **result) { - return build_rule_msg(rule, RTM_DELRULE, flags); + return build_rule_msg(rule, RTM_DELRULE, flags, result); } /** * Delete a rule - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg rule rule to delete * @arg flags additional netlink message flags * @@ -632,22 +531,20 @@ struct nl_msg *rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags) * * @return 0 on sucess or a negative error if an error occured. */ -int rtnl_rule_delete(struct nl_handle *handle, struct rtnl_rule *rule, - int flags) +int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags) { - int err; struct nl_msg *msg; + int err; - msg = rtnl_rule_build_delete_request(rule, flags); - if (!msg) - return nl_errno(ENOMEM); + if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0) + return err; - err = nl_send_auto_complete(handle, msg); + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); if (err < 0) return err; - nlmsg_free(msg); - return nl_wait_for_ack(handle); + return wait_for_ack(sk); } /** @} */ @@ -764,7 +661,7 @@ static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos, { if (rule->ce_mask & RULE_ATTR_FAMILY) { if (new->a_family != rule->r_family) - return nl_error(EINVAL, "Address family mismatch"); + return -NLE_AF_MISMATCH; } else rule->r_family = new->a_family; @@ -811,7 +708,7 @@ struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule) int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev) { if (strlen(dev) > IFNAMSIZ-1) - return nl_errno(ERANGE); + return -NLE_RANGE; strcpy(rule->r_iif, dev); rule->ce_mask |= RULE_ATTR_IIF; @@ -837,16 +734,16 @@ int rtnl_rule_get_action(struct rtnl_rule *rule) if (rule->ce_mask & RULE_ATTR_TYPE) return rule->r_type; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } -void rtnl_rule_set_realms(struct rtnl_rule *rule, realm_t realms) +void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms) { rule->r_realms = realms; rule->ce_mask |= RULE_ATTR_REALMS; } -realm_t rtnl_rule_get_realms(struct rtnl_rule *rule) +uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule) { if (rule->ce_mask & RULE_ATTR_REALMS) return rule->r_realms; @@ -861,11 +758,12 @@ static struct nl_object_ops rule_obj_ops = { .oo_size = sizeof(struct rtnl_rule), .oo_free_data = rule_free_data, .oo_clone = rule_clone, - .oo_dump[NL_DUMP_BRIEF] = rule_dump_brief, - .oo_dump[NL_DUMP_FULL] = rule_dump_full, - .oo_dump[NL_DUMP_STATS] = rule_dump_stats, - .oo_dump[NL_DUMP_XML] = rule_dump_xml, - .oo_dump[NL_DUMP_ENV] = rule_dump_env, + .oo_dump = { + [NL_DUMP_LINE] = rule_dump_line, + [NL_DUMP_DETAILS] = rule_dump_details, + [NL_DUMP_STATS] = rule_dump_stats, + [NL_DUMP_ENV] = rule_dump_env, + }, .oo_compare = rule_compare, .oo_attrs2str = rule_attrs2str, .oo_id_attrs = ~0, diff --git a/lib/route/sch/cbq.c b/lib/route/sch/cbq.c index 9808509..1aaa58d 100644 --- a/lib/route/sch/cbq.c +++ b/lib/route/sch/cbq.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ #include <netlink-local.h> @@ -99,7 +99,7 @@ static int cbq_msg_parser(struct rtnl_tca *tca) cbq = cbq_alloc(tca); if (!cbq) - return nl_errno(ENOMEM); + return -NLE_NOMEM; nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss)); nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate)); @@ -133,7 +133,7 @@ static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src) struct rtnl_cbq *src = cbq_qdisc(_src); if (src && !cbq_alloc(_dst)) - return nl_errno(ENOMEM); + return -NLE_NOMEM; else return 0; } @@ -153,8 +153,7 @@ static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src) return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src); } -static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p, - int line) +static void cbq_dump_line(struct rtnl_tca *tca, struct nl_dump_params *p) { struct rtnl_cbq *cbq; double r, rbit; @@ -162,32 +161,28 @@ static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p, cbq = cbq_qdisc(tca); if (!cbq) - goto ignore; + return; r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); - dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", + nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", r, ru, rbit, rubit, cbq->cbq_wrr.priority); - -ignore: - return line; } -static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void cbq_qdisc_dump_line(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p) { - return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line); + cbq_dump_line((struct rtnl_tca *) qdisc, p); } -static int cbq_class_dump_brief(struct rtnl_class *class, - struct nl_dump_params *p, int line) +static void cbq_class_dump_line(struct rtnl_class *class, + struct nl_dump_params *p) { - return cbq_dump_brief((struct rtnl_tca *) class, p, line); + cbq_dump_line((struct rtnl_tca *) class, p); } -static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p, - int line) +static void cbq_dump_details(struct rtnl_tca *tca, struct nl_dump_params *p) { struct rtnl_cbq *cbq; char *unit, buf[32]; @@ -196,18 +191,18 @@ static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p, cbq = cbq_qdisc(tca); if (!cbq) - goto ignore; + return; w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); - dp_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", + nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", cbq->cbq_lss.avpkt, cbq->cbq_rate.mpu, 1 << cbq->cbq_rate.cell_log, cbq->cbq_wrr.allot, w, unit); el = cbq->cbq_lss.ewma_log; - dp_dump_line(p, line++, " minidle %uus maxidle %uus offtime " + nl_dump_line(p, " minidle %uus maxidle %uus offtime " "%uus level %u ewma_log %u\n", nl_ticks2us(cbq->cbq_lss.minidle >> el), nl_ticks2us(cbq->cbq_lss.maxidle >> el), @@ -215,60 +210,53 @@ static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p, cbq->cbq_lss.level, cbq->cbq_lss.ewma_log); - dp_dump_line(p, line++, " penalty %uus strategy %s ", + nl_dump_line(p, " penalty %uus strategy %s ", nl_ticks2us(cbq->cbq_ovl.penalty), nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); - dp_dump(p, "split %s defmap 0x%08x ", + nl_dump(p, "split %s defmap 0x%08x ", rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), cbq->cbq_fopt.defmap); - dp_dump(p, "police %s", + nl_dump(p, "police %s", nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); - -ignore: - return line; } -static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void cbq_qdisc_dump_details(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p) { - return cbq_dump_full((struct rtnl_tca *) qdisc, p, line); + cbq_dump_details((struct rtnl_tca *) qdisc, p); } -static int cbq_class_dump_full(struct rtnl_class *class, - struct nl_dump_params *p, int line) +static void cbq_class_dump_details(struct rtnl_class *class, + struct nl_dump_params *p) { - return cbq_dump_full((struct rtnl_tca *) class, p, line); + cbq_dump_details((struct rtnl_tca *) class, p); } -static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p, - int line) +static void cbq_dump_stats(struct rtnl_tca *tca, struct nl_dump_params *p) { struct tc_cbq_xstats *x = tca_xstats(tca); if (!x) - goto ignore; + return; - dp_dump_line(p, line++, " borrows overact " - " avgidle undertime\n"); - dp_dump_line(p, line++, " %10u %10u %10u %10u\n", + nl_dump_line(p, " borrows overact " + " avgidle undertime\n"); + nl_dump_line(p, " %10u %10u %10u %10u\n", x->borrows, x->overactions, x->avgidle, x->undertime); - -ignore: - return line; } -static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void cbq_qdisc_dump_stats(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p) { - return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line); + cbq_dump_stats((struct rtnl_tca *) qdisc, p); } -static int cbq_class_dump_with_stats(struct rtnl_class *class, - struct nl_dump_params *p, int line) +static void cbq_class_dump_stats(struct rtnl_class *class, + struct nl_dump_params *p) { - return cbq_dump_with_stats((struct rtnl_tca *) class, p, line); + cbq_dump_stats((struct rtnl_tca *) class, p); } static struct rtnl_qdisc_ops cbq_qdisc_ops = { @@ -276,9 +264,11 @@ static struct rtnl_qdisc_ops cbq_qdisc_ops = { .qo_msg_parser = cbq_qdisc_msg_parser, .qo_free_data = cbq_qdisc_free_data, .qo_clone = cbq_qdisc_clone, - .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief, - .qo_dump[NL_DUMP_FULL] = cbq_qdisc_dump_full, - .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats, + .qo_dump = { + [NL_DUMP_LINE] = cbq_qdisc_dump_line, + [NL_DUMP_DETAILS] = cbq_qdisc_dump_details, + [NL_DUMP_STATS] = cbq_qdisc_dump_stats, + }, }; static struct rtnl_class_ops cbq_class_ops = { @@ -286,9 +276,11 @@ static struct rtnl_class_ops cbq_class_ops = { .co_msg_parser = cbq_class_msg_parser, .co_free_data = cbq_class_free_data, .co_clone = cbq_class_clone, - .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief, - .co_dump[NL_DUMP_FULL] = cbq_class_dump_full, - .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats, + .co_dump = { + [NL_DUMP_LINE] = cbq_class_dump_line, + [NL_DUMP_DETAILS] = cbq_class_dump_details, + [NL_DUMP_STATS] = cbq_class_dump_stats, + }, }; static void __init cbq_init(void) diff --git a/lib/route/sch/dsmark.c b/lib/route/sch/dsmark.c index 5ba6b92..61b0fea 100644 --- a/lib/route/sch/dsmark.c +++ b/lib/route/sch/dsmark.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -70,7 +70,7 @@ static int dsmark_qdisc_msg_parser(struct rtnl_qdisc *qdisc) dsmark = dsmark_qdisc_alloc(qdisc); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (tb[TCA_DSMARK_INDICES]) { dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); @@ -118,7 +118,7 @@ static int dsmark_class_msg_parser(struct rtnl_class *class) dsmark = dsmark_class_alloc(class); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (tb[TCA_DSMARK_MASK]) { dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]); @@ -133,51 +133,43 @@ static int dsmark_class_msg_parser(struct rtnl_class *class) return 0; } -static int dsmark_qdisc_dump_brief(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void dsmark_qdisc_dump_line(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p) { struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc); if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)) - dp_dump(p, " indices 0x%04x", dsmark->qdm_indices); - - return line; + nl_dump(p, " indices 0x%04x", dsmark->qdm_indices); } -static int dsmark_qdisc_dump_full(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void dsmark_qdisc_dump_details(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p) { struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc); if (!dsmark) - goto ignore; + return; if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) - dp_dump(p, " default index 0x%04x", dsmark->qdm_default_index); + nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index); if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) - dp_dump(p, " set-tc-index"); - -ignore: - return line; + nl_dump(p, " set-tc-index"); } -static int dsmark_class_dump_brief(struct rtnl_class *class, - struct nl_dump_params *p, int line) +static void dsmark_class_dump_line(struct rtnl_class *class, + struct nl_dump_params *p) { struct rtnl_dsmark_class *dsmark = dsmark_class(class); if (!dsmark) - goto ignore; + return; if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) - dp_dump(p, " value 0x%02x", dsmark->cdm_value); + nl_dump(p, " value 0x%02x", dsmark->cdm_value); if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) - dp_dump(p, " mask 0x%02x", dsmark->cdm_bmask); - -ignore: - return line; + nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask); } static struct nl_msg *dsmark_qdisc_get_opts(struct rtnl_qdisc *qdisc) @@ -251,7 +243,7 @@ int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask) dsmark = dsmark_class(class); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; dsmark->cdm_bmask = mask; dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; @@ -272,7 +264,7 @@ int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class) if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) return dsmark->cdm_bmask; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -287,7 +279,7 @@ int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value) dsmark = dsmark_class(class); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; dsmark->cdm_value = value; dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; @@ -308,7 +300,7 @@ int rtnl_class_dsmark_get_value(struct rtnl_class *class) if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) return dsmark->cdm_value; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -329,7 +321,7 @@ int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices) dsmark = dsmark_qdisc(qdisc); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; dsmark->qdm_indices = indices; dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; @@ -350,7 +342,7 @@ int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc) if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) return dsmark->qdm_indices; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -366,7 +358,7 @@ int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc, dsmark = dsmark_qdisc(qdisc); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; dsmark->qdm_default_index = default_index; dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; @@ -387,7 +379,7 @@ int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc) if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) return dsmark->qdm_default_index; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -402,7 +394,7 @@ int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag) dsmark = dsmark_qdisc(qdisc); if (!dsmark) - return nl_errno(ENOMEM); + return -NLE_NOMEM; dsmark->qdm_set_tc_index = !!flag; dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; @@ -424,7 +416,7 @@ int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) return dsmark->qdm_set_tc_index; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -432,15 +424,17 @@ int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) static struct rtnl_qdisc_ops dsmark_qdisc_ops = { .qo_kind = "dsmark", .qo_msg_parser = dsmark_qdisc_msg_parser, - .qo_dump[NL_DUMP_BRIEF] = dsmark_qdisc_dump_brief, - .qo_dump[NL_DUMP_FULL] = dsmark_qdisc_dump_full, + .qo_dump = { + [NL_DUMP_LINE] = dsmark_qdisc_dump_line, + [NL_DUMP_DETAILS] = dsmark_qdisc_dump_details, + }, .qo_get_opts = dsmark_qdisc_get_opts, }; static struct rtnl_class_ops dsmark_class_ops = { .co_kind = "dsmark", .co_msg_parser = dsmark_class_msg_parser, - .co_dump[NL_DUMP_BRIEF] = dsmark_class_dump_brief, + .co_dump[NL_DUMP_LINE] = dsmark_class_dump_line, .co_get_opts = dsmark_class_get_opts, }; diff --git a/lib/route/sch/fifo.c b/lib/route/sch/fifo.c index 4f8d202..464af30 100644 --- a/lib/route/sch/fifo.c +++ b/lib/route/sch/fifo.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -60,11 +60,11 @@ static int fifo_msg_parser(struct rtnl_qdisc *qdisc) struct tc_fifo_qopt *opt; if (qdisc->q_opts->d_size < sizeof(struct tc_fifo_qopt)) - return nl_error(EINVAL, "FIFO options size mismatch"); + return -NLE_INVAL; fifo = fifo_alloc(qdisc); if (!fifo) - return nl_errno(ENOMEM); + return -NLE_NOMEM; opt = (struct tc_fifo_qopt *) qdisc->q_opts->d_data; fifo->qf_limit = opt->limit; @@ -78,19 +78,15 @@ static void fifo_free_data(struct rtnl_qdisc *qdisc) free(qdisc->q_subdata); } -static int pfifo_dump_brief(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void pfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_fifo *fifo = fifo_qdisc(qdisc); if (fifo) - dp_dump(p, " limit %u packets", fifo->qf_limit); - - return line; + nl_dump(p, " limit %u packets", fifo->qf_limit); } -static int bfifo_dump_brief(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void bfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_fifo *fifo = fifo_qdisc(qdisc); @@ -99,10 +95,8 @@ static int bfifo_dump_brief(struct rtnl_qdisc *qdisc, double r; r = nl_cancel_down_bytes(fifo->qf_limit, &unit); - dp_dump(p, " limit %.1f%s", r, unit); + nl_dump(p, " limit %.1f%s", r, unit); } - - return line; } static struct nl_msg *fifo_get_opts(struct rtnl_qdisc *qdisc) @@ -148,7 +142,7 @@ int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) fifo = fifo_alloc(qdisc); if (!fifo) - return nl_errno(ENOMEM); + return -NLE_NOMEM; fifo->qf_limit = limit; fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT; @@ -169,7 +163,7 @@ int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT) return fifo->qf_limit; else - return nl_errno(ENOMEM); + return -NLE_NOATTR; } /** @} */ @@ -178,7 +172,7 @@ static struct rtnl_qdisc_ops pfifo_ops = { .qo_kind = "pfifo", .qo_msg_parser = fifo_msg_parser, .qo_free_data = fifo_free_data, - .qo_dump[NL_DUMP_BRIEF] = pfifo_dump_brief, + .qo_dump[NL_DUMP_LINE] = pfifo_dump_line, .qo_get_opts = fifo_get_opts, }; @@ -186,7 +180,7 @@ static struct rtnl_qdisc_ops bfifo_ops = { .qo_kind = "bfifo", .qo_msg_parser = fifo_msg_parser, .qo_free_data = fifo_free_data, - .qo_dump[NL_DUMP_BRIEF] = bfifo_dump_brief, + .qo_dump[NL_DUMP_LINE] = bfifo_dump_line, .qo_get_opts = fifo_get_opts, }; diff --git a/lib/route/sch/htb.c b/lib/route/sch/htb.c index 6de87b3..a167136 100644 --- a/lib/route/sch/htb.c +++ b/lib/route/sch/htb.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com> * Copyright (c) 2005-2006 Siemens AG Oesterreich */ @@ -136,34 +136,31 @@ static void htb_class_free_data(struct rtnl_class *class) free(class->c_subdata); } -static int htb_qdisc_dump_brief(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void htb_qdisc_dump_line(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p) { struct rtnl_htb_qdisc *d = (struct rtnl_htb_qdisc *) qdisc->q_subdata; if (d == NULL) - goto ignore; + return; if (d->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) - dp_dump(p, " r2q %u", d->qh_rate2quantum); + nl_dump(p, " r2q %u", d->qh_rate2quantum); if (d->qh_mask & SCH_HTB_HAS_DEFCLS) { char buf[32]; - dp_dump(p, " default %s", + nl_dump(p, " default %s", rtnl_tc_handle2str(d->qh_defcls, buf, sizeof(buf))); } - -ignore: - return line; } -static int htb_class_dump_brief(struct rtnl_class *class, - struct nl_dump_params *p, int line) +static void htb_class_dump_line(struct rtnl_class *class, + struct nl_dump_params *p) { struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata; if (d == NULL) - goto ignore; + return; if (d->ch_mask & SCH_HTB_HAS_RATE) { double r, rbit; @@ -172,21 +169,18 @@ static int htb_class_dump_brief(struct rtnl_class *class, r = nl_cancel_down_bytes(d->ch_rate.rs_rate, &ru); rbit = nl_cancel_down_bits(d->ch_rate.rs_rate*8, &rubit); - dp_dump(p, " rate %.2f%s/s (%.0f%s) log %u", + nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u", r, ru, rbit, rubit, 1<<d->ch_rate.rs_cell_log); } - -ignore: - return line; } -static int htb_class_dump_full(struct rtnl_class *class, - struct nl_dump_params *p, int line) +static void htb_class_dump_details(struct rtnl_class *class, + struct nl_dump_params *p) { struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata; if (d == NULL) - goto ignore; + return; /* line 1 */ if (d->ch_mask & SCH_HTB_HAS_CEIL) { @@ -196,22 +190,22 @@ static int htb_class_dump_full(struct rtnl_class *class, r = nl_cancel_down_bytes(d->ch_ceil.rs_rate, &ru); rbit = nl_cancel_down_bits(d->ch_ceil.rs_rate*8, &rubit); - dp_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", + nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", r, ru, rbit, rubit, 1<<d->ch_ceil.rs_cell_log); } if (d->ch_mask & SCH_HTB_HAS_PRIO) - dp_dump(p, " prio %u", d->ch_prio); + nl_dump(p, " prio %u", d->ch_prio); if (d->ch_mask & SCH_HTB_HAS_MTU) - dp_dump(p, " mtu %u", d->ch_mtu); + nl_dump(p, " mtu %u", d->ch_mtu); if (d->ch_mask & SCH_HTB_HAS_RBUFFER) { double b; char *bu; b = nl_cancel_down_bytes(d->ch_rbuffer, &bu); - dp_dump(p, " rbuffer %.2f%s", b, bu); + nl_dump(p, " rbuffer %.2f%s", b, bu); } if (d->ch_mask & SCH_HTB_HAS_CBUFFER) { @@ -219,20 +213,17 @@ static int htb_class_dump_full(struct rtnl_class *class, char *bu; b = nl_cancel_down_bytes(d->ch_cbuffer, &bu); - dp_dump(p, " cbuffer %.2f%s", b, bu); + nl_dump(p, " cbuffer %.2f%s", b, bu); } if (d->ch_mask & SCH_HTB_HAS_QUANTUM) - dp_dump(p, " quantum %u", d->ch_quantum); + nl_dump(p, " quantum %u", d->ch_quantum); if (d->ch_mask & SCH_HTB_HAS_OVERHEAD) - dp_dump(p, " overhead %u", d->ch_overhead); + nl_dump(p, " overhead %u", d->ch_overhead); if (d->ch_mask & SCH_HTB_HAS_MPU) - dp_dump(p, " mpu %u", d->ch_mpu); - -ignore: - return line; + nl_dump(p, " mpu %u", d->ch_mpu); } static struct nl_msg *htb_qdisc_get_opts(struct rtnl_qdisc *qdisc) @@ -525,7 +516,7 @@ static struct rtnl_qdisc_ops htb_qdisc_ops = { .qo_kind = "htb", .qo_msg_parser = htb_qdisc_msg_parser, .qo_free_data = htb_qdisc_free_data, - .qo_dump[NL_DUMP_BRIEF] = htb_qdisc_dump_brief, + .qo_dump[NL_DUMP_LINE] = htb_qdisc_dump_line, .qo_get_opts = htb_qdisc_get_opts, }; @@ -533,8 +524,10 @@ static struct rtnl_class_ops htb_class_ops = { .co_kind = "htb", .co_msg_parser = htb_class_msg_parser, .co_free_data = htb_class_free_data, - .co_dump[NL_DUMP_BRIEF] = htb_class_dump_brief, - .co_dump[NL_DUMP_FULL] = htb_class_dump_full, + .co_dump = { + [NL_DUMP_LINE] = htb_class_dump_line, + [NL_DUMP_DETAILS] = htb_class_dump_details, + }, .co_get_opts = htb_class_get_opts, }; diff --git a/lib/route/sch/netem.c b/lib/route/sch/netem.c index e8b8913..18878a7 100644 --- a/lib/route/sch/netem.c +++ b/lib/route/sch/netem.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -27,17 +27,20 @@ #include <netlink/route/sch/netem.h> /** @cond SKIP */ -#define SCH_NETEM_ATTR_LATENCY 0x001 -#define SCH_NETEM_ATTR_LIMIT 0x002 -#define SCH_NETEM_ATTR_LOSS 0x004 -#define SCH_NETEM_ATTR_GAP 0x008 -#define SCH_NETEM_ATTR_DUPLICATE 0x010 -#define SCH_NETEM_ATTR_JITTER 0x020 -#define SCH_NETEM_ATTR_DELAY_CORR 0x040 -#define SCH_NETEM_ATTR_LOSS_CORR 0x080 -#define SCH_NETEM_ATTR_DUP_CORR 0x100 -#define SCH_NETEM_ATTR_RO_PROB 0x200 -#define SCH_NETEM_ATTR_RO_CORR 0x400 +#define SCH_NETEM_ATTR_LATENCY 0x0001 +#define SCH_NETEM_ATTR_LIMIT 0x0002 +#define SCH_NETEM_ATTR_LOSS 0x0004 +#define SCH_NETEM_ATTR_GAP 0x0008 +#define SCH_NETEM_ATTR_DUPLICATE 0x0010 +#define SCH_NETEM_ATTR_JITTER 0x0020 +#define SCH_NETEM_ATTR_DELAY_CORR 0x0040 +#define SCH_NETEM_ATTR_LOSS_CORR 0x0080 +#define SCH_NETEM_ATTR_DUP_CORR 0x0100 +#define SCH_NETEM_ATTR_RO_PROB 0x0200 +#define SCH_NETEM_ATTR_RO_CORR 0x0400 +#define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800 +#define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000 +#define SCH_NETEM_ATTR_DIST 0x2000 /** @endcond */ static inline struct rtnl_netem *netem_qdisc(struct rtnl_qdisc *qdisc) @@ -56,6 +59,7 @@ static inline struct rtnl_netem *netem_alloc(struct rtnl_qdisc *qdisc) static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = { [TCA_NETEM_CORR] = { .minlen = sizeof(struct tc_netem_corr) }, [TCA_NETEM_REORDER] = { .minlen = sizeof(struct tc_netem_reorder) }, + [TCA_NETEM_CORRUPT] = { .minlen = sizeof(struct tc_netem_corrupt) }, }; static int netem_msg_parser(struct rtnl_qdisc *qdisc) @@ -65,11 +69,11 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) struct tc_netem_qopt *opts; if (qdisc->q_opts->d_size < sizeof(*opts)) - return nl_error(EINVAL, "Netem specific options size mismatch"); + return -NLE_INVAL; netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; opts = (struct tc_netem_qopt *) qdisc->q_opts->d_data; netem->qnm_latency = opts->latency; @@ -89,7 +93,7 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) struct nlattr *tb[TCA_NETEM_MAX+1]; err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *) - qdisc->q_opts->d_data + sizeof(*opts), + (qdisc->q_opts->d_data + sizeof(*opts)), len, netem_policy); if (err < 0) { free(netem); @@ -106,7 +110,7 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR | SCH_NETEM_ATTR_LOSS_CORR | - SCH_NETEM_ATTR_DELAY_CORR); + SCH_NETEM_ATTR_DUP_CORR); } if (tb[TCA_NETEM_REORDER]) { @@ -119,6 +123,21 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB | SCH_NETEM_ATTR_RO_CORR); } + + if (tb[TCA_NETEM_CORRUPT]) { + struct tc_netem_corrupt corrupt; + + nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt)); + netem->qnm_crpt.nmcr_probability = corrupt.probability; + netem->qnm_crpt.nmcr_correlation = corrupt.correlation; + + netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB | + SCH_NETEM_ATTR_CORRUPT_CORR); + } + + /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */ + netem->qnm_dist.dist_data = NULL; + netem->qnm_dist.dist_size = 0; } return 0; @@ -126,29 +145,164 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) static void netem_free_data(struct rtnl_qdisc *qdisc) { - free(qdisc->q_subdata); + struct rtnl_netem *netem; + + if ( ! qdisc ) return; + + netem = netem_qdisc(qdisc); + if ( ! netem ) return; + + if ( netem->qnm_dist.dist_data ) + free(netem->qnm_dist.dist_data); + + netem = NULL; + + free (qdisc->q_subdata); } -static int netem_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void netem_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_netem *netem = netem_qdisc(qdisc); if (netem) - dp_dump(p, "limit %d", netem->qnm_limit); - - return line; + nl_dump(p, "limit %d", netem->qnm_limit); } -static int netem_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +int netem_build_msg(struct rtnl_qdisc *qdisc, struct nl_msg *msg) { - return line; -} + int err = 0; + struct tc_netem_qopt opts; + struct tc_netem_corr cor; + struct tc_netem_reorder reorder; + struct tc_netem_corrupt corrupt; + struct rtnl_netem *netem; + + unsigned char set_correlation = 0, set_reorder = 0, + set_corrupt = 0, set_dist = 0; -static struct nl_msg *netem_get_opts(struct rtnl_qdisc *qdisc) -{ - return NULL; + memset(&opts, 0, sizeof(opts)); + memset(&cor, 0, sizeof(cor)); + memset(&reorder, 0, sizeof(reorder)); + memset(&corrupt, 0, sizeof(corrupt)); + + netem = netem_qdisc(qdisc); + if (!netem || !msg) + return EFAULT; + + msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST; + + if ( netem->qnm_ro.nmro_probability != 0 ) { + if (netem->qnm_latency == 0) { + return -NLE_MISSING_ATTR; + } + if (netem->qnm_gap == 0) netem->qnm_gap = 1; + } + else if ( netem->qnm_gap ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_corr.nmc_delay != 0 ) { + if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_corr.nmc_loss != 0 ) { + if ( netem->qnm_loss == 0 ) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_corr.nmc_duplicate != 0 ) { + if ( netem->qnm_duplicate == 0 ) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1; + else if ( netem->qnm_ro.nmro_correlation != 0 ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1; + else if ( netem->qnm_crpt.nmcr_correlation != 0 ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) { + if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) { + return -NLE_MISSING_ATTR; + } + else { + /* Resize to accomodate the large distribution table */ + int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size * + sizeof(netem->qnm_dist.dist_data[0]); + + msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len); + if ( msg->nm_nlh == NULL ) + return -NLE_NOMEM; + msg->nm_size = new_msg_len; + set_dist = 1; + } + } + + opts.latency = netem->qnm_latency; + opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000; + opts.loss = netem->qnm_loss; + opts.gap = netem->qnm_gap; + opts.duplicate = netem->qnm_duplicate; + opts.jitter = netem->qnm_jitter; + + NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts); + + if ( set_correlation ) { + cor.delay_corr = netem->qnm_corr.nmc_delay; + cor.loss_corr = netem->qnm_corr.nmc_loss; + cor.dup_corr = netem->qnm_corr.nmc_duplicate; + + NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor); + } + + if ( set_reorder ) { + reorder.probability = netem->qnm_ro.nmro_probability; + reorder.correlation = netem->qnm_ro.nmro_correlation; + + NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder); + } + + if ( set_corrupt ) { + corrupt.probability = netem->qnm_crpt.nmcr_probability; + corrupt.correlation = netem->qnm_crpt.nmcr_correlation; + + NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); + } + + if ( set_dist ) { + NLA_PUT(msg, TCA_NETEM_DELAY_DIST, + netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]), + netem->qnm_dist.dist_data); + } + + /* Length specified in the TCA_OPTIONS section must span the entire + * remainder of the message. That's just the way that sch_netem expects it. + * Maybe there's a more succinct way to do this at a higher level. + */ + struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) + + NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO); + + struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) + + NLMSG_ALIGN(msg->nm_nlh->nlmsg_len)); + + int old_len = head->nla_len; + head->nla_len = (void *)tail - (void *)head; + msg->nm_nlh->nlmsg_len += (head->nla_len - old_len); + + return err; +nla_put_failure: + return -NLE_MSGSIZE; } /** @@ -168,7 +322,7 @@ int rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_limit = limit; netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT; @@ -189,7 +343,7 @@ int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT)) return netem->qnm_limit; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -211,7 +365,7 @@ int rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_gap = gap; netem->qnm_mask |= SCH_NETEM_ATTR_GAP; @@ -232,7 +386,7 @@ int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_GAP)) return netem->qnm_gap; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -247,7 +401,7 @@ int rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_ro.nmro_probability = prob; netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB; @@ -268,7 +422,7 @@ int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB)) return netem->qnm_ro.nmro_probability; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -283,7 +437,7 @@ int rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_ro.nmro_correlation = prob; netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR; @@ -304,7 +458,86 @@ int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR)) return netem->qnm_ro.nmro_correlation; else - return nl_errno(ENOENT); + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Corruption + * @{ + */ + +/** + * Set corruption probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New corruption probability. + * @return 0 on success or a negative error code. + */ +int rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + netem = netem_alloc(qdisc); + if (!netem) + return -NLE_NOMEM; + + netem->qnm_crpt.nmcr_probability = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB; + + return 0; +} + +/** + * Get corruption probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Corruption probability or a negative error code. + */ +int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + netem = netem_qdisc(qdisc); + if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB)) + return netem->qnm_crpt.nmcr_probability; + else + return -NLE_NOATTR; +} + +/** + * Set corruption correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New corruption correlation probability. + * @return 0 on success or a negative error code. + */ +int rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + netem = netem_alloc(qdisc); + if (!netem) + return -NLE_NOMEM; + + netem->qnm_crpt.nmcr_correlation = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR; + + return 0; +} + +/** + * Get corruption correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Corruption correlation probability or a negative error code. + */ +int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + netem = netem_qdisc(qdisc); + if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR)) + return netem->qnm_crpt.nmcr_correlation; + else + return -NLE_NOATTR; } /** @} */ @@ -326,7 +559,7 @@ int rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_loss = prob; netem->qnm_mask |= SCH_NETEM_ATTR_LOSS; @@ -347,7 +580,7 @@ int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS)) return netem->qnm_loss; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -362,7 +595,7 @@ int rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_corr.nmc_loss = prob; netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR; @@ -383,7 +616,7 @@ int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR)) return netem->qnm_corr.nmc_loss; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -405,7 +638,7 @@ int rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_duplicate = prob; netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE; @@ -426,7 +659,7 @@ int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE)) return netem->qnm_duplicate; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -441,7 +674,7 @@ int rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_corr.nmc_duplicate = prob; netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR; @@ -462,7 +695,7 @@ int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR)) return netem->qnm_corr.nmc_duplicate; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -484,7 +717,7 @@ int rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_latency = nl_us2ticks(delay); netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY; @@ -505,7 +738,7 @@ int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY)) return nl_ticks2us(netem->qnm_latency); else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -520,7 +753,7 @@ int rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_jitter = nl_us2ticks(jitter); netem->qnm_mask |= SCH_NETEM_ATTR_JITTER; @@ -541,7 +774,7 @@ int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_JITTER)) return nl_ticks2us(netem->qnm_jitter); else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -555,7 +788,7 @@ int rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob) netem = netem_alloc(qdisc); if (!netem) - return nl_errno(ENOMEM); + return -NLE_NOMEM; netem->qnm_corr.nmc_delay = prob; netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR; @@ -576,7 +809,110 @@ int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc) if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR)) return netem->qnm_corr.nmc_delay; else - return nl_errno(ENOENT); + return -NLE_NOATTR; +} + +/** + * Get the size of the distribution table. + * @arg qdisc Netem qdisc. + * @return Distribution table size or a negative error code. + */ +int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + netem = netem_qdisc(qdisc); + if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST)) + return netem->qnm_dist.dist_size; + else + return -NLE_NOATTR; +} + +/** + * Get a pointer to the distribution table. + * @arg qdisc Netem qdisc. + * @arg dist_ptr The pointer to set. + * @return Negative error code on failure or 0 on success. + */ +int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr) +{ + struct rtnl_netem *netem; + + netem = netem_qdisc(qdisc); + if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST)) { + *dist_ptr = netem->qnm_dist.dist_data; + return 0; + } + else + return -NLE_NOATTR; +} + +/** + * Set the delay distribution. Latency/jitter must be set before applying. + * @arg qdisc Netem qdisc. + * @arg dist_type The name of the distribution (type, file, path/file). + * @return 0 on success, error code on failure. + */ +int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) { + struct rtnl_netem *netem; + + netem = netem_alloc(qdisc); + if (!netem) + return -NLE_NOMEM; + + FILE *f = NULL; + int i, n = 0; + size_t len = 2048; + char *line; + char name[NAME_MAX]; + char dist_suffix[] = ".dist"; + + /* If the given filename already ends in .dist, don't append it later */ + char *test_suffix = strstr(dist_type, dist_suffix); + if (test_suffix != NULL && strlen(test_suffix) == 5) + strcpy(dist_suffix, ""); + + /* Check several locations for the dist file */ + char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" }; + + for (i = 0; i < sizeof(test_path) && f == NULL; i++) { + snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix); + f = fopen(name, "r"); + } + + if ( f == NULL ) + return -nl_syserr2nlerr(errno); + + netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t)); + + line = (char *) calloc (sizeof(char), len + 1); + + while (getline(&line, &len, f) != -1) { + char *p, *endp; + + if (*line == '\n' || *line == '#') + continue; + + for (p = line; ; p = endp) { + long x = strtol(p, &endp, 0); + if (endp == p) break; + + if (n >= MAXDIST) { + free(line); + fclose(f); + return -NLE_INVAL; + } + netem->qnm_dist.dist_data[n++] = x; + } + } + + free(line); + + netem->qnm_dist.dist_size = n; + netem->qnm_mask |= SCH_NETEM_ATTR_DIST; + + fclose(f); + return 0; } /** @} */ @@ -585,9 +921,9 @@ static struct rtnl_qdisc_ops netem_ops = { .qo_kind = "netem", .qo_msg_parser = netem_msg_parser, .qo_free_data = netem_free_data, - .qo_dump[NL_DUMP_BRIEF] = netem_dump_brief, - .qo_dump[NL_DUMP_FULL] = netem_dump_full, - .qo_get_opts = netem_get_opts, + .qo_dump[NL_DUMP_LINE] = netem_dump_line, + .qo_get_opts = 0, + .qo_build_msg = netem_build_msg }; static void __init netem_init(void) diff --git a/lib/route/sch/prio.c b/lib/route/sch/prio.c index 4e3d624..4c9ebcf 100644 --- a/lib/route/sch/prio.c +++ b/lib/route/sch/prio.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -58,11 +58,11 @@ static int prio_msg_parser(struct rtnl_qdisc *qdisc) struct tc_prio_qopt *opt; if (qdisc->q_opts->d_size < sizeof(*opt)) - return nl_error(EINVAL, "prio specific option size mismatch"); + return -NLE_INVAL; prio = prio_alloc(qdisc); if (!prio) - return nl_errno(ENOMEM); + return -NLE_NOMEM; opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data; prio->qp_bands = opt->bands; @@ -77,55 +77,48 @@ static void prio_free_data(struct rtnl_qdisc *qdisc) free(qdisc->q_subdata); } -static int prio_dump_brief(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void prio_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_prio *prio = prio_qdisc(qdisc); if (prio) - dp_dump(p, " bands %u", prio->qp_bands); - - return line; + nl_dump(p, " bands %u", prio->qp_bands); } -static int prio_dump_full(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p, int line) +static void prio_dump_details(struct rtnl_qdisc *qdisc,struct nl_dump_params *p) { struct rtnl_prio *prio = prio_qdisc(qdisc); int i, hp; if (!prio) - goto ignore; + return; - dp_dump(p, "priomap ["); + nl_dump(p, "priomap ["); for (i = 0; i <= TC_PRIO_MAX; i++) - dp_dump(p, "%u%s", prio->qp_priomap[i], + nl_dump(p, "%u%s", prio->qp_priomap[i], i < TC_PRIO_MAX ? " " : ""); - dp_dump(p, "]\n"); - dp_new_line(p, line++); + nl_dump(p, "]\n"); + nl_new_line(p); hp = (((TC_PRIO_MAX/2) + 1) & ~1); for (i = 0; i < hp; i++) { char a[32]; - dp_dump(p, " %18s => %u", + nl_dump(p, " %18s => %u", rtnl_prio2str(i, a, sizeof(a)), prio->qp_priomap[i]); if (hp+i <= TC_PRIO_MAX) { - dp_dump(p, " %18s => %u", + nl_dump(p, " %18s => %u", rtnl_prio2str(hp+i, a, sizeof(a)), prio->qp_priomap[hp+i]); if (i < (hp - 1)) { - dp_dump(p, "\n"); - dp_new_line(p, line++); + nl_dump(p, "\n"); + nl_new_line(p); } } } - -ignore: - return line; } static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc) @@ -173,7 +166,7 @@ int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) prio = prio_alloc(qdisc); if (!prio) - return nl_errno(ENOMEM); + return -NLE_NOMEM; prio->qp_bands = bands; prio->qp_mask |= SCH_PRIO_ATTR_BANDS; @@ -194,7 +187,7 @@ int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc) if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS) return prio->qp_bands; else - return nl_errno(ENOMEM); + return -NLE_NOMEM; } /** @@ -212,18 +205,17 @@ int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], prio = prio_alloc(qdisc); if (!prio) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS)) - return nl_error(EINVAL, "Set number of bands first"); + return -NLE_MISSING_ATTR; if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1)) - return nl_error(ERANGE, "priomap length out of bounds"); + return -NLE_RANGE; for (i = 0; i <= TC_PRIO_MAX; i++) { if (priomap[i] > prio->qp_bands) - return nl_error(ERANGE, "priomap element %d " \ - "out of bounds, increase bands number"); + return -NLE_RANGE; } memcpy(prio->qp_priomap, priomap, len); @@ -245,10 +237,8 @@ uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc) prio = prio_qdisc(qdisc); if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) return prio->qp_priomap; - else { - nl_errno(ENOENT); + else return NULL; - } } /** @} */ @@ -303,8 +293,10 @@ static struct rtnl_qdisc_ops prio_ops = { .qo_kind = "prio", .qo_msg_parser = prio_msg_parser, .qo_free_data = prio_free_data, - .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief, - .qo_dump[NL_DUMP_FULL] = prio_dump_full, + .qo_dump = { + [NL_DUMP_LINE] = prio_dump_line, + [NL_DUMP_DETAILS] = prio_dump_details, + }, .qo_get_opts = prio_get_opts, }; @@ -312,8 +304,10 @@ static struct rtnl_qdisc_ops pfifo_fast_ops = { .qo_kind = "pfifo_fast", .qo_msg_parser = prio_msg_parser, .qo_free_data = prio_free_data, - .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief, - .qo_dump[NL_DUMP_FULL] = prio_dump_full, + .qo_dump = { + [NL_DUMP_LINE] = prio_dump_line, + [NL_DUMP_DETAILS] = prio_dump_details, + }, .qo_get_opts = prio_get_opts, }; diff --git a/lib/route/sch/red.c b/lib/route/sch/red.c index a31c358..e4cac79 100644 --- a/lib/route/sch/red.c +++ b/lib/route/sch/red.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -66,11 +66,11 @@ static int red_msg_parser(struct rtnl_qdisc *qdisc) return err; if (!tb[TCA_RED_PARMS]) - return nl_error(EINVAL, "Missing TCA_RED_PARMS"); + return -NLE_MISSING_ATTR; red = red_alloc(qdisc); if (!red) - return nl_errno(ENOMEM); + return -NLE_NOMEM; opts = nla_data(tb[TCA_RED_PARMS]); @@ -89,40 +89,31 @@ static int red_msg_parser(struct rtnl_qdisc *qdisc) return 0; } -static int red_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void red_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_red *red = red_qdisc(qdisc); if (red) { /* XXX: limit, min, max, flags */ } - - return line; } -static int red_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void red_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_red *red = red_qdisc(qdisc); if (red) { /* XXX: wlog, plog, scell_log */ } - - return line; } -static int red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_red *red = red_qdisc(qdisc); if (red) { /* XXX: xstats */ } - - return line; } static struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc) @@ -171,7 +162,7 @@ int rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit) red = red_alloc(qdisc); if (!red) - return nl_errno(ENOMEM); + return -NLE_NOMEM; red->qr_limit = limit; red->qr_mask |= RED_ATTR_LIMIT; @@ -192,7 +183,7 @@ int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) if (red && (red->qr_mask & RED_ATTR_LIMIT)) return red->qr_limit; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -200,9 +191,11 @@ int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) static struct rtnl_qdisc_ops red_ops = { .qo_kind = "red", .qo_msg_parser = red_msg_parser, - .qo_dump[NL_DUMP_BRIEF] = red_dump_brief, - .qo_dump[NL_DUMP_FULL] = red_dump_full, - .qo_dump[NL_DUMP_STATS] = red_dump_stats, + .qo_dump = { + [NL_DUMP_LINE] = red_dump_line, + [NL_DUMP_DETAILS] = red_dump_details, + [NL_DUMP_STATS] = red_dump_stats, + }, .qo_get_opts = red_get_opts, }; diff --git a/lib/route/sch/sfq.c b/lib/route/sch/sfq.c index d530c0f..4b47356 100644 --- a/lib/route/sch/sfq.c +++ b/lib/route/sch/sfq.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -61,11 +61,11 @@ static int sfq_msg_parser(struct rtnl_qdisc *qdisc) return 0; if (qdisc->q_opts->d_size < sizeof(*opts)) - return nl_error(EINVAL, "SFQ specific options size mismatch"); + return -NLE_INVAL; sfq = sfq_alloc(qdisc); if (!sfq) - return nl_errno(ENOMEM); + return -NLE_NOMEM; opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data; @@ -87,29 +87,22 @@ static void sfq_free_data(struct rtnl_qdisc *qdisc) free(qdisc->q_subdata); } -static int sfq_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void sfq_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_sfq *sfq = sfq_qdisc(qdisc); if (sfq) - dp_dump(p, " quantum %u perturb %us", - sfq->qs_quantum, + nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum, nl_ticks2us(sfq->qs_perturb * nl_get_hz())); - - return line; } -static int sfq_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void sfq_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_sfq *sfq = sfq_qdisc(qdisc); if (sfq) - dp_dump(p, "limit %u divisor %u", + nl_dump(p, "limit %u divisor %u", sfq->qs_limit, sfq->qs_divisor); - - return line; } static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc) @@ -157,7 +150,7 @@ int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) sfq = sfq_alloc(qdisc); if (!sfq) - return nl_errno(ENOMEM); + return -NLE_NOMEM; sfq->qs_quantum = quantum; sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM; @@ -178,7 +171,7 @@ int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc) if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM) return sfq->qs_quantum; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -193,7 +186,7 @@ int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) sfq = sfq_alloc(qdisc); if (!sfq) - return nl_errno(ENOMEM); + return -NLE_NOMEM; sfq->qs_limit = limit; sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT; @@ -214,7 +207,7 @@ int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc) if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT) return sfq->qs_limit; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -230,7 +223,7 @@ int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) sfq = sfq_alloc(qdisc); if (!sfq) - return nl_errno(ENOMEM); + return -NLE_NOMEM; sfq->qs_perturb = perturb; sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB; @@ -251,7 +244,7 @@ int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc) if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB) return sfq->qs_perturb; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @@ -267,7 +260,7 @@ int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc) if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR) return sfq->qs_divisor; else - return nl_errno(ENOENT); + return -NLE_NOATTR; } /** @} */ @@ -276,8 +269,10 @@ static struct rtnl_qdisc_ops sfq_ops = { .qo_kind = "sfq", .qo_msg_parser = sfq_msg_parser, .qo_free_data = sfq_free_data, - .qo_dump[NL_DUMP_BRIEF] = sfq_dump_brief, - .qo_dump[NL_DUMP_FULL] = sfq_dump_full, + .qo_dump = { + [NL_DUMP_LINE] = sfq_dump_line, + [NL_DUMP_DETAILS] = sfq_dump_details, + }, .qo_get_opts = sfq_get_opts, }; diff --git a/lib/route/sch/tbf.c b/lib/route/sch/tbf.c index 04d1689..eccaf70 100644 --- a/lib/route/sch/tbf.c +++ b/lib/route/sch/tbf.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -62,9 +62,9 @@ static int tbf_msg_parser(struct rtnl_qdisc *q) if (err < 0) return err; - tbf = tbf_qdisc(q); + tbf = tbf_alloc(q); if (!tbf) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (tb[TCA_TBF_PARMS]) { struct tc_tbf_qopt opts; @@ -93,34 +93,34 @@ static int tbf_msg_parser(struct rtnl_qdisc *q) return 0; } -static int tbf_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void tbf_free_data(struct rtnl_qdisc *qdisc) +{ + free(qdisc->q_subdata); +} + +static void tbf_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { double r, rbit, lim; char *ru, *rubit, *limu; struct rtnl_tbf *tbf = tbf_qdisc(qdisc); if (!tbf) - goto ignore; + return; r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru); rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit); lim = nl_cancel_down_bytes(tbf->qt_limit, &limu); - dp_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", + nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", r, ru, rbit, rubit, lim, limu); - -ignore: - return line; } -static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) +static void tbf_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) { struct rtnl_tbf *tbf = tbf_qdisc(qdisc); if (!tbf) - goto ignore; + return; if (1) { char *bu, *cu; @@ -128,7 +128,7 @@ static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log, &cu); - dp_dump(p, "mpu %u rate-bucket-size %1.f%s " + nl_dump(p, "mpu %u rate-bucket-size %1.f%s " "rate-cell-size %.1f%s\n", tbf->qt_mpu, bs, bu, cl, cu); @@ -144,14 +144,11 @@ static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log, &clu); - dp_dump_line(p, line++, " peak-rate %.2f%s/s (%.0f%s) " - "bucket-size %.1f%s cell-size %.1f%s", - "latency %.1f%s", + nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) " + "bucket-size %.1f%s cell-size %.1f%s" + "latency %.1f%s", pr, pru, prb, prbu, bs, bsu, cl, clu); } - -ignore: - return line; } static struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc) @@ -226,7 +223,7 @@ int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) tbf = tbf_alloc(qdisc); if (!tbf) - return nl_errno(ENOMEM); + return -NLE_NOMEM; tbf->qt_limit = limit; tbf->qt_mask |= TBF_ATTR_LIMIT; @@ -270,11 +267,10 @@ int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) tbf = tbf_alloc(qdisc); if (!tbf) - return nl_errno(ENOMEM); + return -NLE_NOMEM; if (!(tbf->qt_mask & TBF_ATTR_RATE)) - return nl_error(EINVAL, "The rate must be specified before " - "limit can be calculated based on latency."); + return -NLE_MISSING_ATTR; limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket); @@ -301,8 +297,8 @@ int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) tbf = tbf_qdisc(qdisc); if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT)) return tbf->qt_limit; - return - nl_errno(ENOENT); + else + return -NLE_NOATTR; } /** @@ -317,7 +313,7 @@ int rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu) tbf = tbf_alloc(qdisc); if (!tbf) - return nl_errno(ENOMEM); + return -NLE_NOMEM; tbf->qt_mpu = mpu; tbf->qt_mask |= TBF_ATTR_MPU; @@ -337,8 +333,8 @@ int rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc) tbf = tbf_qdisc(qdisc); if (tbf && (tbf->qt_mask & TBF_ATTR_MPU)) return tbf->qt_mpu; - return - nl_errno(ENOENT); + else + return -NLE_NOATTR; } static inline int calc_cell_log(int cell, int bucket) @@ -374,7 +370,7 @@ int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, tbf = tbf_alloc(qdisc); if (!tbf) - return nl_errno(ENOMEM); + return -NLE_NOMEM; cell_log = calc_cell_log(cell, bucket); if (cell_log < 0) @@ -453,7 +449,7 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, tbf = tbf_alloc(qdisc); if (!tbf) - return nl_errno(ENOMEM); + return -NLE_NOMEM; cell_log = calc_cell_log(cell, bucket); if (cell_log < 0) @@ -522,8 +518,11 @@ int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) static struct rtnl_qdisc_ops tbf_qdisc_ops = { .qo_kind = "tbf", .qo_msg_parser = tbf_msg_parser, - .qo_dump[NL_DUMP_BRIEF] = tbf_dump_brief, - .qo_dump[NL_DUMP_FULL] = tbf_dump_full, + .qo_dump = { + [NL_DUMP_LINE] = tbf_dump_line, + [NL_DUMP_DETAILS] = tbf_dump_details, + }, + .qo_free_data = tbf_free_data, .qo_get_opts = tbf_get_opts, }; diff --git a/lib/route/tc.c b/lib/route/tc.c index 1351fa2..97faef4 100644 --- a/lib/route/tc.c +++ b/lib/route/tc.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** @@ -66,7 +66,7 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g) return err; if (tb[TCA_KIND] == NULL) - return nl_error(EINVAL, "Missing tca kind TLV"); + return -NLE_MISSING_ATTR; nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ); @@ -81,9 +81,9 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g) TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND); if (tb[TCA_OPTIONS]) { - g->tc_opts = nla_get_data(tb[TCA_OPTIONS]); + g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); if (!g->tc_opts) - return nl_errno(ENOMEM); + return -NLE_NOMEM; g->ce_mask |= TCA_ATTR_OPTS; } @@ -126,9 +126,9 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g) g->ce_mask |= TCA_ATTR_STATS; if (tbs[TCA_STATS_APP]) { - g->tc_xstats = nla_get_data(tbs[TCA_STATS_APP]); + g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); if (g->tc_xstats == NULL) - return -ENOMEM; + return -NLE_NOMEM; } else goto compat_xstats; } else { @@ -149,9 +149,9 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g) compat_xstats: if (tb[TCA_XSTATS]) { - g->tc_xstats = nla_get_data(tb[TCA_XSTATS]); + g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); if (g->tc_xstats == NULL) - return -ENOMEM; + return -NLE_NOMEM; g->ce_mask |= TCA_ATTR_XSTATS; } } @@ -171,58 +171,53 @@ int tca_clone(struct rtnl_tca *dst, struct rtnl_tca *src) if (src->tc_opts) { dst->tc_opts = nl_data_clone(src->tc_opts); if (!dst->tc_opts) - goto errout; + return -NLE_NOMEM; } if (src->tc_xstats) { dst->tc_xstats = nl_data_clone(src->tc_xstats); if (!dst->tc_xstats) - goto errout; + return -NLE_NOMEM; } return 0; -errout: - return nl_get_errno(); } -int tca_dump_brief(struct rtnl_tca *g, const char *type, - struct nl_dump_params *p, int line) +void tca_dump_line(struct rtnl_tca *g, const char *type, + struct nl_dump_params *p) { char handle[32], parent[32]; struct nl_cache *link_cache; link_cache = nl_cache_mngt_require("route/link"); - dp_dump(p, "%s %s ", g->tc_kind, type); + nl_dump_line(p, "%s %s ", g->tc_kind, type); if (link_cache) { char buf[32]; - dp_dump(p, "dev %s ", + nl_dump(p, "dev %s ", rtnl_link_i2name(link_cache, g->tc_ifindex, buf, sizeof(buf))); } else - dp_dump(p, "dev %u ", g->tc_ifindex); + nl_dump(p, "dev %u ", g->tc_ifindex); - dp_dump(p, "handle %s parent %s", + nl_dump(p, "handle %s parent %s", rtnl_tc_handle2str(g->tc_handle, handle, sizeof(handle)), rtnl_tc_handle2str(g->tc_parent, parent, sizeof(parent))); - - return 1; } -int tca_dump_full(struct rtnl_tca *g, struct nl_dump_params *p, int line) +void tca_dump_details(struct rtnl_tca *g, struct nl_dump_params *p) { - dp_dump_line(p, line++, " "); - return line; + nl_dump_line(p, " "); } -int tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p, int line) +void tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p) { char *unit, fmt[64]; float res; strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n"); - dp_dump_line(p, line++, + nl_dump_line(p, " Stats: bytes packets drops overlimits" \ " qlen backlog\n"); @@ -230,7 +225,7 @@ int tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p, int line) if (*unit == 'B') fmt[11] = '9'; - dp_dump_line(p, line++, fmt, res, unit, + nl_dump_line(p, fmt, res, unit, g->tc_stats[RTNL_TC_PACKETS], g->tc_stats[RTNL_TC_DROPS], g->tc_stats[RTNL_TC_OVERLIMITS], @@ -244,9 +239,7 @@ int tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p, int line) if (*unit == 'B') fmt[11] = '9'; - dp_dump_line(p, line++, fmt, res, unit, g->tc_stats[RTNL_TC_RATE_PPS]); - - return line; + nl_dump_line(p, fmt, res, unit, g->tc_stats[RTNL_TC_RATE_PPS]); } int tca_compare(struct nl_object *_a, struct nl_object *_b, @@ -276,10 +269,7 @@ void tca_set_ifindex(struct rtnl_tca *t, int ifindex) int tca_get_ifindex(struct rtnl_tca *t) { - if (t->ce_mask & TCA_ATTR_IFINDEX) - return t->tc_ifindex; - else - return RTNL_LINK_NOT_FOUND; + return t->tc_ifindex; } void tca_set_handle(struct rtnl_tca *t, uint32_t handle) @@ -332,7 +322,8 @@ uint64_t tca_get_stat(struct rtnl_tca *t, int id) return t->tc_stats[id]; } -struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags) +int tca_build_msg(struct rtnl_tca *tca, int type, int flags, + struct nl_msg **result) { struct nl_msg *msg; struct tcmsg tchdr = { @@ -344,7 +335,7 @@ struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags) msg = nlmsg_alloc_simple(type, flags); if (!msg) - goto nla_put_failure; + return -NLE_NOMEM; if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -352,11 +343,12 @@ struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags) if (tca->ce_mask & TCA_ATTR_KIND) NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind); - return msg; + *result = msg; + return 0; nla_put_failure: nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** @endcond */ @@ -425,7 +417,7 @@ int rtnl_tc_calc_cell_log(int cell_size) if ((1 << i) == cell_size) return i; - return nl_errno(EINVAL); + return -NLE_INVAL; } @@ -546,13 +538,13 @@ int rtnl_tc_str2handle(const char *name, uint32_t *res) /* :YYYY */ h = 0; if (':' != *colon) - return -EINVAL; + return -NLE_INVAL; } if (':' == *colon) { /* check if we would lose bits */ if (TC_H_MAJ(h)) - return -ERANGE; + return -NLE_RANGE; h <<= 16; if ('\0' == colon[1]) { @@ -564,10 +556,10 @@ int rtnl_tc_str2handle(const char *name, uint32_t *res) /* check if we overlap with major part */ if (TC_H_MAJ(l)) - return -ERANGE; + return -NLE_RANGE; if ('\0' != *end) - return -EINVAL; + return -NLE_INVAL; *res = (h | l); } @@ -575,7 +567,7 @@ int rtnl_tc_str2handle(const char *name, uint32_t *res) /* XXXXYYYY */ *res = h; } else - return -EINVAL; + return -NLE_INVAL; return 0; } diff --git a/lib/socket.c b/lib/socket.c index aae8f54..8083bbb 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -1,91 +1,17 @@ /* - * lib/socket.c Netlink Socket Handle + * lib/socket.c Netlink Socket * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** - * @ingroup nl + * @ingroup core * @defgroup socket Socket - * @brief Handle representing a netlink socket. - * - * The socket is represented in a structure called the netlink handle, - * besides the socket, it stores various settings and values related - * to the socket. Every socket handle has a mandatory association with - * a set of callbacks which can be used to modify the behaviour when - * sending/receiving data from the socket. - * - * @par Socket Attributes - * - \b Local \b Port: The local port is a netlink port identifying the - * local endpoint. It is used as source address for outgoing messages - * and will be addressed in replies. It must therefore be unique among - * all userspace applications. When the socket handle is allocated, a - * unique port number is generated automatically in the form of 22 bits - * Process Identifier + 10 bits Arbitary Number. Therefore the library - * is capable of generating 1024 unique local port numbers for every - * process. If more sockets are required, the application has to manage - * port numbers itself using nl_socket_set_local_port(). - * - \b Group \b Subscriptions: A socket can subscribe to any number of - * multicast groups. It will then receive a copy of all messages sent - * to one of the groups. This method is mainly used for event notification. - * Prior to kernel 2.6.14, the group subscription was done via bitmask - * which limited to a total number of groups of 32. With 2.6.14 a new - * method was added based on continous identifiers which supports an - * arbitary number of groups. Both methods are supported, see - * nl_join_groups() respectively nl_socket_add_membership() and - * nl_socket_drop_membership(). - * - \b Peer \b Port: The peer port is a netlink port identifying the - * peer's endpoint. If no peer port is specified, the kernel will try to - * autobind to a socket of the specified netlink family automatically. - * This is very common as typically only one listening socket exists - * on the kernel side. The peer port can be modified using - * nl_socket_set_peer_port(). - * - \b Peer \b Groups: - * - \b File \b Descriptor: The file descriptor of the socket, it can be - * accessed via nl_socket_get_fd() to change socket options or monitor - * activity using poll()/select(). - * - \b Protocol: Once connected, the socket is bound to stick to one - * netlink family. This field is invisible, it is maintained automatically. - * (See nl_connect()) - * - \b Next \b Sequence \b Number: Next available sequence number to be used - * for the next message being sent out. (Initial value: UNIX time when the - * socket was allocated.) Sequence numbers can be used via - * nl_socket_use_seq(). - * - \b Expected \b Sequence \b Number: Expected sequence number in the next - * message received from the socket. (Initial value: Equal to next sequence - * number.) - * - \b Callbacks \b Configuration: - * - * @par 1) Creating the netlink handle - * @code - * struct nl_handle *handle; - * - * // Allocate and initialize a new netlink handle - * handle = nl_handle_alloc(); - * - * // Use nl_socket_get_fd() to fetch the file description, for example to - * // put a socket into non-blocking i/o mode. - * fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK); - * @endcode - * - * @par 2) Group Subscriptions - * @code - * // Event notifications are typically sent to multicast addresses which - * // represented by groups. Join a group to f.e. receive link notifications. - * nl_socket_add_membership(handle, RTNLGRP_LINK); - * @endcode - * - * @par 6) Cleaning up - * @code - * // Finally destroy the netlink handle - * nl_handle_destroy(handle); - * @endcode - * * @{ */ @@ -153,7 +79,7 @@ static void release_local_port(uint32_t port) return; nr = port >> 22; - used_ports_map[nr / 32] &= ~((nr % 32) + 1); + used_ports_map[nr / 32] &= ~(1 << nr % 32); } /** @@ -161,83 +87,78 @@ static void release_local_port(uint32_t port) * @{ */ -static struct nl_handle *__alloc_handle(struct nl_cb *cb) +static struct nl_sock *__alloc_socket(struct nl_cb *cb) { - struct nl_handle *handle; + struct nl_sock *sk; - handle = calloc(1, sizeof(*handle)); - if (!handle) { - nl_errno(ENOMEM); + sk = calloc(1, sizeof(*sk)); + if (!sk) return NULL; - } - handle->h_fd = -1; - handle->h_cb = cb; - handle->h_local.nl_family = AF_NETLINK; - handle->h_peer.nl_family = AF_NETLINK; - handle->h_seq_expect = handle->h_seq_next = time(0); - handle->h_local.nl_pid = generate_local_port(); - if (handle->h_local.nl_pid == UINT_MAX) { - nl_handle_destroy(handle); - nl_error(ENOBUFS, "Out of local ports"); + sk->s_fd = -1; + sk->s_cb = cb; + sk->s_local.nl_family = AF_NETLINK; + sk->s_peer.nl_family = AF_NETLINK; + sk->s_seq_expect = sk->s_seq_next = time(0); + sk->s_local.nl_pid = generate_local_port(); + if (sk->s_local.nl_pid == UINT_MAX) { + nl_socket_free(sk); return NULL; } - return handle; + return sk; } /** - * Allocate new netlink socket handle. + * Allocate new netlink socket * - * @return Newly allocated netlink socket handle or NULL. + * @return Newly allocated netlink socket or NULL. */ -struct nl_handle *nl_handle_alloc(void) +struct nl_sock *nl_socket_alloc(void) { struct nl_cb *cb; cb = nl_cb_alloc(default_cb); - if (!cb) { - nl_errno(ENOMEM); + if (!cb) return NULL; - } - return __alloc_handle(cb); + return __alloc_socket(cb); } /** - * Allocate new socket handle with custom callbacks + * Allocate new socket with custom callbacks * @arg cb Callback handler * * The reference to the callback handler is taken into account - * automatically, it is released again upon calling nl_handle_destroy(). + * automatically, it is released again upon calling nl_socket_free(). * *@return Newly allocted socket handle or NULL. */ -struct nl_handle *nl_handle_alloc_cb(struct nl_cb *cb) +struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb) { if (cb == NULL) BUG(); - return __alloc_handle(nl_cb_get(cb)); + return __alloc_socket(nl_cb_get(cb)); } /** - * Destroy netlink handle. - * @arg handle Netlink handle. + * Free a netlink socket. + * @arg sk Netlink socket. */ -void nl_handle_destroy(struct nl_handle *handle) +void nl_socket_free(struct nl_sock *sk) { - if (!handle) + if (!sk) return; - if (handle->h_fd >= 0) - close(handle->h_fd); + if (sk->s_fd >= 0) + close(sk->s_fd); - if (!(handle->h_flags & NL_OWN_PORT)) - release_local_port(handle->h_local.nl_pid); + if (!(sk->s_flags & NL_OWN_PORT)) + release_local_port(sk->s_local.nl_pid); - nl_cb_put(handle->h_cb); - free(handle); + nl_cb_put(sk->s_cb); + free(sk); } /** @} */ @@ -255,33 +176,60 @@ static int noop_seq_check(struct nl_msg *msg, void *arg) /** * Disable sequence number checking. - * @arg handle Netlink handle. + * @arg sk Netlink socket. * - * Disables checking of sequence numbers on the netlink handle. This is + * Disables checking of sequence numbers on the netlink socket This is * required to allow messages to be processed which were not requested by * a preceding request message, e.g. netlink events. * * @note This function modifies the NL_CB_SEQ_CHECK configuration in * the callback handle associated with the socket. */ -void nl_disable_sequence_check(struct nl_handle *handle) +void nl_socket_disable_seq_check(struct nl_sock *sk) { - nl_cb_set(handle->h_cb, NL_CB_SEQ_CHECK, + nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, noop_seq_check, NULL); } /** * Use next sequence number - * @arg handle Netlink handle + * @arg sk Netlink socket. * * Uses the next available sequence number and increases the counter * by one for subsequent calls. * * @return Unique serial sequence number */ -unsigned int nl_socket_use_seq(struct nl_handle *handle) +unsigned int nl_socket_use_seq(struct nl_sock *sk) +{ + return sk->s_seq_next++; +} + +/** + * Disable automatic request for ACK + * @arg sk Netlink socket. + * + * The default behaviour of a socket is to request an ACK for + * each message sent to allow for the caller to synchronize to + * the completion of the netlink operation. This function + * disables this behaviour and will result in requests being + * sent which will not have the NLM_F_ACK flag set automatically. + * However, it is still possible for the caller to set the + * NLM_F_ACK flag explicitely. + */ +void nl_socket_disable_auto_ack(struct nl_sock *sk) +{ + sk->s_flags |= NL_NO_AUTO_ACK; +} + +/** + * Enable automatic request for ACK (default) + * @arg sk Netlink socket. + * @see nl_socket_disable_auto_ack + */ +void nl_socket_enable_auto_ack(struct nl_sock *sk) { - return handle->h_seq_next++; + sk->s_flags &= ~NL_NO_AUTO_ACK; } /** @} */ @@ -291,31 +239,31 @@ unsigned int nl_socket_use_seq(struct nl_handle *handle) * @{ */ -uint32_t nl_socket_get_local_port(struct nl_handle *handle) +uint32_t nl_socket_get_local_port(struct nl_sock *sk) { - return handle->h_local.nl_pid; + return sk->s_local.nl_pid; } /** * Set local port of socket - * @arg handle Netlink handle + * @arg sk Netlink socket. * @arg port Local port identifier * * Assigns a local port identifier to the socket. If port is 0 * a unique port identifier will be generated automatically. */ -void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port) +void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port) { if (port == 0) { port = generate_local_port(); - handle->h_flags &= ~NL_OWN_PORT; + sk->s_flags &= ~NL_OWN_PORT; } else { - if (!(handle->h_flags & NL_OWN_PORT)) - release_local_port(handle->h_local.nl_pid); - handle->h_flags |= NL_OWN_PORT; + if (!(sk->s_flags & NL_OWN_PORT)) + release_local_port(sk->s_local.nl_pid); + sk->s_flags |= NL_OWN_PORT; } - handle->h_local.nl_pid = port; + sk->s_local.nl_pid = port; } /** @} */ @@ -326,13 +274,14 @@ void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port) */ /** - * Join a group - * @arg handle Netlink handle + * Join groups + * @arg sk Netlink socket * @arg group Group identifier * - * Joins the specified group using the modern socket option which + * Joins the specified groups using the modern socket option which * is available since kernel version 2.6.14. It allows joining an - * almost arbitary number of groups without limitation. + * almost arbitary number of groups without limitation. The list + * of groups has to be terminated by 0 (%NFNLGRP_NONE). * * Make sure to use the correct group definitions as the older * bitmask definitions for nl_join_groups() are likely to still @@ -340,61 +289,95 @@ void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port) * * @return 0 on sucess or a negative error code. */ -int nl_socket_add_membership(struct nl_handle *handle, int group) +int nl_socket_add_memberships(struct nl_sock *sk, int group, ...) { int err; + va_list ap; - if (handle->h_fd == -1) - return nl_error(EBADFD, "Socket not connected"); + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; - err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &group, sizeof(group)); - if (err < 0) - return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) " - "failed"); + va_start(ap, group); + + while (group != 0) { + if (group < 0) + return -NLE_INVAL; + + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &group, sizeof(group)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + group = va_arg(ap, int); + } + + va_end(ap); return 0; } +int nl_socket_add_membership(struct nl_sock *sk, int group) +{ + return nl_socket_add_memberships(sk, group, 0); +} + /** - * Leave a group - * @arg handle Netlink handle + * Leave groups + * @arg sk Netlink socket * @arg group Group identifier * - * Leaves the specified group using the modern socket option - * which is available since kernel version 2.6.14. + * Leaves the specified groups using the modern socket option + * which is available since kernel version 2.6.14. The list of groups + * has to terminated by 0 (%NFNLGRP_NONE). * * @see nl_socket_add_membership * @return 0 on success or a negative error code. */ -int nl_socket_drop_membership(struct nl_handle *handle, int group) +int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...) { int err; + va_list ap; - if (handle->h_fd == -1) - return nl_error(EBADFD, "Socket not connected"); + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; - err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, - &group, sizeof(group)); - if (err < 0) - return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) " - "failed"); + va_start(ap, group); + + while (group != 0) { + if (group < 0) + return -NLE_INVAL; + + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, + &group, sizeof(group)); + if (err < 0) + return -nl_syserr2nlerr(errno); + + group = va_arg(ap, int); + } + + va_end(ap); return 0; } +int nl_socket_drop_membership(struct nl_sock *sk, int group) +{ + return nl_socket_drop_memberships(sk, group, 0); +} + + /** * Join multicast groups (deprecated) - * @arg handle Netlink handle. + * @arg sk Netlink socket. * @arg groups Bitmask of groups to join. * * This function defines the old way of joining multicast group which * has to be done prior to calling nl_connect(). It works on any kernel * version but is very limited as only 32 groups can be joined. */ -void nl_join_groups(struct nl_handle *handle, int groups) +void nl_join_groups(struct nl_sock *sk, int groups) { - handle->h_local.nl_groups |= groups; + sk->s_local.nl_groups |= groups; } @@ -405,14 +388,14 @@ void nl_join_groups(struct nl_handle *handle, int groups) * @{ */ -uint32_t nl_socket_get_peer_port(struct nl_handle *handle) +uint32_t nl_socket_get_peer_port(struct nl_sock *sk) { - return handle->h_peer.nl_pid; + return sk->s_peer.nl_pid; } -void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port) +void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port) { - handle->h_peer.nl_pid = port; + sk->s_peer.nl_pid = port; } /** @} */ @@ -422,44 +405,44 @@ void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port) * @{ */ -int nl_socket_get_fd(struct nl_handle *handle) +int nl_socket_get_fd(struct nl_sock *sk) { - return handle->h_fd; + return sk->s_fd; } /** - * Set file descriptor of socket handle to non-blocking state - * @arg handle Netlink socket + * Set file descriptor of socket to non-blocking state + * @arg sk Netlink socket. * * @return 0 on success or a negative error code. */ -int nl_socket_set_nonblocking(struct nl_handle *handle) +int nl_socket_set_nonblocking(struct nl_sock *sk) { - if (handle->h_fd == -1) - return nl_error(EBADFD, "Socket not connected"); + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; - if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0) - return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed"); + if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) + return -nl_syserr2nlerr(errno); return 0; } /** * Enable use of MSG_PEEK when reading from socket - * @arg handle Netlink socket + * @arg sk Netlink socket. */ -void nl_socket_enable_msg_peek(struct nl_handle *handle) +void nl_socket_enable_msg_peek(struct nl_sock *sk) { - handle->h_flags |= NL_MSG_PEEK; + sk->s_flags |= NL_MSG_PEEK; } /** * Disable use of MSG_PEEK when reading from socket - * @arg handle Netlink socket + * @arg sk Netlink socket. */ -void nl_socket_disable_msg_peek(struct nl_handle *handle) +void nl_socket_disable_msg_peek(struct nl_sock *sk) { - handle->h_flags &= ~NL_MSG_PEEK; + sk->s_flags &= ~NL_MSG_PEEK; } /** @} */ @@ -469,20 +452,20 @@ void nl_socket_disable_msg_peek(struct nl_handle *handle) * @{ */ -struct nl_cb *nl_socket_get_cb(struct nl_handle *handle) +struct nl_cb *nl_socket_get_cb(struct nl_sock *sk) { - return nl_cb_get(handle->h_cb); + return nl_cb_get(sk->s_cb); } -void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb) +void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb) { - nl_cb_put(handle->h_cb); - handle->h_cb = nl_cb_get(cb); + nl_cb_put(sk->s_cb); + sk->s_cb = nl_cb_get(cb); } /** * Modify the callback handler associated to the socket - * @arg handle netlink handle + * @arg sk Netlink socket. * @arg type which type callback to set * @arg kind kind of callback * @arg func callback function @@ -490,11 +473,11 @@ void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb) * * @see nl_cb_set */ -int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type, +int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg) { - return nl_cb_set(handle->h_cb, type, kind, func, arg); + return nl_cb_set(sk->s_cb, type, kind, func, arg); } /** @} */ @@ -505,19 +488,19 @@ int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type, */ /** - * Set socket buffer size of netlink handle. - * @arg handle Netlink handle. + * Set socket buffer size of netlink socket. + * @arg sk Netlink socket. * @arg rxbuf New receive socket buffer size in bytes. * @arg txbuf New transmit socket buffer size in bytes. * - * Sets the socket buffer size of a netlink handle to the specified + * Sets the socket buffer size of a netlink socket to the specified * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a * good default value. * * @note It is not required to call this function prior to nl_connect(). * @return 0 on sucess or a negative error code. */ -int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf) +int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { int err; @@ -527,69 +510,69 @@ int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf) if (txbuf <= 0) txbuf = 32768; - if (handle->h_fd == -1) - return nl_error(EBADFD, "Socket not connected"); + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; - err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF, + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf)); if (err < 0) - return nl_error(errno, "setsockopt(SO_SNDBUF) failed"); + return -nl_syserr2nlerr(errno); - err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF, + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, &rxbuf, sizeof(rxbuf)); if (err < 0) - return nl_error(errno, "setsockopt(SO_RCVBUF) failed"); + return -nl_syserr2nlerr(errno); - handle->h_flags |= NL_SOCK_BUFSIZE_SET; + sk->s_flags |= NL_SOCK_BUFSIZE_SET; return 0; } /** - * Enable/disable credential passing on netlink handle. - * @arg handle Netlink handle + * Enable/disable credential passing on netlink socket. + * @arg sk Netlink socket. * @arg state New state (0 - disabled, 1 - enabled) * * @return 0 on success or a negative error code */ -int nl_set_passcred(struct nl_handle *handle, int state) +int nl_socket_set_passcred(struct nl_sock *sk, int state) { int err; - if (handle->h_fd == -1) - return nl_error(EBADFD, "Socket not connected"); + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; - err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED, + err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state)); if (err < 0) - return nl_error(errno, "setsockopt(SO_PASSCRED) failed"); + return -nl_syserr2nlerr(errno); if (state) - handle->h_flags |= NL_SOCK_PASSCRED; + sk->s_flags |= NL_SOCK_PASSCRED; else - handle->h_flags &= ~NL_SOCK_PASSCRED; + sk->s_flags &= ~NL_SOCK_PASSCRED; return 0; } /** * Enable/disable receival of additional packet information - * @arg handle Netlink handle + * @arg sk Netlink socket. * @arg state New state (0 - disabled, 1 - enabled) * * @return 0 on success or a negative error code */ -int nl_socket_recv_pktinfo(struct nl_handle *handle, int state) +int nl_socket_recv_pktinfo(struct nl_sock *sk, int state) { int err; - if (handle->h_fd == -1) - return nl_error(EBADFD, "Socket not connected"); + if (sk->s_fd == -1) + return -NLE_BAD_SOCK; - err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO, + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO, &state, sizeof(state)); if (err < 0) - return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed"); + return -nl_syserr2nlerr(errno); return 0; } diff --git a/lib/utils.c b/lib/utils.c index b5b457a..e1fdae1 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -6,10 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ /** + * @ingroup core * @defgroup utils Utilities * @{ */ @@ -25,7 +26,7 @@ int nl_debug = 0; struct nl_dump_params nl_debug_dp = { - .dp_type = NL_DUMP_FULL, + .dp_type = NL_DUMP_DETAILS, }; static void __init nl_debug_init(void) @@ -41,48 +42,6 @@ static void __init nl_debug_init(void) nl_debug_dp.dp_fd = stderr; } -/** - * @name Error Code Helpers - * @{ - */ - -static char *errbuf; -static int nlerrno; - -/** @cond SKIP */ -int __nl_error(int err, const char *file, unsigned int line, const char *func, - const char *fmt, ...) -{ - char *user_err; - va_list args; - - if (errbuf) { - free(errbuf); - errbuf = NULL; - } - - nlerrno = err; - - if (fmt) { - va_start(args, fmt); - vasprintf(&user_err, fmt, args); - va_end(args); - } - -#ifdef VERBOSE_ERRORS - asprintf(&errbuf, "%s:%u:%s: %s (errno = %s)", - file, line, func, fmt ? user_err : "", strerror(err)); -#else - asprintf(&errbuf, "%s (errno = %s)", - fmt ? user_err : "", strerror(err)); -#endif - - if (fmt) - free(user_err); - - return -err; -} - int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) { FILE *fd; @@ -90,8 +49,7 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) fd = fopen(path, "r"); if (fd == NULL) - return nl_error(errno, "Unable to open file %s for reading", - path); + return -nl_syserr2nlerr(errno); while (fgets(buf, sizeof(buf), fd)) { int goodlen, err; @@ -103,17 +61,17 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) num = strtol(buf, &end, 0); if (end == buf) - return nl_error(EINVAL, "Parsing error"); + return -NLE_INVAL; if (num == LONG_MIN || num == LONG_MAX) - return nl_error(errno, "Number of out range"); + return -NLE_RANGE; while (*end == ' ' || *end == '\t') end++; goodlen = strcspn(end, "#\r\n\t "); if (goodlen == 0) - return nl_error(EINVAL, "Empty string"); + return -NLE_INVAL; end[goodlen] = '\0'; @@ -127,49 +85,6 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)) return 0; } -/** @endcond */ - -int nl_get_errno(void) -{ - return nlerrno; -} - - -/** - * Return error message for an error code - * @return error message - */ -char *nl_geterror(void) -{ - if (errbuf) - return errbuf; - - if (nlerrno) - return strerror(nlerrno); - - return "Sucess\n"; -} - -/** - * Print a libnl error message - * @arg s error message prefix - * - * Prints the error message of the call that failed last. - * - * If s is not NULL and *s is not a null byte the argument - * string is printed, followed by a colon and a blank. Then - * the error message and a new-line. - */ -void nl_perror(const char *s) -{ - if (s && *s) - fprintf(stderr, "%s: %s\n", s, nl_geterror()); - else - fprintf(stderr, "%s\n", nl_geterror()); -} - -/** @} */ - /** * @name Unit Pretty-Printing * @{ @@ -285,7 +200,7 @@ long nl_size2int(const char *str) char *p; long l = strtol(str, &p, 0); if (p == str) - return -1; + return -NLE_INVAL; if (*p) { if (!strcasecmp(p, "kb") || !strcasecmp(p, "k")) @@ -303,7 +218,7 @@ long nl_size2int(const char *str) else if (!strcasecmp(p, "bit")) l /= 8; else if (strcasecmp(p, "b") != 0) - return -1; + return -NLE_INVAL; } return l; @@ -328,16 +243,16 @@ long nl_prob2int(const char *str) double d = strtod(str, &p); if (p == str) - return -1; + return -NLE_INVAL; if (d > 1.0) d /= 100.0f; if (d > 1.0f || d < 0.0f) - return -1; + return -NLE_RANGE; if (*p && strcmp(p, "%") != 0) - return -1; + return -NLE_INVAL; return rint(d * NL_PROB_MAX); } @@ -370,7 +285,7 @@ static void __init get_psched_settings(void) { char name[FILENAME_MAX]; FILE *fd; - int got_hz = 0, got_tick = 0; + int got_hz = 0; if (getenv("HZ")) { long hz = strtol(getenv("HZ"), NULL, 0); @@ -386,28 +301,25 @@ static void __init get_psched_settings(void) if (getenv("TICKS_PER_USEC")) { double t = strtod(getenv("TICKS_PER_USEC"), NULL); - ticks_per_usec = t; - got_tick = 1; } + else { + if (getenv("PROC_NET_PSCHED")) + snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED")); + else if (getenv("PROC_ROOT")) + snprintf(name, sizeof(name), "%s/net/psched", + getenv("PROC_ROOT")); + else + strncpy(name, "/proc/net/psched", sizeof(name) - 1); - - if (getenv("PROC_NET_PSCHED")) - snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED")); - else if (getenv("PROC_ROOT")) - snprintf(name, sizeof(name), "%s/net/psched", - getenv("PROC_ROOT")); - else - strncpy(name, "/proc/net/psched", sizeof(name) - 1); - - if ((fd = fopen(name, "r"))) { - uint32_t tick, us, nom; - int r = fscanf(fd, "%08x%08x%08x%*08x", &tick, &us, &nom); - - if (4 == r && nom == 1000000 && !got_tick) + if ((fd = fopen(name, "r"))) { + uint32_t tick, us; + /* the file contains 4 hexadecimals, but we just use + the first two of them */ + fscanf(fd, "%08x %08x", &tick, &us); ticks_per_usec = (double)tick/(double)us; - - fclose(fd); + fclose(fd); + } } } @@ -442,25 +354,40 @@ uint32_t nl_ticks2us(uint32_t ticks) return ticks / ticks_per_usec; } -long nl_time2int(const char *str) +int nl_str2msec(const char *str, uint64_t *result) { + uint64_t total = 0, l; + int plen; char *p; - long l = strtol(str, &p, 0); - if (p == str) - return -1; - if (*p) { - if (!strcasecmp(p, "min") == 0 || !strcasecmp(p, "m")) - l *= 60; - else if (!strcasecmp(p, "hour") || !strcasecmp(p, "h")) - l *= 60*60; - else if (!strcasecmp(p, "day") || !strcasecmp(p, "d")) - l *= 60*60*24; - else if (strcasecmp(p, "s") != 0) - return -1; - } + do { + l = strtoul(str, &p, 0); + if (p == str) + return -NLE_INVAL; + else if (*p) { + plen = strcspn(p, " \t"); + + if (!plen) + total += l; + else if (!strncasecmp(p, "sec", plen)) + total += (l * 1000); + else if (!strncasecmp(p, "min", plen)) + total += (l * 1000*60); + else if (!strncasecmp(p, "hour", plen)) + total += (l * 1000*60*60); + else if (!strncasecmp(p, "day", plen)) + total += (l * 1000*60*60*24); + else + return -NLE_INVAL; + + str = p + plen; + } else + total += l; + } while (*str && *p); + + *result = total; - return l; + return 0; } /** @@ -505,6 +432,47 @@ char * nl_msec2str(uint64_t msec, char *buf, size_t len) /** @} */ /** + * @name Netlink Family Translations + * @{ + */ + +static struct trans_tbl nlfamilies[] = { + __ADD(NETLINK_ROUTE,route) + __ADD(NETLINK_USERSOCK,usersock) + __ADD(NETLINK_FIREWALL,firewall) + __ADD(NETLINK_INET_DIAG,inetdiag) + __ADD(NETLINK_NFLOG,nflog) + __ADD(NETLINK_XFRM,xfrm) + __ADD(NETLINK_SELINUX,selinux) + __ADD(NETLINK_ISCSI,iscsi) + __ADD(NETLINK_AUDIT,audit) + __ADD(NETLINK_FIB_LOOKUP,fib_lookup) + __ADD(NETLINK_CONNECTOR,connector) + __ADD(NETLINK_NETFILTER,netfilter) + __ADD(NETLINK_IP6_FW,ip6_fw) + __ADD(NETLINK_DNRTMSG,dnrtmsg) + __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent) + __ADD(NETLINK_GENERIC,generic) + __ADD(NETLINK_SCSITRANSPORT,scsitransport) + __ADD(NETLINK_ECRYPTFS,ecryptfs) +}; + +char * nl_nlfamily2str(int family, char *buf, size_t size) +{ + return __type2str(family, buf, size, nlfamilies, + ARRAY_SIZE(nlfamilies)); +} + +int nl_str2nlfamily(const char *name) +{ + return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies)); +} + +/** + * @} + */ + +/** * @name Link Layer Protocol Translations * @{ */ @@ -699,7 +667,7 @@ int nl_str2ip_proto(const char *name) l = strtoul(name, &end, 0); if (l == ULONG_MAX || *end != '\0') - return -1; + return -NLE_OBJ_NOTFOUND; return (int) l; } @@ -714,7 +682,6 @@ int nl_str2ip_proto(const char *name) /** * Handle a new line while dumping * @arg params Dumping parameters - * @arg line Number of lines dumped already. * * This function must be called before dumping any onto a * new line. It will ensure proper prefixing as specified @@ -722,8 +689,10 @@ int nl_str2ip_proto(const char *name) * * @note This function will NOT dump any newlines itself */ -void nl_new_line(struct nl_dump_params *params, int line) +void nl_new_line(struct nl_dump_params *params) { + params->dp_line++; + if (params->dp_prefix) { int i; for (i = 0; i < params->dp_prefix; i++) { @@ -737,9 +706,27 @@ void nl_new_line(struct nl_dump_params *params, int line) } if (params->dp_nl_cb) - params->dp_nl_cb(params, line); + params->dp_nl_cb(params, params->dp_line); } +static void dump_one(struct nl_dump_params *parms, const char *fmt, + va_list args) +{ + if (parms->dp_fd) + vfprintf(parms->dp_fd, fmt, args); + else if (parms->dp_buf || parms->dp_cb) { + char *buf = NULL; + vasprintf(&buf, fmt, args); + if (parms->dp_cb) + parms->dp_cb(parms, buf); + else + strncat(parms->dp_buf, buf, + parms->dp_buflen - strlen(parms->dp_buf) - 1); + free(buf); + } +} + + /** * Dump a formatted character string * @arg params Dumping parameters @@ -754,10 +741,195 @@ void nl_dump(struct nl_dump_params *params, const char *fmt, ...) va_list args; va_start(args, fmt); - __dp_dump(params, fmt, args); + dump_one(params, fmt, args); va_end(args); } +void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...) +{ + va_list args; + + nl_new_line(parms); + + va_start(args, fmt); + dump_one(parms, fmt, args); + va_end(args); +} + + /** @} */ +/** @cond SKIP */ + +int __trans_list_add(int i, const char *a, struct nl_list_head *head) +{ + struct trans_list *tl; + + tl = calloc(1, sizeof(*tl)); + if (!tl) + return -NLE_NOMEM; + + tl->i = i; + tl->a = strdup(a); + + nl_list_add_tail(&tl->list, head); + + return 0; +} + +void __trans_list_clear(struct nl_list_head *head) +{ + struct trans_list *tl, *next; + + nl_list_for_each_entry_safe(tl, next, head, list) { + free(tl->a); + free(tl); + } +} + +char *__type2str(int type, char *buf, size_t len, struct trans_tbl *tbl, + size_t tbl_len) +{ + int i; + for (i = 0; i < tbl_len; i++) { + if (tbl[i].i == type) { + snprintf(buf, len, "%s", tbl[i].a); + return buf; + } + } + + snprintf(buf, len, "0x%x", type); + return buf; +} + +char *__list_type2str(int type, char *buf, size_t len, + struct nl_list_head *head) +{ + struct trans_list *tl; + + nl_list_for_each_entry(tl, head, list) { + if (tl->i == type) { + snprintf(buf, len, "%s", tl->a); + return buf; + } + } + + snprintf(buf, len, "0x%x", type); + return buf; +} + +char *__flags2str(int flags, char *buf, size_t len, + struct trans_tbl *tbl, size_t tbl_len) +{ + int i; + int tmp = flags; + + memset(buf, 0, len); + + for (i = 0; i < tbl_len; i++) { + if (tbl[i].i & tmp) { + tmp &= ~tbl[i].i; + strncat(buf, tbl[i].a, len - strlen(buf) - 1); + if ((tmp & flags)) + strncat(buf, ",", len - strlen(buf) - 1); + } + } + + return buf; +} + +int __str2type(const char *buf, struct trans_tbl *tbl, size_t tbl_len) +{ + unsigned long l; + char *end; + int i; + + if (*buf == '\0') + return -NLE_INVAL; + + for (i = 0; i < tbl_len; i++) + if (!strcasecmp(tbl[i].a, buf)) + return tbl[i].i; + + l = strtoul(buf, &end, 0); + if (l == ULONG_MAX || *end != '\0') + return -NLE_OBJ_NOTFOUND; + + return (int) l; +} + +int __list_str2type(const char *buf, struct nl_list_head *head) +{ + struct trans_list *tl; + unsigned long l; + char *end; + + if (*buf == '\0') + return -NLE_INVAL; + + nl_list_for_each_entry(tl, head, list) { + if (!strcasecmp(tl->a, buf)) + return tl->i; + } + + l = strtoul(buf, &end, 0); + if (l == ULONG_MAX || *end != '\0') + return -NLE_OBJ_NOTFOUND; + + return (int) l; +} + +int __str2flags(const char *buf, struct trans_tbl *tbl, size_t tbl_len) +{ + int i, flags = 0, len; + char *p = (char *) buf, *t; + + for (;;) { + if (*p == ' ') + p++; + + t = strchr(p, ','); + len = t ? t - p : strlen(p); + for (i = 0; i < tbl_len; i++) + if (!strncasecmp(tbl[i].a, p, len)) + flags |= tbl[i].i; + + if (!t) + return flags; + + p = ++t; + } + + return 0; +} + +void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params) +{ + int type = params->dp_type; + + if (type < 0 || type > NL_DUMP_MAX) + BUG(); + + params->dp_line = 0; + + if (params->dp_dump_msgtype) { +#if 0 + /* XXX */ + char buf[64]; + + dp_dump_line(params, 0, "%s ", + nl_cache_mngt_type2name(obj->ce_ops, + obj->ce_ops->co_protocol, + obj->ce_msgtype, + buf, sizeof(buf))); +#endif + params->dp_pre_dump = 1; + } + + if (obj->ce_ops->oo_dump[type]) + obj->ce_ops->oo_dump[type](obj, params); +} + +/** @endcond */ + /** @} */ diff --git a/libnl-1.pc.in b/libnl-2.0.pc.in index 7ac8413..e44f0fb 100644 --- a/libnl-1.pc.in +++ b/libnl-2.0.pc.in @@ -1,10 +1,10 @@ prefix=@prefix@ -exec_prefix=@prefix@ +exec_prefix=@exec_prefix@ libdir=@libdir@ -includedir=@prefix@/include +includedir=@includedir@ Name: libnl Description: Convenience library for netlink sockets Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lnl -Cflags: +Cflags: -I${includedir} diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..8d0c756 --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,2 @@ +/lt*.m4 +/libtool.m4 diff --git a/src/.gitignore b/src/.gitignore index 11fe5ab..60233c8 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,13 +1,12 @@ -genl-ctrl-dump -genl-ctrl-get -nf-ct-dump +genl-ctrl-list +nf-ct-list nf-log nf-monitor nl-addr-add nl-addr-delete -nl-addr-dump +nl-addr-list nl-fib-lookup -nl-link-dump +nl-link-list nl-link-ifindex2name nl-link-name2ifindex nl-link-set @@ -17,15 +16,16 @@ nl-list-sockets nl-monitor nl-neigh-add nl-neigh-delete -nl-neigh-dump -nl-neightbl-dump +nl-neigh-list +nl-neightbl-list nl-qdisc-add nl-qdisc-delete -nl-qdisc-dump +nl-qdisc-list nl-route-add -nl-route-del -nl-route-dump +nl-route-delete +nl-route-list nl-route-get -nl-rule-dump -nl-tctree-dump +nl-rule-list +nl-tctree-list nl-util-addr +nf-queue diff --git a/src/COPYING b/src/COPYING new file mode 100644 index 0000000..4432540 --- /dev/null +++ b/src/COPYING @@ -0,0 +1,676 @@ + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. + diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index ddbe29a..0000000 --- a/src/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# src/Makefile -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation version 2.1 -# of the License. -# -# Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> -# - -ifeq ($(shell [ ! -r ../Makefile.opts ] && echo 1),) - include ../Makefile.opts -endif - -LDFLAGS += -L../lib -lnl utils.o -CIN := $(wildcard nl-*.c) $(wildcard genl-*.c) $(wildcard nf-*.c) -TOOLS := $(CIN:%.c=%) - -all: $(TOOLS) - -$(TOOLS): utils.o - -nl-%: nl-%.c - @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) - -genl-%: genl-%.c - @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) - -nf-%: nf-%.c - @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) - -clean: - @echo " CLEAN src"; \ - rm -f $(TOOLS) utils.o - -distclean: clean - -install: - @true - -include ../Makefile.rules diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..dda32a7 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,101 @@ +# -*- Makefile -*- + +SUBDIRS = lib + +AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE +AM_LDFLAGS = -L${top_builddir}/lib -L${top_builddir}/src/lib -lnl-cli + +noinst_PROGRAMS = \ + genl-ctrl-list \ + nf-ct-list nf-log nf-queue nf-monitor \ + nl-addr-add nl-addr-delete nl-addr-list \ + nl-link-list nl-link-set nl-link-stats \ + nl-link-ifindex2name nl-link-name2ifindex \ + nl-neigh-add nl-neigh-delete nl-neigh-list \ + nl-qdisc-delete nl-qdisc-list \ + nl-rule-list \ + nl-neightbl-list \ + nl-monitor \ + nl-tctree-list \ + nl-route-add nl-route-delete nl-route-get nl-route-list \ + nl-fib-lookup \ + nl-list-caches nl-list-sockets \ + nl-util-addr \ + nl-pktloc-lookup + +genl_ctrl_list_SOURCES = genl-ctrl-list.c +genl_ctrl_list_LDADD = -lnl-genl -lnl-route + +nf_ct_list_SOURCES = nf-ct-list.c +nf_ct_list_LDADD = -lnl-nf +nf_log_SOURCES = nf-log.c +nf_log_LDADD = -lnl-nf +nf_queue_SOURCES = nf-queue.c +nf_queue_LDADD = -lnl-nf +nf_monitor_SOURCES = nf-monitor.c +nf_monitor_LDADD = -lnl-nf + +nl_addr_add_SOURCES = nl-addr-add.c +nl_addr_add_LDADD = -lnl-route +nl_addr_delete_SOURCES = nl-addr-delete.c +nl_addr_delete_LDADD = -lnl-route +nl_addr_list_SOURCES = nl-addr-list.c +nl_addr_list_LDADD = -lnl-route + +nl_link_list_SOURCES = nl-link-list.c +nl_link_list_LDADD = -lnl-route +nl_link_set_SOURCES = nl-link-set.c +nl_link_set_LDADD = -lnl-route +nl_link_stats_SOURCES = nl-link-stats.c +nl_link_stats_LDADD = -lnl-route +nl_link_ifindex2name_SOURCES = nl-link-ifindex2name.c +nl_link_ifindex2name_LDADD = -lnl-route +nl_link_name2ifindex_SOURCES = nl-link-name2ifindex.c +nl_link_name2ifindex_LDADD = -lnl-route + +nl_monitor_SOURCES = nl-monitor.c +nl_monitor_LDADD = -lnl-route + +nl_neigh_add_SOURCES = nl-neigh-add.c +nl_neigh_add_LDADD = -lnl-route +nl_neigh_delete_SOURCES = nl-neigh-delete.c +nl_neigh_delete_LDADD = -lnl-route +nl_neigh_list_SOURCES = nl-neigh-list.c +nl_neigh_list_LDADD = -lnl-route + +nl_neightbl_list_SOURCES = nl-neightbl-list.c +nl_neightbl_list_LDADD = -lnl-route + +nl_qdisc_delete_SOURCES = nl-qdisc-delete.c +nl_qdisc_delete_LDADD = -lnl-route +nl_qdisc_list_SOURCES = nl-qdisc-list.c +nl_qdisc_list_LDADD = -lnl-route + +nl_route_add_SOURCES = nl-route-add.c +nl_route_add_LDADD = -lnl-route +nl_route_delete_SOURCES = nl-route-delete.c +nl_route_delete_LDADD = -lnl-route +nl_route_get_SOURCES = nl-route-get.c +nl_route_get_LDADD = -lnl-route +nl_route_list_SOURCES = nl-route-list.c +nl_route_list_LDADD = -lnl-route + +nl_rule_list_SOURCES = nl-rule-list.c +nl_rule_list_LDADD = -lnl-route + +nl_tctree_list_SOURCES = nl-tctree-list.c +nl_tctree_list_LDADD = -lnl-route + +nl_fib_lookup_SOURCES = nl-fib-lookup.c +nl_fib_lookup_LDADD = -lnl-route + +nl_list_caches_SOURCES = nl-list-caches.c +nl_list_caches_LDADD = -lnl-route +nl_list_sockets_SOURCES = nl-list-sockets.c +nl_list_sockets_LDADD = -lnl-route + +nl_util_addr_SOURCES = nl-util-addr.c +nl_util_addr_LDADD = -lnl-route + +nl_pktloc_lookup_SOURCES = nl-pktloc-lookup.c +nl_pktloc_lookup_LDADD = -lnl-route diff --git a/src/cls/basic.c b/src/cls/basic.c new file mode 100644 index 0000000..df1c112 --- /dev/null +++ b/src/cls/basic.c @@ -0,0 +1,90 @@ +/* + * src/cls/basic.c Basic Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#include "utils.h" +#include <netlink/route/cls/basic.h> +#include <netlink/route/cls/ematch.h> + +static void print_usage(void) +{ + printf( +"Usage: ... basic [OPTIONS]...\n" +"\n" +"Options\n" +" -h, --help Show this help.\n" +" -e, --ematch=MATCH Extended match (See --ematch help).\n" +" -c, --classid=HANDLE Target class to classify matching packets to.\n" + ); + exit(0); +} + +static void basic_parse_argv(struct rtnl_cls *cls, int argc, char **argv) +{ + uint32_t classid; + + for (;;) { + int c, optidx = 0, err; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "ematch", 1, 0, 'e' }, + { "classid", 1, 0, 'c' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "he:c:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case '?': + exit(NLE_INVAL); + + case 'h': + print_usage(); + + case 'e': +#if 0 + if ((err = parse_ematch_syntax(optarg, &tree)) < 0) + fatal(err, "Error while parsing ematch: %s", + nl_geterror(err)); + + if ((err = rtnl_basic_set_ematch(cls, tree)) < 0) + fatal(err, "Unable to set ematch: %s", + nl_geterror(err)); +#endif + break; + + case 'c': + if ((err = rtnl_tc_str2handle(optarg, &classid)) < 0) + fatal(err, "Invalid classid \"%s\": %s", + optarg, nl_geterror(err)); + + if ((err = rtnl_basic_set_classid(cls, classid)) < 0) + fatal(err, "Unable to set classid: %s", + nl_geterror(err)); + break; + } + } +} + +static struct cls_module basic_module = { + .name = "basic", + .parse_argv = basic_parse_argv, +}; + +static void __attribute__ ((constructor)) basic_init(void) +{ + register_cls_module(&basic_module); +} + +static void __attribute__ ((destructor)) basic_exit(void) +{ + unregister_cls_module(&basic_module); +} diff --git a/src/cls/cgroup.c b/src/cls/cgroup.c new file mode 100644 index 0000000..ad0392f --- /dev/null +++ b/src/cls/cgroup.c @@ -0,0 +1,78 @@ +/* + * src/cls/cgroup.c Control Groups Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2009 Thomas Graf <tgraf@suug.ch> + */ + +#include "utils.h" +#include <netlink/route/cls/cgroup.h> +#include <netlink/route/cls/ematch.h> + +static void print_usage(void) +{ + printf( +"Usage: ... cgroup [OPTIONS]...\n" +"\n" +"Options\n" +" -h, --help Show this help.\n" +" -e, --ematch=MATCH Extended match (See --ematch help).\n" +" -c, --classid=HANDLE Target class to classify matching packets to.\n" + ); + exit(0); +} + +static void basic_parse_argv(struct rtnl_cls *cls, int argc, char **argv) +{ + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "ematch", 1, 0, 'e' }, + { "classid", 1, 0, 'c' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "he:c:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case '?': + exit(NLE_INVAL); + + case 'h': + print_usage(); + +#if 0 + case 'e': + if ((err = parse_ematch_syntax(optarg, &tree)) < 0) + fatal(err, "Error while parsing ematch: %s", + nl_geterror(err)); + + if ((err = rtnl_basic_set_ematch(cls, tree)) < 0) + fatal(err, "Unable to set ematch: %s", + nl_geterror(err)); + break; +#endif + } + } +} + +static struct cls_module cgroup_module = { + .name = "cgroup", + .parse_argv = basic_parse_argv, +}; + +static void __init cgroup_init(void) +{ + register_cls_module(&cgroup_module); +} + +static void __exit cgroup_exit(void) +{ + unregister_cls_module(&cgroup_module); +} diff --git a/src/cls/utils.c b/src/cls/utils.c new file mode 100644 index 0000000..ef6603b --- /dev/null +++ b/src/cls/utils.c @@ -0,0 +1,105 @@ +/* + * src/cls-utils.c Classifier Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include "utils.h" + +struct rtnl_cls *nlt_alloc_cls(void) +{ + struct rtnl_cls *cls; + + cls = rtnl_cls_alloc(); + if (!cls) + fatal(ENOMEM, "Unable to allocate classifier object"); + + return cls; +} + +void parse_dev(struct rtnl_cls *cls, struct nl_cache *link_cache, char *arg) +{ + int ival; + + if (!(ival = rtnl_link_name2i(link_cache, arg))) + fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_cls_set_ifindex(cls, ival); +} + +void parse_prio(struct rtnl_cls *cls, char *arg) +{ + uint32_t prio = parse_u32(arg); + rtnl_cls_set_prio(cls, prio); +} + +void parse_parent(struct rtnl_cls *cls, char *arg) +{ + uint32_t parent; + int err; + + if ((err = rtnl_tc_str2handle(arg, &parent)) < 0) + fatal(err, "Unable to parse handle \"%s\": %s", + arg, nl_geterror(err)); + + rtnl_cls_set_parent(cls, parent); +} + +void parse_handle(struct rtnl_cls *cls, char *arg) +{ + uint32_t handle; + int err; + + if ((err = rtnl_tc_str2handle(arg, &handle)) < 0) + fatal(err, "Unable to parse handle \"%s\": %s", + arg, nl_geterror(err)); + + rtnl_cls_set_handle(cls, handle); +} + +void parse_proto(struct rtnl_cls *cls, char *arg) +{ + int proto = nl_str2ether_proto(arg); + if (proto < 0) + fatal(proto, "Unable to parse protocol \"%s\": %s", + arg, nl_geterror(proto)); + rtnl_cls_set_protocol(cls, proto); +} + +static NL_LIST_HEAD(cls_modules); + +struct cls_module *lookup_cls_mod(struct rtnl_cls_ops *ops) +{ + struct cls_module *mod; + + nl_list_for_each_entry(mod, &cls_modules, list) { + if (mod->ops == ops) + return mod; + } + + return NULL; +} + +void register_cls_module(struct cls_module *mod) +{ + struct rtnl_cls_ops *ops; + + if (!(ops = __rtnl_cls_lookup_ops(mod->name))) + fatal(ENOENT, "Could not locate classifier module \"%s\"", + mod->name); + + if (lookup_cls_mod(ops) != NULL) + fatal(EEXIST, "Duplicate classifier module registration."); + + mod->ops = ops; + nl_list_add_tail(&mod->list, &cls_modules); +} + +void unregister_cls_module(struct cls_module *mod) +{ + nl_list_del(&mod->list); +} diff --git a/src/cls/utils.h b/src/cls/utils.h new file mode 100644 index 0000000..1a8ee9b --- /dev/null +++ b/src/cls/utils.h @@ -0,0 +1,51 @@ +/* + * src/cls-utils.h Classifier Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +#ifndef __CLS_UTILS_H_ +#define __CLS_UTILS_H_ + +#include "../utils.h" +#include <netlink/route/classifier-modules.h> +#include <netlink/route/cls/ematch.h> + +struct cls_module +{ + const char * name; + struct rtnl_cls_ops * ops; + void (*parse_argv)(struct rtnl_cls *, int, char **); + struct nl_list_head list; +}; + +extern struct cls_module *lookup_cls_mod(struct rtnl_cls_ops *); +extern void register_cls_module(struct cls_module *); +extern void unregister_cls_module(struct cls_module *); + +struct ematch_module +{ + int kind; + struct rtnl_ematch_ops *ops; + void (*parse_argv)(struct rtnl_ematch *, int, char **); + struct nl_list_head list; +}; + +extern struct ematch_module *lookup_ematch_mod(struct rtnl_ematch_ops *); +extern void register_ematch_module(struct ematch_module *); +extern void unregister_ematch_module(struct ematch_module *); + +extern struct rtnl_cls *nlt_alloc_cls(void); +extern void parse_dev(struct rtnl_cls *, struct nl_cache *, char *); +extern void parse_prio(struct rtnl_cls *, char *); +extern void parse_parent(struct rtnl_cls *, char *); +extern void parse_handle(struct rtnl_cls *, char *); +extern void parse_proto(struct rtnl_cls *, char *); + +extern int parse_ematch_syntax(const char *, struct rtnl_ematch_tree **); + +#endif diff --git a/src/nl-qdisc-add.c b/src/disabled-nl-qdisc-add.c index be19f9b..a1fab4e 100644 --- a/src/nl-qdisc-add.c +++ b/src/disabled-nl-qdisc-add.c @@ -125,7 +125,7 @@ usage: int main(int argc, char *argv[]) { - struct nl_handle *nlh; + struct nl_sock *nlh; struct rtnl_qdisc *qdisc; uint32_t handle, parent; int err = 1; diff --git a/src/f_addr.c b/src/f_addr.c deleted file mode 100644 index 491d88f..0000000 --- a/src/f_addr.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * src/f_addr.c Address Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -static void get_filter(struct rtnl_addr *addr, int argc, char **argv, int idx, - struct nl_cache *link_cache) -{ - struct nl_addr *a; - - while (argc > idx) { - if (arg_match("dev")) { - if (argc > ++idx) { - int ifindex = rtnl_link_name2i(link_cache, argv[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_addr_set_ifindex(addr, ifindex); - } - } else if (arg_match("family")) { - if (argc > ++idx) { - int family = nl_str2af(argv[idx++]); - if (family == AF_UNSPEC) - goto err_invaf; - rtnl_addr_set_family(addr, family); - } - } else if (arg_match("label")) { - if (argc > ++idx) - rtnl_addr_set_label(addr, argv[idx++]); - } else if (arg_match("scope")) { - if (argc > ++idx) { - int scope = rtnl_str2scope(argv[idx++]); - if (scope < 0) - goto err_invscope; - rtnl_addr_set_scope(addr, scope); - } - } else if (arg_match("local")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - rtnl_addr_get_family(addr)); - if (!a) - goto err_invaddr; - rtnl_addr_set_local(addr, a); - nl_addr_put(a); - } - } else if (arg_match("peer")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - rtnl_addr_get_family(addr)); - if (!a) - goto err_invaddr; - rtnl_addr_set_peer(addr, a); - nl_addr_put(a); - } - } else if (arg_match("broadcast")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - rtnl_addr_get_family(addr)); - if (!a) - goto err_invaddr; - rtnl_addr_set_broadcast(addr, a); - nl_addr_put(a); - } - } else if (arg_match("multicast")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - rtnl_addr_get_family(addr)); - if (!a) - goto err_invaddr; - rtnl_addr_set_multicast(addr, a); - nl_addr_put(a); - } - } else if (arg_match("anycast")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - rtnl_addr_get_family(addr)); - if (!a) - goto err_invaddr; - rtnl_addr_set_anycast(addr, a); - nl_addr_put(a); - } - } else { - fprintf(stderr, "What is '%s'?\n", argv[idx]); - exit(1); - } - } - - return; - -err_notfound: - fprintf(stderr, "Unknown link %s\n", argv[idx-1]); - exit(1); -err_invscope: - fprintf(stderr, "Invalid scope name \"%s\".\n", argv[idx-1]); - exit(1); -err_invaf: - fprintf(stderr, "Invalid address family \"%s\"\n", argv[idx-1]); - exit(1); -err_invaddr: - fprintf(stderr, "Invalid address \"%s\": %s\n", argv[idx-1], nl_geterror()); - exit(1); -} diff --git a/src/f_ct.c b/src/f_ct.c deleted file mode 100644 index fbb04fc..0000000 --- a/src/f_ct.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * src/f_ct.c Conntrack Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> - * Copyright (c) 2007 Secure Computing Corporation - */ - -static void get_filter(struct nfnl_ct *ct, int argc, char **argv, int idx) -{ - struct nl_addr *a; - - while (argc > idx) { - if (arg_match("family")) { - if (argc > ++idx) { - int family = nl_str2af(argv[idx++]); - if (family == AF_UNSPEC) - goto err_invaf; - nfnl_ct_set_family(ct, family); - } - } else if (arg_match("proto")) { - if (argc > ++idx) { - int proto = nl_str2ip_proto(argv[idx++]); - if (proto < 0) - goto err_invproto; - nfnl_ct_set_proto(ct, proto); - } - } else if (arg_match("tcpstate")) { - if (argc > ++idx) { - int state = nfnl_ct_str2tcp_state(argv[idx++]); - if (state < 0) - goto err_invtcpstate; - nfnl_ct_set_tcp_state(ct, state); - } - } else if (arg_match("status")) { - if (argc > ++idx) { - int status = strtoul(argv[idx++], NULL, 0); - nfnl_ct_set_status(ct, status); - nfnl_ct_unset_status(ct, ~status); - } - } else if (arg_match("timeout")) { - if (argc > ++idx) - nfnl_ct_set_timeout(ct, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("mark")) { - if (argc > ++idx) - nfnl_ct_set_mark(ct, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("use")) { - if (argc > ++idx) - nfnl_ct_set_use(ct, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("id")) { - if (argc > ++idx) - nfnl_ct_set_id(ct, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origsrc")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - nfnl_ct_get_family(ct)); - if (!a) - goto err_invaddr; - nfnl_ct_set_src(ct, 0, a); - nl_addr_put(a); - } - } else if (arg_match("origdst")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - nfnl_ct_get_family(ct)); - if (!a) - goto err_invaddr; - nfnl_ct_set_dst(ct, 0, a); - nl_addr_put(a); - } - } else if (arg_match("origsrcport")) { - if (argc > ++idx) - nfnl_ct_set_src_port(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origdstport")) { - if (argc > ++idx) - nfnl_ct_set_dst_port(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origicmpid")) { - if (argc > ++idx) - nfnl_ct_set_icmp_id(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origicmptype")) { - if (argc > ++idx) - nfnl_ct_set_icmp_type(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origicmpcode")) { - if (argc > ++idx) - nfnl_ct_set_icmp_code(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origpackets")) { - if (argc > ++idx) - nfnl_ct_set_packets(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("origbytes")) { - if (argc > ++idx) - nfnl_ct_set_bytes(ct, 0, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replysrc")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - nfnl_ct_get_family(ct)); - if (!a) - goto err_invaddr; - nfnl_ct_set_src(ct, 1, a); - nl_addr_put(a); - } - } else if (arg_match("replydst")) { - if (argc > ++idx) { - a = nl_addr_parse(argv[idx++], - nfnl_ct_get_family(ct)); - if (!a) - goto err_invaddr; - nfnl_ct_set_dst(ct, 1, a); - nl_addr_put(a); - } - } else if (arg_match("replysrcport")) { - if (argc > ++idx) - nfnl_ct_set_src_port(ct, 1, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replydstport")) { - if (argc > ++idx) - nfnl_ct_set_dst_port(ct, 1, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replyicmpid")) { - if (argc > ++idx) - nfnl_ct_set_icmp_id(ct, 1, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replyicmptype")) { - if (argc > ++idx) - nfnl_ct_set_icmp_type(ct, 1, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replyicmpcode")) { - if (argc > ++idx) - nfnl_ct_set_icmp_code(ct, 1, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replypackets")) { - if (argc > ++idx) - nfnl_ct_set_packets(ct, 1, strtoul(argv[idx++], NULL, 0)); - } else if (arg_match("replybytes")) { - if (argc > ++idx) - nfnl_ct_set_bytes(ct, 1, strtoul(argv[idx++], NULL, 0)); - } -#define MSTATUS(STR, STATUS) \ - else if (!strcasecmp(argv[idx], STR)) { \ - nfnl_ct_set_status(ct, STATUS); idx++; } -#define MNOSTATUS(STR, STATUS) \ - else if (!strcasecmp(argv[idx], STR)) { \ - nfnl_ct_unset_status(ct, STATUS); idx++; } - - MSTATUS("replied", IPS_SEEN_REPLY) - MNOSTATUS("unreplied", IPS_SEEN_REPLY) - MSTATUS("assured", IPS_ASSURED) - MNOSTATUS("unassured", IPS_ASSURED) -#undef MSTATUS -#undef MNOSTATUS - else { - fprintf(stderr, "What is '%s'?\n", argv[idx]); - exit(1); - } - } - - return; - -err_invproto: - fprintf(stderr, "Invalid IP protocol \"%s\".\n", argv[idx-1]); - exit(1); -err_invtcpstate: - fprintf(stderr, "Invalid TCP state \"%s\".\n", argv[idx-1]); - exit(1); -err_invaf: - fprintf(stderr, "Invalid address family \"%s\"\n", argv[idx-1]); - exit(1); -err_invaddr: - fprintf(stderr, "Invalid address \"%s\": %s\n", argv[idx-1], nl_geterror()); - exit(1); -} diff --git a/src/f_link.c b/src/f_link.c deleted file mode 100644 index 3c1cb93..0000000 --- a/src/f_link.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * src/f_link.c Link Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include <linux/if.h> - -static void get_filter(struct rtnl_link *l, int ac, char **av, int idx, - struct nl_cache *cache) -{ - while (ac > idx) { - if (!strcasecmp(av[idx], "dev")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(cache, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_link_set_ifindex(l, ifindex); - } - } else if (!strcasecmp(av[idx], "mtu")) { - if (ac > ++idx) - rtnl_link_set_mtu(l, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "txqlen")) { - if (ac > ++idx) - rtnl_link_set_txqlen(l, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "weight")) { - if (ac > ++idx) - rtnl_link_set_weight(l, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "link")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(cache, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_link_set_link(l, ifindex); - } - } else if (!strcasecmp(av[idx], "master")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(cache, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_link_set_master(l, ifindex); - } - } else if (!strcasecmp(av[idx], "qdisc")) { - if (ac > ++idx) - rtnl_link_set_qdisc(l, av[idx++]); - } else if (!strcasecmp(av[idx], "name")) { - if (ac > ++idx) - rtnl_link_set_name(l, av[idx++]); - } else if (!strcasecmp(av[idx], "addr")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (a == NULL) - goto err; - rtnl_link_set_addr(l, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "broadcast")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (a == NULL) - goto err; - rtnl_link_set_broadcast(l, a); - nl_addr_put(a); - } - } -#define MFLAG(STR, FLAG) \ - else if (!strcasecmp(av[idx], STR)) { \ - rtnl_link_set_flags(l, FLAG); idx++; } -#define MNOFLAG(STR, FLAG) \ - else if (!strcasecmp(av[idx], STR)) { \ - rtnl_link_unset_flags(l, FLAG); idx++; } - - MFLAG("up", IFF_UP) - MNOFLAG("down", IFF_UP) - MFLAG("noarp", IFF_NOARP) - MNOFLAG("arp", IFF_NOARP) - MFLAG("promisc", IFF_PROMISC) - MNOFLAG("nopromisc", IFF_PROMISC) - MFLAG("dynamic", IFF_DYNAMIC) - MNOFLAG("nodynamic", IFF_DYNAMIC) - MFLAG("multicast", IFF_MULTICAST) - MNOFLAG("nomulticast", IFF_MULTICAST) - MFLAG("allmulticast", IFF_ALLMULTI) - MNOFLAG("noallmulticast", IFF_ALLMULTI) -#undef MFLAG -#undef MNOFLAG - else { - fprintf(stderr, "What is '%s'?\n", av[idx]); - exit(1); - } - } - - return; - -err_notfound: - fprintf(stderr, "Unknown link %s\n", av[idx-1]); - exit(1); -err: - fprintf(stderr, "%s\n", nl_geterror()); - exit(1); -} diff --git a/src/f_neigh.c b/src/f_neigh.c deleted file mode 100644 index ac9355c..0000000 --- a/src/f_neigh.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * src/f_neigh.c Neighbour Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -static void get_filter(struct rtnl_neigh *n, int ac, char **av, int idx, - struct nl_cache *cache) -{ - struct nl_cache *lc = nl_cache_mngt_require("route/link"); - - while (ac > idx) { - if (!strcasecmp(av[idx], "dev")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(lc, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_neigh_set_ifindex(n, ifindex); - } - } else if (!strcasecmp(av[idx], "dst")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (a == NULL) - goto err; - rtnl_neigh_set_dst(n, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "lladdr")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (a == NULL) - goto err; - rtnl_neigh_set_lladdr(n, a); - nl_addr_put(a); - } - } - } - - return; -err_notfound: - fprintf(stderr, "Unable to find interface %s\n", av[idx-1]); - exit(1); -err: - fprintf(stderr, "%s\n", nl_geterror()); - exit(1); -} diff --git a/src/f_route.c b/src/f_route.c deleted file mode 100644 index 581ff65..0000000 --- a/src/f_route.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * src/f_route.c Routes Filter - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -static void get_filter(struct rtnl_route *r, int ac, char **av, int idx, - struct nl_cache *cache, struct nl_cache *link_cache) -{ - while (ac > idx) { - if (!strcasecmp(av[idx], "src")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_pref_src(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "dst")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_dst(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "via")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_gateway(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "from")) { - if (ac > ++idx) { - struct nl_addr *a = nl_addr_parse(av[idx++], AF_UNSPEC); - if (!a) - goto err; - rtnl_route_set_src(r, a); - nl_addr_put(a); - } - } else if (!strcasecmp(av[idx], "tos")) { - if (ac > ++idx) - rtnl_route_set_tos(r, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "prio")) { - if (ac > ++idx) - rtnl_route_set_prio(r, strtoul(av[idx++], NULL, 0)); - } else if (!strcasecmp(av[idx], "scope")) { - if (ac > ++idx) - rtnl_route_set_scope(r, rtnl_str2scope(av[idx++])); - } else if (!strcasecmp(av[idx], "dev")) { - if (ac > ++idx) { - int ifindex = rtnl_link_name2i(link_cache, av[idx++]); - if (ifindex == RTNL_LINK_NOT_FOUND) - goto err_notfound; - rtnl_route_set_oif(r, ifindex); - } - } else if (!strcasecmp(av[idx], "table")) { - if (ac > ++idx) - rtnl_route_set_table(r, strtoul(av[idx++], NULL, 0)); - } else { - fprintf(stderr, "What is '%s'?\n", av[idx]); - exit(1); - } - } - - return; - -err_notfound: - fprintf(stderr, "Unable to find device \"%s\"\n", av[idx-1]); - exit(1); -err: - fprintf(stderr, "%s\n", nl_geterror()); - exit(1); -} diff --git a/src/genl-ctrl-dump.c b/src/genl-ctrl-dump.c deleted file mode 100644 index 98a26a1..0000000 --- a/src/genl-ctrl-dump.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * src/genl-ctrl-dump.c Dump Generic Netlink Controller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: genl-ctrl-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats }\n" - " filter := \n"); - exit(1); -} - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *family_cache; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - if (genl_connect(nlh) < 0) { - fprintf(stderr, "Unable to connect generic netlink socket%s\n", - nl_geterror()); - goto errout; - } - - family_cache = nltool_alloc_genl_family_cache(nlh); - if (!family_cache) - goto errout; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout; - - //get_filter(link, argc, argv, 2, link_cache); - nl_cache_dump(family_cache, ¶ms); - nl_cache_free(family_cache); - err = 0; -errout: - nl_close(nlh); - nl_handle_destroy(nlh); - return err; -} diff --git a/src/genl-ctrl-list.c b/src/genl-ctrl-list.c new file mode 100644 index 0000000..e25eb2a --- /dev/null +++ b/src/genl-ctrl-list.c @@ -0,0 +1,69 @@ +/* + * src/genl-ctrl-list.c List Generic Netlink Controller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> + +static struct nl_cache *alloc_genl_family_cache(struct nl_sock *sk) +{ + return nl_cli_alloc_cache(sk, "generic netlink family", + genl_ctrl_alloc_cache); +} + +static void print_usage(void) +{ + printf( + "Usage: genl-ctrl-list [OPTION]...\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *family_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_GENERIC); + family_cache = alloc_genl_family_cache(sock); + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:hv", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + } + } + + nl_cache_dump(family_cache, ¶ms); + + return 0; +} diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..80c217c --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,41 @@ +# -*- Makefile -*- + +AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DPKGLIBDIR=\"$(pkglibdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -rdynamic +AM_LDFLAGS = -L${top_builddir}/lib -ldl + +#nobase_pkglib_LTLIBRARIES = cls/basic.la cls/ematch/cmp.la +#cls_basic_la_LDFLAGS = -module -version-info 2:0:0 +#cls_ematch_cmp_la_LDFLAGS = -module -version-info 2:0:0 + +#cls/ematch_grammar.c: cls/ematch_grammar.l +# $(LEX) --header-file=cls/ematch_grammar.h $(LFLAGS) -o $@ $^ + +#cls/ematch_syntax.c: cls/ematch_syntax.y +# $(YACC) -d $(YFLAGS) -o $@ $^ + +#cls/pktloc_grammar.c: cls/pktloc_grammar.l +# $(LEX) --header-file=cls/pktloc_grammar.h $(LFLAGS) -o $@ $^ + +#cls/pktloc_syntax.c: cls/pktloc_syntax.y +# $(YACC) -d $(YFLAGS) -o $@ $^ + +#CLEANFILES = \ +# cls/ematch_grammar.c cls/ematch_grammar.h \ +# cls/ematch_syntax.c cls/ematch_syntax.h \ +# cls/pktloc_grammar.c cls/pktloc_grammar.h \ +# cls/pktloc_syntax.c cls/pktloc_syntax.h + +lib_LTLIBRARIES = \ + libnl-cli.la + +libnl_cli_la_LDFLAGS = -version-info 2:0:0 + +libnl_cli_la_LIBADD = ${top_builddir}/lib/libnl.la \ + ${top_builddir}/lib/libnl-route.la \ + ${top_builddir}/lib/libnl-nf.la \ + ${top_builddir}/lib/libnl-genl.la + +libnl_cli_la_SOURCES = \ + utils.c addr.c ct.c link.c neigh.c qdisc.c rule.c route.c +# cls/ematch_syntax.c cls/ematch_grammar.c cls/ematch.c +# cls/pktloc_syntax.c cls/pktloc_grammar.c cls/utils.c diff --git a/src/lib/addr.c b/src/lib/addr.c new file mode 100644 index 0000000..a9c137b --- /dev/null +++ b/src/lib/addr.c @@ -0,0 +1,135 @@ +/* + * src/lib/addr.c Address Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_addr Addresses + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/addr.h> + +struct rtnl_addr *nl_cli_addr_alloc(void) +{ + struct rtnl_addr *addr; + + addr = rtnl_addr_alloc(); + if (!addr) + nl_cli_fatal(ENOMEM, "Unable to allocate address object"); + + return addr; +} + +void nl_cli_addr_parse_family(struct rtnl_addr *addr, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) != AF_UNSPEC) + rtnl_addr_set_family(addr, family); +} + +void nl_cli_addr_parse_local(struct rtnl_addr *addr, char *arg) +{ + struct nl_addr *a; + int err; + + a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr)); + if ((err = rtnl_addr_set_local(addr, a)) < 0) + nl_cli_fatal(err, "Unable to set local address: %s", + nl_geterror(err)); + + nl_addr_put(a); +} + +void nl_cli_addr_parse_dev(struct rtnl_addr *addr, struct nl_cache *link_cache, + char *arg) +{ + int ival; + + if (!(ival = rtnl_link_name2i(link_cache, arg))) + nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_addr_set_ifindex(addr, ival); +} + +void nl_cli_addr_parse_label(struct rtnl_addr *addr, char *arg) +{ + int err; + + if ((err = rtnl_addr_set_label(addr, arg)) < 0) + nl_cli_fatal(err, "Unable to set address label: %s", + nl_geterror(err)); +} + +void nl_cli_addr_parse_peer(struct rtnl_addr *addr, char *arg) +{ + struct nl_addr *a; + int err; + + a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr)); + if ((err = rtnl_addr_set_peer(addr, a)) < 0) + nl_cli_fatal(err, "Unable to set peer address: %s", + nl_geterror(err)); + + nl_addr_put(a); +} + +void nl_cli_addr_parse_scope(struct rtnl_addr *addr, char *arg) +{ + int ival; + + if ((ival = rtnl_str2scope(arg)) < 0) + nl_cli_fatal(EINVAL, "Unknown address scope \"%s\"", arg); + + rtnl_addr_set_scope(addr, ival); +} + +void nl_cli_addr_parse_broadcast(struct rtnl_addr *addr, char *arg) +{ + struct nl_addr *a; + int err; + + a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr)); + if ((err = rtnl_addr_set_broadcast(addr, a)) < 0) + nl_cli_fatal(err, "Unable to set broadcast address: %s", + nl_geterror(err)); + + nl_addr_put(a); +} + +static uint32_t parse_lifetime(const char *arg) +{ + uint64_t msecs; + int err; + + if (!strcasecmp(arg, "forever")) + return 0xFFFFFFFFU; + + if ((err = nl_str2msec(arg, &msecs)) < 0) + nl_cli_fatal(err, "Unable to parse time string \"%s\": %s", + arg, nl_geterror(err)); + + return (msecs / 1000); +} + +void nl_cli_addr_parse_preferred(struct rtnl_addr *addr, char *arg) +{ + rtnl_addr_set_preferred_lifetime(addr, parse_lifetime(arg)); +} + +void nl_cli_addr_parse_valid(struct rtnl_addr *addr, char *arg) +{ + rtnl_addr_set_valid_lifetime(addr, parse_lifetime(arg)); +} + +/** @} */ diff --git a/src/lib/ct.c b/src/lib/ct.c new file mode 100644 index 0000000..5bab08f --- /dev/null +++ b/src/lib/ct.c @@ -0,0 +1,162 @@ +/* + * src/lib/ct.c CLI Conntrack Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_ct Connection Tracking + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/ct.h> + +struct nfnl_ct *nl_cli_ct_alloc(void) +{ + struct nfnl_ct *ct; + + ct = nfnl_ct_alloc(); + if (!ct) + nl_cli_fatal(ENOMEM, "Unable to allocate conntrack object"); + + return ct; +} + +struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *sk) +{ + return nl_cli_alloc_cache(sk, "conntrack", nfnl_ct_alloc_cache); +} + +void nl_cli_ct_parse_family(struct nfnl_ct *ct, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) == AF_UNSPEC) + nl_cli_fatal(EINVAL, + "Unable to nl_cli_ct_parse family \"%s\": %s", + arg, nl_geterror(NLE_INVAL)); + + nfnl_ct_set_family(ct, family); +} + +void nl_cli_ct_parse_protocol(struct nfnl_ct *ct, char *arg) +{ + int proto; + + if ((proto = nl_str2ip_proto(arg)) < 0) + nl_cli_fatal(proto, + "Unable to nl_cli_ct_parse protocol \"%s\": %s", + arg, nl_geterror(proto)); + + nfnl_ct_set_proto(ct, proto); +} + +void nl_cli_ct_parse_mark(struct nfnl_ct *ct, char *arg) +{ + uint32_t mark = nl_cli_parse_u32(arg); + nfnl_ct_set_mark(ct, mark); +} + +void nl_cli_ct_parse_timeout(struct nfnl_ct *ct, char *arg) +{ + uint32_t timeout = nl_cli_parse_u32(arg); + nfnl_ct_set_timeout(ct, timeout); +} + +void nl_cli_ct_parse_id(struct nfnl_ct *ct, char *arg) +{ + uint32_t id = nl_cli_parse_u32(arg); + nfnl_ct_set_id(ct, id); +} + +void nl_cli_ct_parse_use(struct nfnl_ct *ct, char *arg) +{ + uint32_t use = nl_cli_parse_u32(arg); + nfnl_ct_set_use(ct, use); +} + +void nl_cli_ct_parse_src(struct nfnl_ct *ct, int reply, char *arg) +{ + int err; + struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_ct_get_family(ct)); + if ((err = nfnl_ct_set_src(ct, reply, a)) < 0) + nl_cli_fatal(err, "Unable to set source address: %s", + nl_geterror(err)); +} + +void nl_cli_ct_parse_dst(struct nfnl_ct *ct, int reply, char *arg) +{ + int err; + struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_ct_get_family(ct)); + if ((err = nfnl_ct_set_dst(ct, reply, a)) < 0) + nl_cli_fatal(err, "Unable to set destination address: %s", + nl_geterror(err)); +} + +void nl_cli_ct_parse_src_port(struct nfnl_ct *ct, int reply, char *arg) +{ + uint32_t port = nl_cli_parse_u32(arg); + nfnl_ct_set_src_port(ct, reply, port); +} + +void nl_cli_ct_parse_dst_port(struct nfnl_ct *ct, int reply, char *arg) +{ + uint32_t port = nl_cli_parse_u32(arg); + nfnl_ct_set_dst_port(ct, reply, port); +} + +void nl_cli_ct_parse_tcp_state(struct nfnl_ct *ct, char *arg) +{ + int state; + + if ((state = nfnl_ct_str2tcp_state(arg)) < 0) + nl_cli_fatal(state, + "Unable to nl_cli_ct_parse tcp state \"%s\": %s", + arg, nl_geterror(state)); + + nfnl_ct_set_tcp_state(ct, state); +} + +void nl_cli_ct_parse_status(struct nfnl_ct *ct, char *arg) +{ + int status; + + if ((status = nfnl_ct_str2status(arg)) < 0) + nl_cli_fatal(status, + "Unable to nl_cli_ct_parse flags \"%s\": %s", + arg, nl_geterror(status)); + + nfnl_ct_set_status(ct, status); +} + +#if 0 + } else if (arg_match("origicmpid")) { + if (argc > ++idx) + nfnl_ct_set_icmp_id(ct, 0, strtoul(argv[idx++], NULL, 0)); + } else if (arg_match("origicmptype")) { + if (argc > ++idx) + nfnl_ct_set_icmp_type(ct, 0, strtoul(argv[idx++], NULL, 0)); + } else if (arg_match("origicmpcode")) { + if (argc > ++idx) + nfnl_ct_set_icmp_code(ct, 0, strtoul(argv[idx++], NULL, 0)); + } else if (arg_match("replyicmpid")) { + if (argc > ++idx) + nfnl_ct_set_icmp_id(ct, 1, strtoul(argv[idx++], NULL, 0)); + } else if (arg_match("replyicmptype")) { + if (argc > ++idx) + nfnl_ct_set_icmp_type(ct, 1, strtoul(argv[idx++], NULL, 0)); + } else if (arg_match("replyicmpcode")) { + if (argc > ++idx) + nfnl_ct_set_icmp_code(ct, 1, strtoul(argv[idx++], NULL, 0)); + } +#endif + +/** @} */ diff --git a/src/lib/link.c b/src/lib/link.c new file mode 100644 index 0000000..c192569 --- /dev/null +++ b/src/lib/link.c @@ -0,0 +1,73 @@ +/* + * src/lib/link.c CLI Link Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_link Links + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> + +struct rtnl_link *nl_cli_link_alloc(void) +{ + struct rtnl_link *link; + + link = rtnl_link_alloc(); + if (!link) + nl_cli_fatal(ENOMEM, "Unable to allocate link object"); + + return link; +} + +void nl_cli_link_parse_family(struct rtnl_link *link, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) == AF_UNSPEC) + nl_cli_fatal(EINVAL, + "Unable to translate address family \"%s\"", arg); + + rtnl_link_set_family(link, family); +} + +void nl_cli_link_parse_name(struct rtnl_link *link, char *arg) +{ + rtnl_link_set_name(link, arg); +} + +void nl_cli_link_parse_mtu(struct rtnl_link *link, char *arg) +{ + uint32_t mtu = nl_cli_parse_u32(arg); + rtnl_link_set_mtu(link, mtu); +} + +void nl_cli_link_parse_ifindex(struct rtnl_link *link, char *arg) +{ + uint32_t index = nl_cli_parse_u32(arg); + rtnl_link_set_ifindex(link, index); +} + +void nl_cli_link_parse_txqlen(struct rtnl_link *link, char *arg) +{ + uint32_t qlen = nl_cli_parse_u32(arg); + rtnl_link_set_txqlen(link, qlen); +} + +void nl_cli_link_parse_weight(struct rtnl_link *link, char *arg) +{ + uint32_t weight = nl_cli_parse_u32(arg); + rtnl_link_set_weight(link, weight); +} + +/** @} */ diff --git a/src/lib/neigh.c b/src/lib/neigh.c new file mode 100644 index 0000000..a814bd8 --- /dev/null +++ b/src/lib/neigh.c @@ -0,0 +1,88 @@ +/* + * src/lib/neigh.c CLI Neighbour Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_neigh Neighbour + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/neigh.h> + +struct rtnl_neigh *nl_cli_neigh_alloc(void) +{ + struct rtnl_neigh *neigh; + + neigh = rtnl_neigh_alloc(); + if (!neigh) + nl_cli_fatal(ENOMEM, "Unable to allocate neighbout object"); + + return neigh; +} + +void nl_cli_neigh_parse_dst(struct rtnl_neigh *neigh, char *arg) +{ + struct nl_addr *a; + int err; + + a = nl_cli_addr_parse(arg, rtnl_neigh_get_family(neigh)); + if ((err = rtnl_neigh_set_dst(neigh, a)) < 0) + nl_cli_fatal(err, "Unable to set local address: %s", + nl_geterror(err)); + + nl_addr_put(a); +} + +void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *neigh, char *arg) +{ + struct nl_addr *a; + + a = nl_cli_addr_parse(arg, AF_UNSPEC); + rtnl_neigh_set_lladdr(neigh, a); + nl_addr_put(a); +} + +void nl_cli_neigh_parse_dev(struct rtnl_neigh *neigh, + struct nl_cache *link_cache, char *arg) +{ + int ival; + + if (!(ival = rtnl_link_name2i(link_cache, arg))) + nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_neigh_set_ifindex(neigh, ival); +} + +void nl_cli_neigh_parse_family(struct rtnl_neigh *neigh, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) == AF_UNSPEC) + nl_cli_fatal(EINVAL, + "Unable to translate address family \"%s\"", arg); + + rtnl_neigh_set_family(neigh, family); +} + +void nl_cli_neigh_parse_state(struct rtnl_neigh *neigh, char *arg) +{ + int state; + + if ((state = rtnl_neigh_str2state(arg)) < 0) + nl_cli_fatal(state, "Unable to translate state \"%s\": %s", + arg, state); + + rtnl_neigh_set_state(neigh, state); +} + +/** @} */ diff --git a/src/lib/qdisc.c b/src/lib/qdisc.c new file mode 100644 index 0000000..bc7ff92 --- /dev/null +++ b/src/lib/qdisc.c @@ -0,0 +1,72 @@ +/* + * src/lib/qdisc.c CLI QDisc Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_qdisc Queueing Disciplines + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/qdisc.h> + +struct rtnl_qdisc *nl_cli_qdisc_alloc(void) +{ + struct rtnl_qdisc *qdisc; + + qdisc = rtnl_qdisc_alloc(); + if (!qdisc) + nl_cli_fatal(ENOMEM, "Unable to allocate qdisc object"); + + return qdisc; +} + +void nl_cli_qdisc_parse_dev(struct rtnl_qdisc *qdisc, struct nl_cache *link_cache, char *arg) +{ + int ival; + + if (!(ival = rtnl_link_name2i(link_cache, arg))) + nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_qdisc_set_ifindex(qdisc, ival); +} + +void nl_cli_qdisc_parse_parent(struct rtnl_qdisc *qdisc, char *arg) +{ + uint32_t parent; + int err; + + if ((err = rtnl_tc_str2handle(arg, &parent)) < 0) + nl_cli_fatal(err, "Unable to parse handle \"%s\": %s", + arg, nl_geterror(err)); + + rtnl_qdisc_set_parent(qdisc, parent); +} + +void nl_cli_qdisc_parse_handle(struct rtnl_qdisc *qdisc, char *arg) +{ + uint32_t handle; + int err; + + if ((err = rtnl_tc_str2handle(arg, &handle)) < 0) + nl_cli_fatal(err, "Unable to parse handle \"%s\": %s", + arg, nl_geterror(err)); + + rtnl_qdisc_set_handle(qdisc, handle); +} + +void nl_cli_qdisc_parse_kind(struct rtnl_qdisc *qdisc, char *arg) +{ + rtnl_qdisc_set_kind(qdisc, arg); +} + +/** @} */ diff --git a/src/lib/route.c b/src/lib/route.c new file mode 100644 index 0000000..05cb2ad --- /dev/null +++ b/src/lib/route.c @@ -0,0 +1,270 @@ +/* + * src/lib/route.c CLI Route Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_route Routing + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/route.h> + +struct rtnl_route *nl_cli_route_alloc(void) +{ + struct rtnl_route *route; + + route = rtnl_route_alloc(); + if (!route) + nl_cli_fatal(ENOMEM, "Unable to allocate route object"); + + return route; +} + +struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *sk, int flags) +{ + struct nl_cache *cache; + int err; + + if ((err = rtnl_route_alloc_cache(sk, AF_UNSPEC, flags, &cache)) < 0) + nl_cli_fatal(err, "Unable to allocate route cache: %s\n", + nl_geterror(err)); + + nl_cache_mngt_provide(cache); + + return cache; +} + +void nl_cli_route_parse_family(struct rtnl_route *route, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) != AF_UNSPEC) + rtnl_route_set_family(route, family); +} + +void nl_cli_route_parse_dst(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route)); + if ((err = rtnl_route_set_dst(route, addr)) < 0) + nl_cli_fatal(err, "Unable to set destination address: %s", + nl_geterror(err)); + + nl_addr_put(addr); +} + +void nl_cli_route_parse_src(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route)); + if ((err = rtnl_route_set_src(route, addr)) < 0) + nl_cli_fatal(err, "Unable to set source address: %s", + nl_geterror(err)); + + nl_addr_put(addr); +} + +void nl_cli_route_parse_pref_src(struct rtnl_route *route, char *arg) +{ + struct nl_addr *addr; + int err; + + addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route)); + if ((err = rtnl_route_set_pref_src(route, addr)) < 0) + nl_cli_fatal(err, "Unable to set preferred source address: %s", + nl_geterror(err)); + + nl_addr_put(addr); +} + +void nl_cli_route_parse_metric(struct rtnl_route *route, char *subopts) +{ + /* strict equal order to RTAX_* */ + static char *const tokens[] = { + "unspec", + "lock", + "mtu", + "window", + "rtt", + "rttvar", + "sstresh", + "cwnd", + "advmss", + "reordering", + "hoplimit", + "initcwnd", + "features", + NULL, + }; + unsigned long lval; + char *arg, *endptr; + + while (*subopts != '\0') { + int ret = getsubopt(&subopts, tokens, &arg); + if (ret == -1) + nl_cli_fatal(EINVAL, "Unknown metric token \"%s\"", arg); + + if (ret == 0) + nl_cli_fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]); + + if (arg == NULL) + nl_cli_fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]); + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + nl_cli_fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]); + + if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0) + nl_cli_fatal(ret, "Unable to set metric: %s", + nl_geterror(ret)); + } +} + +void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts, + struct nl_cache *link_cache) +{ + enum { + NH_DEV, + NH_VIA, + NH_WEIGHT, + }; + static char *const tokens[] = { + "dev", + "via", + "weight", + NULL, + }; + struct rtnl_nexthop *nh; + unsigned long lval; + struct nl_addr *addr; + int ival; + char *arg, *endptr; + + if (!(nh = rtnl_route_nh_alloc())) + nl_cli_fatal(ENOMEM, "Out of memory"); + + while (*subopts != '\0') { + int ret = getsubopt(&subopts, tokens, &arg); + if (ret == -1) + nl_cli_fatal(EINVAL, "Unknown nexthop token \"%s\"", arg); + + if (arg == NULL) + nl_cli_fatal(EINVAL, "Missing argument to option \"%s\"\n", + tokens[ret]); + + switch (ret) { + case NH_DEV: + if (!(ival = rtnl_link_name2i(link_cache, arg))) + nl_cli_fatal(ENOENT,"Link \"%s\" does not exist", arg); + + rtnl_route_nh_set_ifindex(nh, ival); + break; + + case NH_VIA: + addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route)); + rtnl_route_nh_set_gateway(nh, addr); + nl_addr_put(addr); + break; + + case NH_WEIGHT: + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + nl_cli_fatal(EINVAL, + "Invalid weight \"%s\", not numeric", + arg); + rtnl_route_nh_set_weight(nh, lval); + break; + } + } + + rtnl_route_add_nexthop(route, nh); +} + +void nl_cli_route_parse_table(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) { + if ((lval = rtnl_route_str2table(arg)) < 0) + nl_cli_fatal(EINVAL, "Unknown table name \"%s\"", arg); + } + + rtnl_route_set_table(route, lval); +} + +void nl_cli_route_parse_prio(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) + nl_cli_fatal(EINVAL, "Invalid priority value, not numeric"); + rtnl_route_set_priority(route, lval); +} + +void nl_cli_route_parse_scope(struct rtnl_route *route, char *arg) +{ + int ival; + + if ((ival = rtnl_str2scope(arg)) < 0) + nl_cli_fatal(EINVAL, "Unknown routing scope \"%s\"", arg); + + rtnl_route_set_scope(route, ival); +} + +void nl_cli_route_parse_protocol(struct rtnl_route *route, char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg) { + if ((lval = rtnl_route_str2proto(arg)) < 0) + nl_cli_fatal(EINVAL, + "Unknown routing protocol name \"%s\"", + arg); + } + + rtnl_route_set_protocol(route, lval); +} + +void nl_cli_route_parse_type(struct rtnl_route *route, char *arg) +{ + int ival; + + if ((ival = nl_str2rtntype(arg)) < 0) + nl_cli_fatal(EINVAL, "Unknown routing type \"%s\"", arg); + + if ((ival = rtnl_route_set_type(route, ival)) < 0) + nl_cli_fatal(ival, "Unable to set routing type: %s", + nl_geterror(ival)); +} + +void nl_cli_route_parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache) +{ + int ival; + + if (!(ival = rtnl_link_name2i(link_cache, arg))) + nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg); + + rtnl_route_set_iif(route, ival); +} + +/** @} */ diff --git a/src/lib/rule.c b/src/lib/rule.c new file mode 100644 index 0000000..96f1d4c --- /dev/null +++ b/src/lib/rule.c @@ -0,0 +1,55 @@ +/* + * src/lib/rule.c CLI Routing Rule Helpers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @ingroup cli + * @defgroup cli_rule Routing Rules + * + * @{ + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/rule.h> + +struct rtnl_rule *nl_cli_rule_alloc(void) +{ + struct rtnl_rule *rule; + + rule = rtnl_rule_alloc(); + if (!rule) + nl_cli_fatal(ENOMEM, "Unable to allocate rule object"); + + return rule; +} + +struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *sk) +{ + struct nl_cache *cache; + int err; + + if ((err = rtnl_rule_alloc_cache(sk, AF_UNSPEC, &cache)) < 0) + nl_cli_fatal(err, "Unable to allocate routing rule cache: %s\n", + nl_geterror(err)); + + nl_cache_mngt_provide(cache); + + return cache; +} + +void nl_cli_rule_parse_family(struct rtnl_rule *rule, char *arg) +{ + int family; + + if ((family = nl_str2af(arg)) != AF_UNSPEC) + rtnl_rule_set_family(rule, family); +} + +/** @} */ diff --git a/src/lib/utils.c b/src/lib/utils.c new file mode 100644 index 0000000..02a7be1 --- /dev/null +++ b/src/lib/utils.c @@ -0,0 +1,147 @@ +/* + * src/utils.c Utilities + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +/** + * @defgroup cli Command Line Interface API + * + * @{ + */ + +#include <netlink/cli/utils.h> + +uint32_t nl_cli_parse_u32(const char *arg) +{ + unsigned long lval; + char *endptr; + + lval = strtoul(arg, &endptr, 0); + if (endptr == arg || lval == ULONG_MAX) + nl_cli_fatal(EINVAL, "Unable to parse \"%s\", not a number.", + arg); + + return (uint32_t) lval; +} + +void nl_cli_print_version(void) +{ + printf("libnl tools version %s\n", LIBNL_VERSION); + printf( + "Copyright (C) 2003-2009 Thomas Graf <tgraf@redhat.com>\n" + "\n" + "This program comes with ABSOLUTELY NO WARRANTY. This is free \n" + "software, and you are welcome to redistribute it under certain\n" + "conditions. See the GNU General Public License for details.\n" + ); + + exit(0); +} + +void nl_cli_fatal(int err, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "Error: "); + + if (fmt) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + } else + fprintf(stderr, "%s\n", strerror(err)); + + exit(abs(err)); +} + +int nl_cli_connect(struct nl_sock *sk, int protocol) +{ + int err; + + if ((err = nl_connect(sk, protocol)) < 0) + nl_cli_fatal(err, "Unable to connect netlink socket: %s", + nl_geterror(err)); + + return err; +} + +struct nl_sock *nl_cli_alloc_socket(void) +{ + struct nl_sock *sock; + + if (!(sock = nl_socket_alloc())) + nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket"); + + return sock; +} + +struct nl_addr *nl_cli_addr_parse(const char *str, int family) +{ + struct nl_addr *addr; + int err; + + if ((err = nl_addr_parse(str, family, &addr)) < 0) + nl_cli_fatal(err, "Unable to parse address \"%s\": %s", + str, nl_geterror(err)); + + return addr; +} + +int nl_cli_parse_dumptype(const char *str) +{ + if (!strcasecmp(str, "brief")) + return NL_DUMP_LINE; + else if (!strcasecmp(str, "details") || !strcasecmp(str, "detailed")) + return NL_DUMP_DETAILS; + else if (!strcasecmp(str, "stats")) + return NL_DUMP_STATS; + else if (!strcasecmp(str, "env")) + return NL_DUMP_ENV; + else + nl_cli_fatal(EINVAL, "Invalid dump type \"%s\".\n", str); + + return 0; +} + +int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params, + int default_yes) +{ + int answer; + + nl_object_dump(obj, params); + printf("Delete? (%c/%c) ", + default_yes ? 'Y' : 'y', + default_yes ? 'n' : 'N'); + + do { + answer = tolower(getchar()); + if (answer == '\n') + answer = default_yes ? 'y' : 'n'; + } while (answer != 'y' && answer != 'n'); + + return answer == 'y'; +} + +struct nl_cache *nl_cli_alloc_cache(struct nl_sock *sock, const char *name, + int (*ac)(struct nl_sock *, struct nl_cache **)) +{ + struct nl_cache *cache; + int err; + + if ((err = ac(sock, &cache)) < 0) + nl_cli_fatal(err, "Unable to allocate %s cache: %s", + name, nl_geterror(err)); + + nl_cache_mngt_provide(cache); + + return cache; +} + +/** @} */ diff --git a/src/nf-ct-dump.c b/src/nf-ct-dump.c deleted file mode 100644 index 54ee4c7..0000000 --- a/src/nf-ct-dump.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * src/nf-ct-dump.c Dump conntrack attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> - * Copyright (c) 2007 Secure Computing Corporation - */ - -#include "utils.h" -#include <netlink/netfilter/ct.h> -#include <linux/netfilter/nf_conntrack_common.h> - -#include "f_ct.c" - -static void print_usage(void) -{ - printf( - "Usage: nf-ct-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n" - " filter := [family FAMILY] [proto PROTO] [tcpstate TCPSTATE]\n" - " [status STATUS] [timeout TIMEOUT] [mark MARK] [use USE] [id ID]\n" - " [origsrc ADDR] [origdst ADDR] [origsrcport PORT] [origdstport PORT]\n" - " [origicmpid ID] [origicmptype TYPE] [origicmpcode CODE]\n" - " [origpackets PACKETS] [origbytes BYTES]\n" - " [replysrc ADDR] [replydst ADDR] [replysrcport PORT] [replydstport PORT]\n" - " [replyicmpid ID] [replyicmptype TYPE] [replyicmpcode CODE]\n" - " [replypackets PACKETS] [replybytes BYTES]\n" - " [{ replied | unreplied }] [{ assured | unassured }]\n" - ); - exit(1); -} - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *ct_cache; - struct nfnl_ct *ct; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - ct = nfnl_ct_alloc(); - if (!ct) - goto errout; - - if (nltool_connect(nlh, NETLINK_NETFILTER) < 0) - goto errout_free; - - ct_cache = nfnl_ct_alloc_cache(nlh); - if (!ct_cache) { - fprintf(stderr, "Unable to retrieve ct cache: %s\n", - nl_geterror()); - goto errout_close; - } - nl_cache_mngt_provide(ct_cache); - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_ct_cache; - - get_filter(ct, argc, argv, 2); - nl_cache_dump_filter(ct_cache, ¶ms, (struct nl_object *) ct); - - err = 0; - -errout_ct_cache: - nl_cache_free(ct_cache); -errout_close: - nl_close(nlh); -errout_free: - nfnl_ct_put(ct); -errout: - return err; -} diff --git a/src/nf-ct-list.c b/src/nf-ct-list.c new file mode 100644 index 0000000..5f72998 --- /dev/null +++ b/src/nf-ct-list.c @@ -0,0 +1,136 @@ +/* + * src/nf-ct-list.c List Conntrack Entries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> + * Copyright (c) 2007 Secure Computing Corporation + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/ct.h> + +static void print_usage(void) +{ + printf( + "Usage: nf-ct-list [OPTION]... [CONNTRACK ENTRY]\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Conntrack Selection\n" + " -i, --id=NUM Identifier\n" + " -p, --proto=PROTOCOL Protocol\n" + " --tcp-state=STATE TCP connection state\n" + " --orig-src=ADDR Original source address\n" + " --orig-sport=PORT Original source port\n" + " --orig-dst=ADDR Original destination address\n" + " --orig-dport=PORT Original destination port\n" + " --reply-src=ADDR Reply source address\n" + " --reply-sport=PORT Reply source port\n" + " --reply-dst=ADDR Reply destination address\n" + " --reply-dport=PORT Reply destination port\n" + " -F, --family=FAMILY Address family\n" + " --mark=NUM Mark value\n" + " --timeout=NUM Timeout value\n" + " --refcnt=NUM Use counter value\n" + " --flags Flags\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *ct_cache; + struct nfnl_ct *ct; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + ct = nl_cli_ct_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_MARK = 257, + ARG_TCP_STATE = 258, + ARG_ORIG_SRC, + ARG_ORIG_SPORT, + ARG_ORIG_DST, + ARG_ORIG_DPORT, + ARG_REPLY_SRC, + ARG_REPLY_SPORT, + ARG_REPLY_DST, + ARG_REPLY_DPORT, + ARG_TIMEOUT, + ARG_REFCNT, + ARG_FLAGS, + }; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "id", 1, 0, 'i' }, + { "proto", 1, 0, 'p' }, + { "tcp-state", 1, 0, ARG_TCP_STATE }, + { "orig-src", 1, 0, ARG_ORIG_SRC }, + { "orig-sport", 1, 0, ARG_ORIG_SPORT }, + { "orig-dst", 1, 0, ARG_ORIG_DST }, + { "orig-dport", 1, 0, ARG_ORIG_DPORT }, + { "reply-src", 1, 0, ARG_REPLY_SRC }, + { "reply-sport", 1, 0, ARG_REPLY_SPORT }, + { "reply-dst", 1, 0, ARG_REPLY_DST }, + { "reply-dport", 1, 0, ARG_REPLY_DPORT }, + { "family", 1, 0, 'F' }, + { "mark", 1, 0, ARG_MARK }, + { "timeout", 1, 0, ARG_TIMEOUT }, + { "refcnt", 1, 0, ARG_REFCNT }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case '?': exit(NLE_INVAL); + case '4': nfnl_ct_set_family(ct, AF_INET); break; + case '6': nfnl_ct_set_family(ct, AF_INET6); break; + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'i': nl_cli_ct_parse_id(ct, optarg); break; + case 'p': nl_cli_ct_parse_protocol(ct, optarg); break; + case ARG_TCP_STATE: nl_cli_ct_parse_tcp_state(ct, optarg); break; + case ARG_ORIG_SRC: nl_cli_ct_parse_src(ct, 0, optarg); break; + case ARG_ORIG_SPORT: nl_cli_ct_parse_src_port(ct, 0, optarg); break; + case ARG_ORIG_DST: nl_cli_ct_parse_dst(ct, 0, optarg); break; + case ARG_ORIG_DPORT: nl_cli_ct_parse_dst_port(ct, 0, optarg); break; + case ARG_REPLY_SRC: nl_cli_ct_parse_src(ct, 1, optarg); break; + case ARG_REPLY_SPORT: nl_cli_ct_parse_src_port(ct, 1, optarg); break; + case ARG_REPLY_DST: nl_cli_ct_parse_dst(ct, 1, optarg); break; + case ARG_REPLY_DPORT: nl_cli_ct_parse_dst_port(ct, 1, optarg); break; + case 'F': nl_cli_ct_parse_family(ct, optarg); break; + case ARG_MARK: nl_cli_ct_parse_mark(ct, optarg); break; + case ARG_TIMEOUT: nl_cli_ct_parse_timeout(ct, optarg); break; + case ARG_REFCNT: nl_cli_ct_parse_use(ct, optarg); break; + case ARG_FLAGS: nl_cli_ct_parse_status(ct, optarg); break; + } + } + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_NETFILTER); + ct_cache = nl_cli_ct_alloc_cache(sock); + + nl_cache_dump_filter(ct_cache, ¶ms, OBJ_CAST(ct)); + + return 0; +} diff --git a/src/nf-log.c b/src/nf-log.c index 2c100f8..26bae6d 100644 --- a/src/nf-log.c +++ b/src/nf-log.c @@ -6,18 +6,28 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ -#include <sys/types.h> +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> #include <linux/netfilter/nfnetlink_log.h> - -#include "utils.h" #include <netlink/netfilter/nfnl.h> #include <netlink/netfilter/log.h> +static struct nfnl_log *alloc_log(void) +{ + struct nfnl_log *log; + + log = nfnl_log_alloc(); + if (!log) + nl_cli_fatal(ENOMEM, "Unable to allocate log object"); + + return log; +} + static void obj_input(struct nl_object *obj, void *arg) { struct nl_dump_params dp = { @@ -40,74 +50,73 @@ static int event_input(struct nl_msg *msg, void *arg) int main(int argc, char *argv[]) { - struct nl_handle *nfnlh; - struct nl_handle *rtnlh; + struct nl_sock *nf_sock; + struct nl_sock *rt_sock; struct nl_cache *link_cache; - int err = 1; - int family, group; + struct nfnl_log *log; + enum nfnl_log_copy_mode copy_mode; + uint32_t copy_range; + int err; + int family; - if (nltool_init(argc, argv) < 0) - return -1; - - nfnlh = nltool_alloc_handle(); - if (nfnlh == NULL) - return -1; - - nl_disable_sequence_check(nfnlh); - - nl_socket_modify_cb(nfnlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + nf_sock = nl_cli_alloc_socket(); + nl_socket_disable_seq_check(nf_sock); + nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) { - printf("Usage: nf-log family group\n"); + printf("Usage: nf-log family group [ copy_mode ] " + "[copy_range] \n"); return 2; } - if (nfnl_connect(nfnlh) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } + nl_cli_connect(nf_sock, NETLINK_NETFILTER); family = nl_str2af(argv[1]); - if (family == AF_UNSPEC) { - fprintf(stderr, "Unknown family: %s\n", argv[1]); - goto errout; - } - if (nfnl_log_pf_unbind(nfnlh, family) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; + if (family == AF_UNSPEC) + nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\": %s", + argv[1], nl_geterror(family)); + + nfnl_log_pf_unbind(nf_sock, family); + if ((err = nfnl_log_pf_bind(nf_sock, family)) < 0) + nl_cli_fatal(err, "Unable to bind logger: %s", + nl_geterror(err)); + + log = alloc_log(); + nfnl_log_set_group(log, atoi(argv[2])); + + copy_mode = NFNL_LOG_COPY_META; + if (argc > 3) { + copy_mode = nfnl_log_str2copy_mode(argv[3]); + if (copy_mode < 0) + nl_cli_fatal(copy_mode, + "Unable to parse copy mode \"%s\": %s", + argv[3], nl_geterror(copy_mode)); } - if (nfnl_log_pf_bind(nfnlh, family) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } - - group = nl_str2af(argv[2]); - if (nfnl_log_bind(nfnlh, group) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } - - if (nfnl_log_set_mode(nfnlh, 0, NFULNL_COPY_PACKET, 0xffff) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } - - rtnlh = nltool_alloc_handle(); - if (rtnlh == NULL) { - goto errout_close; - } - - if (nl_connect(rtnlh, NETLINK_ROUTE) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } - - if ((link_cache = rtnl_link_alloc_cache(rtnlh)) == NULL) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_close; + nfnl_log_set_copy_mode(log, copy_mode); + + copy_range = 0xFFFF; + if (argc > 4) + copy_mode = atoi(argv[4]); + nfnl_log_set_copy_range(log, copy_range); + + if ((err = nfnl_log_create(nf_sock, log)) < 0) + nl_cli_fatal(err, "Unable to bind instance: %s", + nl_geterror(err)); + + { + struct nl_dump_params dp = { + .dp_type = NL_DUMP_STATS, + .dp_fd = stdout, + .dp_dump_msgtype = 1, + }; + + printf("log params: "); + nl_object_dump((struct nl_object *) log, &dp); } - nl_cache_mngt_provide(link_cache); + rt_sock = nl_cli_alloc_socket(); + nl_cli_connect(rt_sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(rt_sock); while (1) { fd_set rfds; @@ -115,28 +124,24 @@ int main(int argc, char *argv[]) FD_ZERO(&rfds); - maxfd = nffd = nl_socket_get_fd(nfnlh); + maxfd = nffd = nl_socket_get_fd(nf_sock); FD_SET(nffd, &rfds); - rtfd = nl_socket_get_fd(rtnlh); + rtfd = nl_socket_get_fd(rt_sock); FD_SET(rtfd, &rfds); if (maxfd < rtfd) maxfd = rtfd; - /* wait for an incoming message on the netlink socket */ + /* wait for an incoming message on the netlink nf_socket */ retval = select(maxfd+1, &rfds, NULL, NULL, NULL); if (retval) { if (FD_ISSET(nffd, &rfds)) - nl_recvmsgs_default(nfnlh); + nl_recvmsgs_default(nf_sock); if (FD_ISSET(rtfd, &rfds)) - nl_recvmsgs_default(rtnlh); + nl_recvmsgs_default(rt_sock); } } - nl_close(rtnlh); -errout_close: - nl_close(nfnlh); -errout: - return err; + return 0; } diff --git a/src/nf-monitor.c b/src/nf-monitor.c index 2bc58c9..fe99af4 100644 --- a/src/nf-monitor.c +++ b/src/nf-monitor.c @@ -6,12 +6,12 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> * Copyright (c) 2007 Secure Computing Corporation */ -#include "utils.h" +#include <netlink/cli/utils.h> #include <netlink/netfilter/nfnl.h> static void obj_input(struct nl_object *obj, void *arg) @@ -36,67 +36,59 @@ static int event_input(struct nl_msg *msg, void *arg) int main(int argc, char *argv[]) { - struct nl_handle *nlh; - int err = 1; + struct nl_sock *sock; + int err; int i, idx; static const struct { enum nfnetlink_groups gr_id; const char* gr_name; - } known_groups[] = { + } groups[] = { { NFNLGRP_CONNTRACK_NEW, "ct-new" }, { NFNLGRP_CONNTRACK_UPDATE, "ct-update" }, { NFNLGRP_CONNTRACK_DESTROY, "ct-destroy" }, { NFNLGRP_NONE, NULL } }; - if (nltool_init(argc, argv) < 0) - return -1; - - nlh = nltool_alloc_handle(); - if (nlh == NULL) - return -1; - - nl_disable_sequence_check(nlh); - - nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + sock = nl_cli_alloc_socket(); + nl_socket_disable_seq_check(sock); + nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); if (argc > 1 && !strcasecmp(argv[1], "-h")) { printf("Usage: nf-monitor [<groups>]\n"); printf("Known groups:"); - for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++) - printf(" %s", known_groups[i].gr_name); + for (i = 0; groups[i].gr_id != NFNLGRP_NONE; i++) + printf(" %s", groups[i].gr_name); printf("\n"); return 2; } - if (nfnl_connect(nlh) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } + nl_cli_connect(sock, NETLINK_NETFILTER); for (idx = 1; argc > idx; idx++) { - for (i = 0; known_groups[i].gr_id != NFNLGRP_NONE; i++) { - if (!strcmp(argv[idx], known_groups[i].gr_name)) { - - if (nl_socket_add_membership(nlh, known_groups[i].gr_id) < 0) { - fprintf(stderr, "%s: %s\n", argv[idx], nl_geterror()); - goto errout; - } - - break; - } + for (i = 0; groups[i].gr_id != NFNLGRP_NONE; i++) { + if (strcmp(argv[idx], groups[i].gr_name)) + continue; + + err = nl_socket_add_membership(sock, groups[i].gr_id); + if (err < 0) + nl_cli_fatal(err, + "Unable to add membership: %s", + nl_geterror(err)); + break; } - if (known_groups[i].gr_id == NFNLGRP_NONE) - fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]); + + if (groups[i].gr_id == NFNLGRP_NONE) + nl_cli_fatal(NLE_OBJ_NOTFOUND, "Unknown group: \"%s\"", + argv[idx]); } while (1) { fd_set rfds; int fd, retval; - fd = nl_socket_get_fd(nlh); + fd = nl_socket_get_fd(sock); FD_ZERO(&rfds); FD_SET(fd, &rfds); @@ -105,11 +97,9 @@ int main(int argc, char *argv[]) if (retval) { /* FD_ISSET(fd, &rfds) will be true */ - nl_recvmsgs_default(nlh); + nl_recvmsgs_default(sock); } } - nl_close(nlh); -errout: - return err; + return 0; } diff --git a/src/nf-queue.c b/src/nf-queue.c new file mode 100644 index 0000000..3fb3c11 --- /dev/null +++ b/src/nf-queue.c @@ -0,0 +1,172 @@ +/* + * src/nf-queue.c Monitor netfilter queue events + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> + * Copyright (c) 2010 Karl Hiramoto <karl@hiramoto.org> + */ + + +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> +#include <linux/netfilter.h> +#include <linux/netfilter/nfnetlink_queue.h> +#include <netlink/netfilter/nfnl.h> +#include <netlink/netfilter/queue.h> +#include <netlink/netfilter/queue_msg.h> + +static struct nl_sock *nf_sock; + +static struct nfnl_queue *alloc_queue(void) +{ + struct nfnl_queue *queue; + + queue = nfnl_queue_alloc(); + if (!queue) + nl_cli_fatal(ENOMEM, "Unable to allocate queue object"); + + return queue; +} + + +static void obj_input(struct nl_object *obj, void *arg) +{ + struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj; + struct nl_dump_params dp = { + .dp_type = NL_DUMP_STATS, + .dp_fd = stdout, + .dp_dump_msgtype = 1, + }; + uint32_t packet_id = nfnl_queue_msg_get_packetid(msg); + static uint32_t next_packet_id = 0; + struct nfnl_queue_msg *lost_msg = NULL; + uint8_t family; + uint16_t group; + + if (packet_id > next_packet_id) { + printf("Warning: %d Out of order packets. Queue or socket overload \n", packet_id - next_packet_id); + group = nfnl_queue_msg_get_group(msg); + family = nfnl_queue_msg_get_family(msg); + lost_msg = nfnl_queue_msg_alloc(); + + do { + nfnl_queue_msg_set_group(lost_msg, group); + nfnl_queue_msg_set_family(lost_msg, family); + nfnl_queue_msg_set_packetid(lost_msg, next_packet_id); + nfnl_queue_msg_set_verdict(lost_msg, NF_ACCEPT); + nfnl_queue_msg_send_verdict(nf_sock, lost_msg); + next_packet_id++; + } while (packet_id > next_packet_id); + + nfnl_queue_msg_put(lost_msg); + } + + next_packet_id = packet_id + 1; + nfnl_queue_msg_set_verdict(msg, NF_ACCEPT); + nl_object_dump(obj, &dp); + nfnl_queue_msg_send_verdict(nf_sock, msg); +} + +static int event_input(struct nl_msg *msg, void *arg) +{ + if (nl_msg_parse(msg, &obj_input, NULL) < 0) + fprintf(stderr, "<<EVENT>> Unknown message type\n"); + + /* Exit nl_recvmsgs_def() and return to the main select() */ + return NL_STOP; +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *rt_sock; + struct nl_cache *link_cache; + struct nfnl_queue *queue; + enum nfnl_queue_copy_mode copy_mode; + uint32_t copy_range; + int err = 1; + int family; + + nf_sock = nfnl_queue_socket_alloc(); + if (nf_sock == NULL) + nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket"); + + nl_socket_disable_seq_check(nf_sock); + nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + + if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) { + printf("Usage: nf-queue family group [ copy_mode ] " + "[ copy_range ]\n"); + printf("family: [ inet | inet6 | ... ] \n"); + printf("group: the --queue-num arg that you gave to iptables\n"); + printf("copy_mode: [ none | meta | packet ] \n"); + return 2; + } + + nl_cli_connect(nf_sock, NETLINK_NETFILTER); + + if ((family = nl_str2af(argv[1])) == AF_UNSPEC) + nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\"", argv[1]); + + nfnl_queue_pf_unbind(nf_sock, family); + if ((err = nfnl_queue_pf_bind(nf_sock, family)) < 0) + nl_cli_fatal(err, "Unable to bind logger: %s", + nl_geterror(err)); + + queue = alloc_queue(); + nfnl_queue_set_group(queue, atoi(argv[2])); + + copy_mode = NFNL_QUEUE_COPY_PACKET; + if (argc > 3) { + copy_mode = nfnl_queue_str2copy_mode(argv[3]); + if (copy_mode < 0) + nl_cli_fatal(copy_mode, + "Unable to parse copy mode \"%s\": %s", + argv[3], nl_geterror(copy_mode)); + } + nfnl_queue_set_copy_mode(queue, copy_mode); + + copy_range = 0xFFFF; + if (argc > 4) + copy_range = atoi(argv[4]); + nfnl_queue_set_copy_range(queue, copy_range); + + if ((err = nfnl_queue_create(nf_sock, queue)) < 0) + nl_cli_fatal(err, "Unable to bind queue: %s", nl_geterror(err)); + + rt_sock = nl_cli_alloc_socket(); + nl_cli_connect(rt_sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(rt_sock); + + nl_socket_set_buffer_size(nf_sock, 1024*127, 1024*127); + + while (1) { + fd_set rfds; + int nffd, rtfd, maxfd, retval; + + FD_ZERO(&rfds); + + maxfd = nffd = nl_socket_get_fd(nf_sock); + FD_SET(nffd, &rfds); + + rtfd = nl_socket_get_fd(rt_sock); + FD_SET(rtfd, &rfds); + if (maxfd < rtfd) + maxfd = rtfd; + + /* wait for an incoming message on the netlink socket */ + retval = select(maxfd+1, &rfds, NULL, NULL, NULL); + + if (retval) { + if (FD_ISSET(nffd, &rfds)) + nl_recvmsgs_default(nf_sock); + if (FD_ISSET(rtfd, &rfds)) + nl_recvmsgs_default(rt_sock); + } + } + + return 0; +} diff --git a/src/nl-addr-add.c b/src/nl-addr-add.c index de5ddcd..52995ec 100644 --- a/src/nl-addr-add.c +++ b/src/nl-addr-add.c @@ -2,67 +2,119 @@ * src/nl-addr-add.c Add addresses * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/addr.h> +#include <netlink/cli/link.h> -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct rtnl_addr *addr; - struct nl_addr *local; - int err = 1; - - if (argc < 3 || !strcmp(argv[1], "-h")) { - printf("Usage: nl-addr-add <addr> <ifindex>\n"); - goto errout; - } - - if (nltool_init(argc, argv) < 0) - goto errout; - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; +static int quiet = 0; - addr = rtnl_addr_alloc(); - if (!addr) - goto errout_free_handle; +static void print_usage(void) +{ + printf( +"Usage: nl-addr-add [OPTION]... [ADDRESS]\n" +"\n" +"Options\n" +" --replace Replace the address if it exists.\n" +" -q, --quiet Do not print informal notifications.\n" +" -h, --help Show this help.\n" +" -v, --version Show versioning information.\n" +"\n" +"Address Options\n" +" -a, --local=ADDR Address to be considered local.\n" +" -d, --dev=DEV Device the address should be assigned to.\n" +" --family=FAMILY Address family (normally autodetected).\n" +" --broadcast=ADDR Broadcast address of network (IPv4).\n" +" --peer=ADDR Peer address (IPv4).\n" +" --label=STRING Additional address label (IPv4).\n" +" --scope=SCOPE Scope of local address (IPv4).\n" +" --preferred=TIME Preferred lifetime (IPv6).\n" +" --valid=TIME Valid lifetime (IPv6).\n" + ); - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free_addr; + exit(0); +} - local = nltool_addr_parse(argv[1]); - if (!local) - goto errout_close; +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_addr *addr; + struct nl_cache *link_cache; + struct nl_dump_params dp = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err, nlflags = NLM_F_CREATE; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + addr = nl_cli_addr_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_LABEL = 258, + ARG_PEER, + ARG_SCOPE, + ARG_BROADCAST, + ARG_REPLACE, + ARG_PREFERRED, + ARG_VALID, + }; + static struct option long_opts[] = { + { "replace", 0, 0, ARG_REPLACE }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "local", 1, 0, 'a' }, + { "dev", 1, 0, 'd' }, + { "family", 1, 0, ARG_FAMILY }, + { "label", 1, 0, ARG_LABEL }, + { "peer", 1, 0, ARG_PEER }, + { "scope", 1, 0, ARG_SCOPE }, + { "broadcast", 1, 0, ARG_BROADCAST }, + { "preferred", 1, 0, ARG_PREFERRED }, + { "valid", 1, 0, ARG_VALID }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhva:d:", long_opts, &optidx); + if (c == -1) + break; - if (rtnl_addr_set_local(addr, local) < 0) { - fprintf(stderr, "Unable to set local address: %s\n", - nl_geterror()); - goto errout_put_addr; - } + switch (c) { + case '?': exit(NLE_INVAL); + case ARG_REPLACE: nlflags |= NLM_F_REPLACE; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'a': nl_cli_addr_parse_local(addr, optarg); break; + case 'd': nl_cli_addr_parse_dev(addr, link_cache, optarg); break; + case ARG_FAMILY: nl_cli_addr_parse_family(addr, optarg); break; + case ARG_LABEL: nl_cli_addr_parse_label(addr, optarg); break; + case ARG_PEER: nl_cli_addr_parse_peer(addr, optarg); break; + case ARG_SCOPE: nl_cli_addr_parse_scope(addr, optarg); break; + case ARG_BROADCAST: nl_cli_addr_parse_broadcast(addr, optarg); break; + case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break; + case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break; + } + } - rtnl_addr_set_ifindex(addr, strtoul(argv[2], NULL, 0)); + if ((err = rtnl_addr_add(sock, addr, nlflags)) < 0) + nl_cli_fatal(err, "Unable to add address: %s", + nl_geterror(err)); - if (rtnl_addr_add(nlh, addr, 0) < 0) { - fprintf(stderr, "Unable to add address: %s\n", nl_geterror()); - goto errout_close; - } + if (!quiet) { + printf("Added "); + nl_object_dump(OBJ_CAST(addr), &dp); + } - err = 0; -errout_put_addr: - nl_addr_put(local); -errout_close: - nl_close(nlh); -errout_free_addr: - rtnl_addr_put(addr); -errout_free_handle: - nl_handle_destroy(nlh); -errout: - return err; + return 0; } diff --git a/src/nl-addr-delete.c b/src/nl-addr-delete.c index 19ee6c5..2849c01 100644 --- a/src/nl-addr-delete.c +++ b/src/nl-addr-delete.c @@ -2,69 +2,139 @@ * src/nl-addr-delete.c Delete addresses * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/addr.h> +#include <netlink/cli/link.h> -int main(int argc, char *argv[]) +static struct nl_sock *sock; +static int interactive = 0, default_yes = 0, quiet = 0; +static int deleted = 0; + +static void print_usage(void) { - struct nl_handle *nlh; - struct rtnl_addr *addr; - struct nl_addr *local; - int err = 1; + printf( +"Usage: nl-addr-delete [OPTION]... [ADDRESS]\n" +"\n" +"Options\n" +" -i, --interactive Run interactively.\n" +" --yes Set default answer to yes.\n" +" -q, --quiet Do not print informal notifications.\n" +" -h, --help Show this help.\n" +" -v, --version Show versioning information.\n" +"\n" +"Address Options\n" +" -a, --local=ADDR Local address.\n" +" -d, --dev=DEV Associated network device.\n" +" --family=FAMILY Family of local address.\n" +" --label=STRING Address label (IPv4).\n" +" --peer=ADDR Peer address (IPv4).\n" +" --scope=SCOPE Address scope (IPv4).\n" +" --broadcast=ADDR Broadcast address of network (IPv4).\n" +" --valid-lifetime=TS Valid lifetime before route expires (IPv6).\n" +" --preferred=TIME Preferred lifetime (IPv6).\n" +" --valid=TIME Valid lifetime (IPv6).\n" + ); - if (argc < 3 || !strcmp(argv[1], "-h")) { - printf("Usage: nl-addr-delete <addr> <ifindex>\n"); - goto errout; - } + exit(0); +} + +static void delete_cb(struct nl_object *obj, void *arg) +{ + struct rtnl_addr *addr = nl_object_priv(obj); + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + if (interactive && !nl_cli_confirm(obj, ¶ms, default_yes)) + return; - if (nltool_init(argc, argv) < 0) - goto errout; + if ((err = rtnl_addr_delete(sock, addr, 0)) < 0) + nl_cli_fatal(err, "Unable to delete address: %s\n", + nl_geterror(err)); - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; + if (!quiet) { + printf("Deleted "); + nl_object_dump(obj, ¶ms); + } + + deleted++; +} - addr = rtnl_addr_alloc(); - if (!addr) - goto errout_free_handle; +int main(int argc, char *argv[]) +{ + struct rtnl_addr *addr; + struct nl_cache *link_cache, *addr_cache; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free_addr; + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + addr_cache = nl_cli_addr_alloc_cache(sock); + addr = nl_cli_addr_alloc(); - local = nltool_addr_parse(argv[1]); - if (!local) - goto errout_close; + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_LABEL = 258, + ARG_YES, + ARG_PEER, + ARG_SCOPE, + ARG_BROADCAST, + ARG_PREFERRED, + ARG_VALID, + }; + static struct option long_opts[] = { + { "interactive", 0, 0, 'i' }, + { "yes", 0, 0, ARG_YES }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "local", 1, 0, 'a' }, + { "dev", 1, 0, 'd' }, + { "family", 1, 0, ARG_FAMILY }, + { "label", 1, 0, ARG_LABEL }, + { "peer", 1, 0, ARG_PEER }, + { "scope", 1, 0, ARG_SCOPE }, + { "broadcast", 1, 0, ARG_BROADCAST }, + { "preferred", 1, 0, ARG_PREFERRED }, + { "valid", 1, 0, ARG_VALID }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "iqhva:d:", long_opts, &optidx); + if (c == -1) + break; - if (rtnl_addr_set_local(addr, local) < 0) { - fprintf(stderr, "Unable to set local address: %s\n", - nl_geterror()); - goto errout_addr_put; - } + switch (c) { + case 'i': interactive = 1; break; + case ARG_YES: default_yes = 1; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'a': nl_cli_addr_parse_local(addr, optarg); break; + case 'd': nl_cli_addr_parse_dev(addr, link_cache, optarg); break; + case ARG_FAMILY: nl_cli_addr_parse_family(addr, optarg); break; + case ARG_LABEL: nl_cli_addr_parse_label(addr, optarg); break; + case ARG_PEER: nl_cli_addr_parse_peer(addr, optarg); break; + case ARG_SCOPE: nl_cli_addr_parse_scope(addr, optarg); break; + case ARG_BROADCAST: nl_cli_addr_parse_broadcast(addr, optarg); break; + case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break; + case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break; + } + } - rtnl_addr_set_ifindex(addr, strtoul(argv[2], NULL, 0)); + nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), delete_cb, NULL); - if (rtnl_addr_delete(nlh, addr, 0) < 0) { - fprintf(stderr, "Unable to delete address: %s\n", - nl_geterror()); - goto errout_addr_put; - } + if (!quiet) + printf("Deleted %d addresses\n", deleted); - err = 0; - -errout_addr_put: - nl_addr_put(local); -errout_close: - nl_close(nlh); -errout_free_addr: - rtnl_addr_put(addr); -errout_free_handle: - nl_handle_destroy(nlh); -errout: - return err; + return 0; } diff --git a/src/nl-addr-dump.c b/src/nl-addr-dump.c deleted file mode 100644 index 5dcd53b..0000000 --- a/src/nl-addr-dump.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * src/nl-addr-dump.c Dump address attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-addr-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n" - " filter := [dev DEV] [label LABEL] [family FAMILY] [scope SCOPE]\n" - " [local ADDR] [peer ADDR] [broadcast ADDR] [anycast ADDR]\n" - " [multicast ADDR]\n"); - exit(1); -} - -#include "f_addr.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *addr_cache; - struct rtnl_addr *addr; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - addr = rtnl_addr_alloc(); - if (!addr) - goto errout; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - addr_cache = nltool_alloc_addr_cache(nlh); - if (!addr_cache) - goto errout_link_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_addr_cache; - get_filter(addr, argc, argv, 2, link_cache); - - nl_cache_dump_filter(addr_cache, ¶ms, (struct nl_object *) addr); - - err = 0; - -errout_addr_cache: - nl_cache_free(addr_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_addr_put(addr); -errout: - return err; -} diff --git a/src/nl-addr-list.c b/src/nl-addr-list.c new file mode 100644 index 0000000..9b045a5 --- /dev/null +++ b/src/nl-addr-list.c @@ -0,0 +1,193 @@ +/* + * src/nl-addr-list.c List addresses + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/addr.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf( +"Usage: nl-addr-list [OPTION]... [ADDRESS]\n" +"\n" +"Options\n" +" --details Show details on multiple lines.\n" +" --env Print address details in sh env variable syntax.\n" +" --prefix=STRING Prefix each printed line.\n" +" -h, --help Show this help.\n" +" -v, --version Show versioning information.\n" +"\n" +"Address Selection\n" +" -a, --local=ADDR Local address.\n" +" -d, --dev=DEV Associated network device.\n" +" --family=FAMILY Family of local address.\n" +" --label=STRING Address label (IPv4).\n" +" --peer=ADDR Peer address (IPv4).\n" +" --scope=SCOPE Address scope (IPv4).\n" +" --broadcast=ADDR Broadcast address of network (IPv4).\n" +" --valid-lifetime=TS Valid lifetime before route expires (IPv6).\n" +" --preferred=TIME Preferred lifetime (IPv6).\n" +" --valid=TIME Valid lifetime (IPv6).\n" + ); + exit(0); +} + +static char *prefix; + +void print_prefix(struct nl_dump_params *p, int line) +{ + if (prefix) + nl_dump(p, "%s", prefix); +} + +static void env_dump(struct nl_object *obj, void *arg) +{ + struct nl_dump_params *p = arg; + struct rtnl_addr *addr = (struct rtnl_addr *) obj; + struct nl_cache *link_cache; + struct nl_addr *a; + static int index = 0; + char buf[128], pfx[32], *s; + + snprintf(pfx, sizeof(pfx), "ADDR%d", index++); + + nl_dump_line(p, "%s_FAMILY=%s\n", pfx, + nl_af2str(rtnl_addr_get_family(addr), buf, sizeof(buf))); + + nl_dump_line(p, "%s_LOCAL=%s\n", pfx, + nl_addr2str(rtnl_addr_get_local(addr), buf, sizeof(buf))); + + nl_dump_line(p, "%s_IFINDEX=%u\n", pfx, rtnl_addr_get_ifindex(addr)); + link_cache = nl_cache_mngt_require("route/link"); + if (link_cache) + nl_dump_line(p, "%s_IFNAME=%s\n", pfx, + rtnl_link_i2name(link_cache, + rtnl_addr_get_ifindex(addr), + buf, sizeof(buf))); + + if ((a = rtnl_addr_get_peer(addr))) + nl_dump_line(p, "%s_PEER=%s\n", pfx, + nl_addr2str(a, buf, sizeof(buf))); + + if ((a = rtnl_addr_get_broadcast(addr))) + nl_dump_line(p, "%s_BROADCAST=%s\n", pfx, + nl_addr2str(a, buf, sizeof(buf))); + + nl_dump_line(p, "%s_SCOPE=%s\n", pfx, + rtnl_scope2str(rtnl_addr_get_scope(addr), + buf, sizeof(buf))); + + if ((s = rtnl_addr_get_label(addr))) + nl_dump_line(p, "%s_LABEL=%s\n", pfx, s); + + rtnl_addr_flags2str(rtnl_addr_get_flags(addr), buf, sizeof(buf)); + if (buf[0]) + nl_dump_line(p, "%s_FLAGS=%s\n", pfx, buf); + + nl_dump_line(p, "%s_CACHEINFO_VALID=%u\n", pfx, + rtnl_addr_get_valid_lifetime(addr)); + +#if 0 + if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { + struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; + + nl_dump_line(p, "ADDR_CACHEINFO_PREFERRED=%u\n", + ci->aci_prefered); + + nl_dump_line(p, "ADDR_CACHEINFO_CREATED=%u\n", ci->aci_cstamp); + nl_dump_line(p, "ADDR_CACHEINFO_LASTUPDATE=%u\n", + ci->aci_tstamp); + } +#endif +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_addr *addr; + struct nl_cache *link_cache, *addr_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_nl_cb = print_prefix, + .dp_fd = stdout, + }; + int dump_env = 0; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + addr_cache = nl_cli_addr_alloc_cache(sock); + addr = nl_cli_addr_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_LABEL = 258, + ARG_PEER, + ARG_SCOPE, + ARG_BROADCAST, + ARG_DETAILS, + ARG_ENV, + ARG_PREFIX, + ARG_PREFERRED, + ARG_VALID, + }; + static struct option long_opts[] = { + { "details", 0, 0, ARG_DETAILS }, + { "env", 0, 0, ARG_ENV }, + { "prefix", 1, 0, ARG_PREFIX }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "local", 1, 0, 'a' }, + { "dev", 1, 0, 'd' }, + { "family", 1, 0, ARG_FAMILY }, + { "label", 1, 0, ARG_LABEL }, + { "peer", 1, 0, ARG_PEER }, + { "scope", 1, 0, ARG_SCOPE }, + { "broadcast", 1, 0, ARG_BROADCAST }, + { "preferred", 1, 0, ARG_PREFERRED }, + { "valid", 1, 0, ARG_VALID }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "46hva:d:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case '?': exit(NLE_INVAL); + case '4': rtnl_addr_set_family(addr, AF_INET); break; + case '6': rtnl_addr_set_family(addr, AF_INET6); break; + case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break; + case ARG_ENV: dump_env = 1; break; + case ARG_PREFIX: prefix = strdup(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'a': nl_cli_addr_parse_local(addr, optarg); break; + case 'd': nl_cli_addr_parse_dev(addr, link_cache, optarg); break; + case ARG_FAMILY: nl_cli_addr_parse_family(addr, optarg); break; + case ARG_LABEL: nl_cli_addr_parse_label(addr, optarg); break; + case ARG_PEER: nl_cli_addr_parse_peer(addr, optarg); break; + case ARG_SCOPE: nl_cli_addr_parse_scope(addr, optarg); break; + case ARG_BROADCAST: nl_cli_addr_parse_broadcast(addr, optarg); break; + case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break; + case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break; + } + } + + if (dump_env) + nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), env_dump, + ¶ms); + else + nl_cache_dump_filter(addr_cache, ¶ms, OBJ_CAST(addr)); + + return 0; +} diff --git a/src/nl-cls-add.c b/src/nl-cls-add.c new file mode 100644 index 0000000..997f02f --- /dev/null +++ b/src/nl-cls-add.c @@ -0,0 +1,117 @@ +/* + * src/nl-cls-add.c Add classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2 of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include "cls/utils.h" + +static int quiet = 0; + +static void print_usage(void) +{ + printf( +"Usage: nl-cls-add [OPTION]... [CLASSIFIER] TYPE [TYPE OPTIONS]...\n" +"\n" +"Options\n" +" -q, --quiet Do not print informal notifications.\n" +" -h, --help Show this help.\n" +" -v, --version Show versioning information.\n" +"\n" +"Classifier Options\n" +" -d, --dev=DEV Device the classifier should be assigned to.\n" +" -p, --parent=HANDLE Parent QDisc\n" +" --proto=PROTO Protocol (default=IPv4)\n" +" --prio=NUM Priority (0..256)\n" +" --id=HANDLE Unique identifier\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_cls *cls; + struct nl_cache *link_cache; + struct rtnl_cls_ops *ops; + struct cls_module *mod; + struct nl_dump_params dp = { + .dp_type = NL_DUMP_DETAILS, + .dp_fd = stdout, + }; + char *kind; + int err, nlflags = NLM_F_CREATE; + + sock = nlt_alloc_socket(); + nlt_connect(sock, NETLINK_ROUTE); + link_cache = nlt_alloc_link_cache(sock); + cls = nlt_alloc_cls(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_PROTO = 257, + ARG_PRIO = 258, + ARG_ID, + }; + static struct option long_opts[] = { + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dev", 1, 0, 'd' }, + { "parent", 1, 0, 'p' }, + { "proto", 1, 0, ARG_PROTO }, + { "prio", 1, 0, ARG_PRIO }, + { "id", 1, 0, ARG_ID }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "+qhva:d:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case '?': exit(NLE_INVAL); + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nlt_print_version(); break; + case 'd': parse_dev(cls, link_cache, optarg); break; + case 'p': parse_parent(cls, optarg); break; + case ARG_PRIO: parse_prio(cls, optarg); break; + case ARG_ID: parse_handle(cls, optarg); break; + case ARG_PROTO: parse_proto(cls, optarg); break; + } + } + + if (optind >= argc) { + print_usage(); + fatal(EINVAL, "Missing classifier type"); + } + + kind = argv[optind++]; + if ((err = rtnl_cls_set_kind(cls, kind)) < 0) + fatal(ENOENT, "Unknown classifier type \"%s\".", kind); + + ops = rtnl_cls_get_ops(cls); + if (!(mod = lookup_cls_mod(ops))) + fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind); + + mod->parse_argv(cls, argc, argv); + + printf("Adding "); + nl_object_dump(OBJ_CAST(cls), &dp); + + if ((err = rtnl_cls_add(sock, cls, nlflags)) < 0) + fatal(err, "Unable to add classifier: %s", nl_geterror(err)); + + if (!quiet) { + printf("Added "); + nl_object_dump(OBJ_CAST(cls), &dp); + } + + return 0; +} diff --git a/src/nl-cls-delete.c b/src/nl-cls-delete.c new file mode 100644 index 0000000..cfdc170 --- /dev/null +++ b/src/nl-cls-delete.c @@ -0,0 +1,133 @@ +/* + * src/nl-cls-delete.c Delete Classifier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#include "cls/utils.h" + +static int interactive = 0, default_yes = 0, quiet = 0; +static int deleted = 0; +static struct nl_sock *sock; + +static void print_usage(void) +{ + printf( + "Usage: nl-cls-list [OPTION]... [CLASSIFIER]\n" + "\n" + "Options\n" + " -i, --interactive Run interactively\n" + " --yes Set default answer to yes\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Classifier Options\n" + " -d, --dev=DEV Device the classifier should be assigned to.\n" + " -p, --parent=HANDLE Parent qdisc/class\n" + " --proto=PROTO Protocol\n" + " --prio=NUM Priority (0..256)\n" + " --id=HANDLE Unique identifier\n" + ); + exit(0); +} + +static void delete_cb(struct nl_object *obj, void *arg) +{ + struct rtnl_cls *cls = (struct rtnl_cls *) obj; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + if (interactive && !nlt_confirm(obj, ¶ms, default_yes)) + return; + + if ((err = rtnl_cls_delete(sock, cls, 0)) < 0) + fatal(err, "Unable to delete classifier: %s", + nl_geterror(err)); + + if (!quiet) { + printf("Deleted "); + nl_object_dump(obj, ¶ms); + } + + deleted++; +} + +int main(int argc, char *argv[]) +{ + struct nl_cache *link_cache, *cls_cache; + struct rtnl_cls *cls; + int nf = 0, err; + + sock = nlt_alloc_socket(); + nlt_connect(sock, NETLINK_ROUTE); + link_cache = nlt_alloc_link_cache(sock); + cls = nlt_alloc_cls(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_PRIO = 257, + ARG_PROTO = 258, + ARG_ID, + ARG_YES, + }; + static struct option long_opts[] = { + { "interactive", 0, 0, 'i' }, + { "yes", 0, 0, ARG_YES }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dev", 1, 0, 'd' }, + { "parent", 1, 0, 'p' }, + { "proto", 1, 0, ARG_PROTO }, + { "prio", 1, 0, ARG_PRIO }, + { "id", 1, 0, ARG_ID }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "iqhvd:p:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'i': interactive = 1; break; + case ARG_YES: default_yes = 1; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nlt_print_version(); break; + case 'd': nf++; parse_dev(cls, link_cache, optarg); break; + case 'p': nf++; parse_parent(cls, optarg); break; + case ARG_PRIO: nf++; parse_prio(cls, optarg); break; + case ARG_ID: nf++; parse_handle(cls, optarg); break; + case ARG_PROTO: nf++; parse_proto(cls, optarg); break; + } + } + + if (nf == 0 && !interactive && !default_yes) { + fprintf(stderr, "You attempted to delete all classifiers in " + "non-interactive mode, aborting.\n"); + exit(0); + } + + err = rtnl_cls_alloc_cache(sock, rtnl_cls_get_ifindex(cls), + rtnl_cls_get_parent(cls), &cls_cache); + if (err < 0) + fatal(err, "Unable to allocate classifier cache: %s", + nl_geterror(err)); + + nl_cache_foreach_filter(cls_cache, OBJ_CAST(cls), delete_cb, NULL); + + if (!quiet) + printf("Deleted %d classifiers\n", deleted); + + return 0; +} diff --git a/src/nl-cls-list.c b/src/nl-cls-list.c new file mode 100644 index 0000000..9121d52 --- /dev/null +++ b/src/nl-cls-list.c @@ -0,0 +1,113 @@ +/* + * src/nl-cls-list.c List classifiers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch> + */ + +#include "cls/utils.h" + +static struct nl_sock *sock; +static struct rtnl_cls *cls; +static struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, +}; + +static void print_usage(void) +{ + printf( + "Usage: nl-cls-list [OPTION]... [CLASSIFIER]\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help text.\n" + " -v, --version Show versioning information.\n" + "\n" + "Classifier Options\n" + " -d, --dev=DEV Device the classifier should be assigned to.\n" + " -p, --parent=HANDLE Parent qdisc/class\n" + " --proto=PROTO Protocol\n" + " --prio=NUM Priority\n" + " --id=NUM Identifier\n" + ); + exit(0); +} + +static void print_cls(struct nl_object *obj, void *arg) +{ + struct nl_cache *cls_cache; + int err, ifindex; + + if (obj) + ifindex = rtnl_link_get_ifindex((struct rtnl_link *) obj); + else + ifindex = rtnl_cls_get_ifindex(cls); + + err = rtnl_cls_alloc_cache(sock, ifindex, rtnl_cls_get_parent(cls), + &cls_cache); + if (err < 0) + fatal(err, "Unable to allocate classifier cache: %s", + nl_geterror(err)); + + nl_cache_dump_filter(cls_cache, ¶ms, OBJ_CAST(cls)); + nl_cache_free(cls_cache); +} + +int main(int argc, char *argv[]) +{ + struct nl_cache *link_cache; + int dev = 0; + + params.dp_fd = stdout; + sock = nlt_alloc_socket(); + nlt_connect(sock, NETLINK_ROUTE); + link_cache = nlt_alloc_link_cache(sock); + cls = nlt_alloc_cls(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_PROTO = 257, + ARG_PRIO = 258, + ARG_ID, + }; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dev", 1, 0, 'd' }, + { "parent", 1, 0, 'p' }, + { "proto", 1, 0, ARG_PROTO }, + { "prio", 1, 0, ARG_PRIO }, + { "id", 1, 0, ARG_ID }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "+f:qhva:d:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case '?': exit(NLE_INVAL); + case 'f': params.dp_type = nlt_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nlt_print_version(); break; + case 'd': dev = 1; parse_dev(cls, link_cache, optarg); break; + case 'p': parse_parent(cls, optarg); break; + case ARG_PRIO: parse_prio(cls, optarg); break; + case ARG_ID: parse_handle(cls, optarg); break; + case ARG_PROTO: parse_proto(cls, optarg); break; + } + } + + if (!dev) + nl_cache_foreach(link_cache, print_cls, NULL); + else + print_cls(NULL, NULL); + + return 0; +} diff --git a/src/nl-fib-lookup.c b/src/nl-fib-lookup.c index 5bbf91e..705cf32 100644 --- a/src/nl-fib-lookup.c +++ b/src/nl-fib-lookup.c @@ -6,10 +6,10 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> static void print_usage(void) { @@ -25,21 +25,18 @@ static void print_usage(void) int main(int argc, char *argv[]) { - struct nl_handle *nlh; + struct nl_sock *nlh; struct nl_cache *result; struct flnl_request *request; struct nl_addr *addr; struct nl_dump_params params = { .dp_fd = stdout, - .dp_type = NL_DUMP_FULL, + .dp_type = NL_DUMP_DETAILS, }; int table = RT_TABLE_UNSPEC, scope = RT_SCOPE_UNIVERSE; int tos = 0, err = 1; uint64_t fwmark = 0; - if (nltool_init(argc, argv) < 0) - return -1; - while (1) { static struct option long_opts[] = { {"table", 1, 0, 't'}, @@ -76,24 +73,19 @@ int main(int argc, char *argv[]) if (optind >= argc) print_usage(); - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; + nlh = nl_cli_alloc_socket(); - addr = nl_addr_parse(argv[optind], AF_INET); - if (!addr) { - fprintf(stderr, "Unable to parse address \"%s\": %s\n", - argv[optind], nl_geterror()); - goto errout; - } + if ((err = nl_addr_parse(argv[optind], AF_INET, &addr)) < 0) + nl_cli_fatal(err, "Unable to parse address \"%s\": %s\n", + argv[optind], nl_geterror(err)); result = flnl_result_alloc_cache(); if (!result) - goto errout_addr; + nl_cli_fatal(ENOMEM, "Unable to allocate cache"); request = flnl_request_alloc(); if (!request) - goto errout_result; + nl_cli_fatal(ENOMEM, "Unable to allocate request"); flnl_request_set_table(request, table); flnl_request_set_fwmark(request, fwmark); @@ -103,28 +95,15 @@ int main(int argc, char *argv[]) err = flnl_request_set_addr(request, addr); nl_addr_put(addr); if (err < 0) - goto errout_put; + nl_cli_fatal(err, "Unable to send request: %s", nl_geterror(err)); - if (nltool_connect(nlh, NETLINK_FIB_LOOKUP) < 0) - goto errout_put; + nl_cli_connect(nlh, NETLINK_FIB_LOOKUP); err = flnl_lookup(nlh, request, result); - if (err < 0) { - fprintf(stderr, "Unable to lookup: %s\n", nl_geterror()); - goto errout_put; - } + if (err < 0) + nl_cli_fatal(err, "Unable to lookup: %s\n", nl_geterror(err)); nl_cache_dump(result, ¶ms); - err = 0; -errout_put: - nl_object_put(OBJ_CAST(request)); -errout_result: - nl_cache_free(result); -errout_addr: - nl_addr_put(addr); -errout: - nl_close(nlh); - nl_handle_destroy(nlh); - return err; + return 0; } diff --git a/src/nl-link-dump.c b/src/nl-link-dump.c deleted file mode 100644 index 0214025..0000000 --- a/src/nl-link-dump.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * src/nl-link-dump.c Dump link attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-link-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n" - " filter := [dev DEV] [mtu MTU] [txqlen TXQLEN] [weight WEIGHT] [link LINK]\n" - " [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n" - " [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n" - " [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n" - " [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n"); - exit(1); -} - -#include "f_link.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache; - struct rtnl_link *link; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - link = rtnl_link_alloc(); - if (!link) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_put; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_put; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_put; - - get_filter(link, argc, argv, 2, link_cache); - nl_cache_dump_filter(link_cache, ¶ms, (struct nl_object *) link); - nl_cache_free(link_cache); - err = 0; -errout_put: - rtnl_link_put(link); -errout: - nl_close(nlh); - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-link-ifindex2name.c b/src/nl-link-ifindex2name.c index e1043fb..68e5158 100644 --- a/src/nl-link-ifindex2name.c +++ b/src/nl-link-ifindex2name.c @@ -6,50 +6,39 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> -int main(int argc, char **argv) +static void print_usage(void) { - struct nl_handle *nlh; - struct nl_cache *link_cache; - int err = -1, ifindex; - char dst[32] = {0}; - const char *name; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) { - fprintf(stderr, "Usage: nl-link-ifindex2name <ifindex>\n"); - return -1; - } + printf("Usage: nl-link-ifindex2name <ifindex>\n"); + exit(0); +} - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *link_cache; + char name[IFNAMSIZ]; + uint32_t ifindex; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout; + if (argc < 2) + print_usage(); - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout; + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); - ifindex = strtoul(argv[1], NULL, 0); + ifindex = nl_cli_parse_u32(argv[1]); - if (!(name = rtnl_link_i2name(link_cache, ifindex, dst, sizeof(dst)))) - fprintf(stderr, "Interface index %d does not exist\n", ifindex); - else - printf("%s\n", name); + if (!rtnl_link_i2name(link_cache, ifindex, name, sizeof(name))) + nl_cli_fatal(ENOENT, "Interface index %d does not exist", + ifindex); - nl_cache_free(link_cache); - err = 0; -errout: - nl_close(nlh); - nl_handle_destroy(nlh); + printf("%s\n", name); - return err; + return 0; } diff --git a/src/nl-link-list.c b/src/nl-link-list.c new file mode 100644 index 0000000..5e1e3f6 --- /dev/null +++ b/src/nl-link-list.c @@ -0,0 +1,106 @@ +/* + * src/nl-link-dump.c Dump link attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#if 0 +static void print_usage(void) +{ + printf( + "Usage: nl-link-dump <mode> [<filter>]\n" + " mode := { brief | detailed | stats | xml }\n" + " filter := [dev DEV] [mtu MTU] [txqlen TXQLEN] [weight WEIGHT] [link LINK]\n" + " [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n" + " [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n" + " [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n" + " [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n"); + exit(1); +} +#endif + +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf( + "Usage: nl-link-list [OPTION]... [Link]\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Link Options\n" + " -n, --name=NAME link name\n" + " -i, --index interface index\n" + " --mtu=NUM MTU value\n" + " --txqlen=NUM TX queue length\n" + " --weight=NUM weight\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *link_cache; + struct rtnl_link *link; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + link = nl_cli_link_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_MTU = 258, + ARG_TXQLEN, + ARG_WEIGHT, + }; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "name", 1, 0, 'n' }, + { "index", 1, 0, 'i' }, + { "family", 1, 0, ARG_FAMILY }, + { "mtu", 1, 0, ARG_MTU }, + { "txqlen", 1, 0, ARG_TXQLEN }, + { "weight", 1, 0, ARG_WEIGHT }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:hvn:i:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'n': nl_cli_link_parse_name(link, optarg); break; + case 'i': nl_cli_link_parse_ifindex(link, optarg); break; + case ARG_FAMILY: nl_cli_link_parse_family(link, optarg); break; + case ARG_MTU: nl_cli_link_parse_mtu(link, optarg); break; + case ARG_TXQLEN: nl_cli_link_parse_txqlen(link, optarg); break; + case ARG_WEIGHT: nl_cli_link_parse_weight(link, optarg); break; + } + } + + nl_cache_dump_filter(link_cache, ¶ms, OBJ_CAST(link)); + + return 0; +} diff --git a/src/nl-link-name2ifindex.c b/src/nl-link-name2ifindex.c index 993397d..b04af04 100644 --- a/src/nl-link-name2ifindex.c +++ b/src/nl-link-name2ifindex.c @@ -6,46 +6,36 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf("Usage: nl-link-ifindex2name <ifindex>\n"); + exit(0); +} int main(int argc, char *argv[]) { - struct nl_handle *nlh; + struct nl_sock *sock; struct nl_cache *link_cache; - int err = -1, ifindex; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) { - printf("Usage: nl-link-name2ifindex <name>\n"); - return -1; - } - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; + uint32_t ifindex; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout; + if (argc < 2) + print_usage(); - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout; + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); - if ((ifindex = rtnl_link_name2i(link_cache, argv[1])) == RTNL_LINK_NOT_FOUND) - fprintf(stderr, "Interface %s does not exist\n", argv[1]); - else - printf("%d\n", ifindex); + if (!(ifindex = rtnl_link_name2i(link_cache, argv[1]))) + nl_cli_fatal(ENOENT, "Interface \"%s\" does not exist", + argv[1]); - nl_cache_free(link_cache); - err = 0; -errout: - nl_close(nlh); - nl_handle_destroy(nlh); + printf("%u\n", ifindex); - return err; + return 0; } diff --git a/src/nl-link-set.c b/src/nl-link-set.c index 1872301..94c94e7 100644 --- a/src/nl-link-set.c +++ b/src/nl-link-set.c @@ -6,78 +6,119 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> -static void print_usage(void) -{ - printf( - "Usage: nl-link-set <ifindex> <changes>\n" - " changes := [dev DEV] [mtu MTU] [txqlen TXQLEN] [weight WEIGHT] [link LINK]\n" +static struct nl_sock *sock; +static int quiet = 0; + +#if 0 + " changes := [link LINK]\n" " [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n" " [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n" " [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n" " [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n"); - exit(1); +#endif + +static void print_usage(void) +{ + printf( + "Usage: nl-link-set [OPTION]... [LINK]\n" + "\n" + "Options\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Selecting the Link\n" + " -n, --name=NAME link name\n" + " -i, --index interface index\n" + "Change Options\n" + " --rename=NAME rename interface\n" + " --mtu=NUM MTU value\n" + " --txqlen=NUM TX queue length\n" + " --weight=NUM weight\n" + ); + exit(0); } -#include "f_link.c" +static void set_cb(struct nl_object *obj, void *arg) +{ + struct rtnl_link *link = nl_object_priv(obj); + struct rtnl_link *change = arg; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + if ((err = rtnl_link_change(sock, link, change, 0) < 0)) + nl_cli_fatal(err, "Unable to change link: %s", + nl_geterror(err)); + + if (!quiet) { + printf("Changed "); + nl_object_dump(OBJ_CAST(link), ¶ms); + } +} int main(int argc, char *argv[]) { - struct nl_handle *nlh; struct nl_cache *link_cache; - struct rtnl_link *link, *orig; - int err = 1, ifindex; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - link = rtnl_link_alloc(); - if (!link) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - ifindex = strtoul(argv[1], NULL, 0); - - if (!(orig = rtnl_link_get(link_cache, ifindex))) { - fprintf(stderr, "Interface index %d does not exist\n", ifindex); - goto errout_cache; + struct rtnl_link *link, *change; + int ok = 0; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + link = nl_cli_link_alloc(); + change = nl_cli_link_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_RENAME = 257, + ARG_MTU = 258, + ARG_TXQLEN, + ARG_WEIGHT, + }; + static struct option long_opts[] = { + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "name", 1, 0, 'n' }, + { "index", 1, 0, 'i' }, + { "rename", 1, 0, ARG_RENAME }, + { "mtu", 1, 0, ARG_MTU }, + { "txqlen", 1, 0, ARG_TXQLEN }, + { "weight", 1, 0, ARG_WEIGHT }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhvn:i:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'n': ok++; nl_cli_link_parse_name(link, optarg); break; + case 'i': ok++; nl_cli_link_parse_ifindex(link, optarg); break; + case ARG_RENAME: nl_cli_link_parse_name(change, optarg); break; + case ARG_MTU: nl_cli_link_parse_mtu(link, optarg); break; + case ARG_TXQLEN: nl_cli_link_parse_txqlen(link, optarg); break; + case ARG_WEIGHT: nl_cli_link_parse_weight(link, optarg); break; + } } - get_filter(link, argc, argv, 2, link_cache); - - if (rtnl_link_change(nlh, orig, link, 0) < 0) { - fprintf(stderr, "Unable to change link: %s\n", nl_geterror()); - goto errout_put; - } + if (!ok) + print_usage(); - err = 0; + nl_cache_foreach_filter(link_cache, OBJ_CAST(link), set_cb, change); -errout_put: - rtnl_link_put(orig); -errout_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_link_put(link); -errout: - nl_handle_destroy(nlh); - return err; + return 0; } diff --git a/src/nl-link-stats.c b/src/nl-link-stats.c index 8a9200e..4dfca86 100644 --- a/src/nl-link-stats.c +++ b/src/nl-link-stats.c @@ -6,31 +6,46 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> static void print_usage(void) { printf( -"Usage: nl-link-stats <ifindex> [<statistic> ...]\n" -" ifindex := { all | number }\n" -" statistic := { (rx|tx)_packets | (rx|tx)_bytes | (rx|tx)_errors |\n" -" (rx|tx)_dropped | (rx|tx)_compressed | (rx|tx)_fifo_err |\n" \ -" rx_len_err | rx_over_err | rx_crc_err | rx_frame_err |\n" -" rx_missed_err | tx_abort_err | tx_carrier_err |\n" -" tx_hbeat_err | tx_win_err | tx_collision | multicast }\n"); - exit(1); + "Usage: nl-link-stats [OPTION]... [LINK] [ListOfStats]\n" + "\n" + "Options\n" + " -l, --list List available statistic names\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Link Options\n" + " -n, --name=NAME link name\n" + " -i, --index=NUM interface index\n" + ); + exit(0); +} + +static void list_stat_names(void) +{ + char buf[64]; + int i; + + for (i = 0; i < RTNL_LINK_STATS_MAX; i++) + printf("%s\n", rtnl_link_stat2str(i, buf, sizeof(buf))); + + exit(0); } -static char **gargv; static int gargc; static void dump_stat(struct rtnl_link *link, int id) { uint64_t st = rtnl_link_get_stat(link, id); - char buf[62]; + char buf[64]; printf("%s.%s %" PRIu64 "\n", rtnl_link_get_name(link), rtnl_link_stat2str(id, buf, sizeof(buf)), st); @@ -38,72 +53,67 @@ static void dump_stat(struct rtnl_link *link, int id) static void dump_stats(struct nl_object *obj, void *arg) { - int i; struct rtnl_link *link = (struct rtnl_link *) obj; + char **argv = arg; + + if (optind >= gargc) { + int i; - if (!strcasecmp(gargv[0], "all")) { for (i = 0; i < RTNL_LINK_STATS_MAX; i++) dump_stat(link, i); } else { - for (i = 0; i < gargc; i++) { - int id = rtnl_link_str2stat(gargv[i]); + while (optind < gargc) { + int id = rtnl_link_str2stat(argv[optind]); if (id < 0) fprintf(stderr, "Warning: Unknown statistic " - "\"%s\"\n", gargv[i]); + "\"%s\"\n", argv[optind]); else dump_stat(link, id); + + optind++; } } } int main(int argc, char *argv[]) { - struct nl_handle *nlh; + struct nl_sock *sock; struct nl_cache *link_cache; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 3 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - gargv = &argv[2]; - gargc = argc - 2; - - if (!strcasecmp(argv[1], "all")) - nl_cache_foreach(link_cache, dump_stats, NULL); - else { - int ifindex = strtoul(argv[1], NULL, 0); - struct rtnl_link *link = rtnl_link_get(link_cache, ifindex); - - if (!link) { - fprintf(stderr, "Could not find ifindex %d\n", ifindex); - goto errout_link_cache; + struct rtnl_link *link; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + link = nl_cli_link_alloc(); + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "list", 0, 0, 'l' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "name", 1, 0, 'n' }, + { "index", 1, 0, 'i' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "lhvn:i:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'l': list_stat_names(); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'n': nl_cli_link_parse_name(link, optarg); break; + case 'i': nl_cli_link_parse_ifindex(link, optarg); break; } - - dump_stats((struct nl_object *) link, NULL); - rtnl_link_put(link); } - err = 0; -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout: - nl_handle_destroy(nlh); - return err; + gargc = argc; + nl_cache_foreach_filter(link_cache, OBJ_CAST(link), dump_stats, argv); + + return 0; } + diff --git a/src/nl-list-caches.c b/src/nl-list-caches.c index ed0e92a..7e4ffc1 100644 --- a/src/nl-list-caches.c +++ b/src/nl-list-caches.c @@ -6,10 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink-local.h> +#include <netlink/cli/utils.h> static void print_usage(void) { @@ -47,9 +48,7 @@ static void print(struct nl_cache_ops *ops, void *arg) "brief", "detailed", "stats", - "xml", "env", - "events" }; int i; diff --git a/src/nl-list-sockets.c b/src/nl-list-sockets.c index 9a1333c..868006e 100644 --- a/src/nl-list-sockets.c +++ b/src/nl-list-sockets.c @@ -6,35 +6,26 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> #define PROC_NETLINK "/proc/net/netlink" -static void print_usage(void) -{ - fprintf(stderr, "Usage: nl-list-sockets [<file>]\n"); - exit(1); -} - int main(int argc, char *argv[]) { FILE *fd; char buf[2048], p[64]; - if (argc > 1 && !strcasecmp(argv[1], "-h")) - print_usage(); - fd = fopen(PROC_NETLINK, "r"); if (fd == NULL) { perror("fopen"); return -1; } - printf("Address Family PID Groups rmem wmem " \ - "CB refcnt\n"); + printf("Address Family PID Groups rmem " + "wmem CB refcnt\n"); while (fgets(buf, sizeof(buf), fd)) { unsigned long sk, cb; @@ -47,7 +38,7 @@ int main(int argc, char *argv[]) if (ret != 8) continue; - printf("0x%08lx %-16s %-6d %08x %-6d %-6d 0x%08lx %d\n", + printf("0x%016lx %-16s %-6d %08x %-6d %-6d 0x%08lx %d\n", sk, nl_nlfamily2str(proto, p, sizeof(p)), pid, groups, rmem, wmem, cb, refcnt); } diff --git a/src/nl-monitor.c b/src/nl-monitor.c index 9f21dbb..fdf6497 100644 --- a/src/nl-monitor.c +++ b/src/nl-monitor.c @@ -6,12 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" -#include <netlink/route/link.h> -#include <netlink/route/addr.h> +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> static void obj_input(struct nl_object *obj, void *arg) { @@ -35,7 +34,7 @@ static int event_input(struct nl_msg *msg, void *arg) int main(int argc, char *argv[]) { - struct nl_handle *nlh; + struct nl_sock *sock; struct nl_cache *link_cache; int err = 1; int i, idx; @@ -61,16 +60,9 @@ int main(int argc, char *argv[]) { RTNLGRP_NONE, NULL } }; - if (nltool_init(argc, argv) < 0) - return -1; - - nlh = nltool_alloc_handle(); - if (nlh == NULL) - return -1; - - nl_disable_sequence_check(nlh); - - nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); + sock = nl_cli_alloc_socket(); + nl_socket_disable_seq_check(sock); + nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL); if (argc > 1 && !strcasecmp(argv[1], "-h")) { printf("Usage: nl-monitor [<groups>]\n"); @@ -82,18 +74,15 @@ int main(int argc, char *argv[]) return 2; } - if (nl_connect(nlh, NETLINK_ROUTE) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout; - } + nl_cli_connect(sock, NETLINK_ROUTE); for (idx = 1; argc > idx; idx++) { for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++) { if (!strcmp(argv[idx], known_groups[i].gr_name)) { - if (nl_socket_add_membership(nlh, known_groups[i].gr_id) < 0) { - fprintf(stderr, "%s: %s\n", argv[idx], nl_geterror()); - goto errout; + if ((err = nl_socket_add_membership(sock, known_groups[i].gr_id)) < 0) { + nl_cli_fatal(err, "%s: %s\n", argv[idx], + nl_geterror(err)); } break; @@ -103,18 +92,13 @@ int main(int argc, char *argv[]) fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]); } - if ((link_cache = rtnl_link_alloc_cache(nlh)) == NULL) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_close; - } - - nl_cache_mngt_provide(link_cache); + link_cache = nl_cli_link_alloc_cache(sock); while (1) { fd_set rfds; int fd, retval; - fd = nl_socket_get_fd(nlh); + fd = nl_socket_get_fd(sock); FD_ZERO(&rfds); FD_SET(fd, &rfds); @@ -123,13 +107,9 @@ int main(int argc, char *argv[]) if (retval) { /* FD_ISSET(fd, &rfds) will be true */ - nl_recvmsgs_default(nlh); + nl_recvmsgs_default(sock); } } - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout: - return err; + return 0; } diff --git a/src/nl-neigh-add.c b/src/nl-neigh-add.c index 14b99de..4cddabe 100644 --- a/src/nl-neigh-add.c +++ b/src/nl-neigh-add.c @@ -6,74 +6,105 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/neigh.h> +#include <netlink/cli/link.h> -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct rtnl_neigh *neigh; - struct nl_addr *addr; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 4 || !strcmp(argv[1], "-h")) { - printf("Usage: nl-neigh-add <addr> <lladdr> " - "<ifindex> [<state>]\n"); - return 1; - } - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - neigh = rtnl_neigh_alloc(); - if (!neigh) - goto errout; +static int quiet = 0; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - addr = nltool_addr_parse(argv[1]); - if (!addr) - goto errout_close; - rtnl_neigh_set_dst(neigh, addr); - nl_addr_put(addr); +static void print_usage(void) +{ + printf( + "Usage: nl-neigh-add [OPTION]... NEIGHBOUR\n" + "\n" + "Options\n" + " --update-only Do not create neighbour, updates exclusively\n" + " --create-only Do not update neighbour if it exists already.\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Neighbour Options\n" + " -a, --addr=ADDR Destination address of neighbour\n" + " -l, --lladdr=ADDR Link layer address of neighbour\n" + " -d, --dev=DEV Device the neighbour is connected to\n" + " --state=STATE Neighbour state, (default = permanent)\n" + "\n" + "Example\n" + " nl-neigh-add --create-only --addr=10.0.0.1 --dev=eth0 \\\n" + " --lladdr=AA:BB:CC:DD:EE:FF\n" + ); - addr = nltool_addr_parse(argv[2]); - if (!addr) - goto errout_close; - rtnl_neigh_set_lladdr(neigh, addr); - nl_addr_put(addr); + exit(0); +} - rtnl_neigh_set_ifindex(neigh, strtoul(argv[3], NULL, 0)); +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_neigh *neigh; + struct nl_cache *link_cache; + struct nl_dump_params dp = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err, ok = 0, nlflags = NLM_F_REPLACE | NLM_F_CREATE; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + neigh = nl_cli_neigh_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_UPDATE_ONLY = 257, + ARG_CREATE_ONLY = 258, + ARG_STATE, + }; + static struct option long_opts[] = { + { "update-only", 0, 0, ARG_UPDATE_ONLY }, + { "create-only", 0, 0, ARG_CREATE_ONLY }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "addr", 1, 0, 'a' }, + { "lladdr", 1, 0, 'l' }, + { "dev", 1, 0, 'd' }, + { "state", 1, 0, ARG_STATE }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx); + if (c == -1) + break; - if (argc > 4) { - int state = rtnl_neigh_str2state(argv[4]); - if (state < 0) { - fprintf(stderr, "Unknown state \"%s\"\n", argv[4]); - goto errout_close; + switch (c) { + case ARG_UPDATE_ONLY: nlflags &= ~NLM_F_CREATE; break; + case ARG_CREATE_ONLY: nlflags |= NLM_F_EXCL; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'a': ok++; nl_cli_neigh_parse_dst(neigh, optarg); break; + case 'l': nl_cli_neigh_parse_lladdr(neigh, optarg); break; + case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break; + case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break; } - rtnl_neigh_set_state(neigh, state); - } else - rtnl_neigh_set_state(neigh, NUD_PERMANENT); + } + + if (!ok) + print_usage(); - if (rtnl_neigh_add(nlh, neigh, 0) < 0) { - fprintf(stderr, "Unable to add address: %s\n", nl_geterror()); - goto errout_close; - } + if ((err = rtnl_neigh_add(sock, neigh, nlflags)) < 0) + nl_cli_fatal(err, "Unable to add neighbour: %s", + nl_geterror(err)); - err = 0; + if (!quiet) { + printf("Added "); + nl_object_dump(OBJ_CAST(neigh), &dp); + } -errout_close: - nl_close(nlh); -errout_free: - rtnl_neigh_put(neigh); -errout: - nl_handle_destroy(nlh); - return err; + return 0; } diff --git a/src/nl-neigh-delete.c b/src/nl-neigh-delete.c index 7829d34..887bd84 100644 --- a/src/nl-neigh-delete.c +++ b/src/nl-neigh-delete.c @@ -6,61 +6,117 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/neigh.h> +#include <netlink/cli/link.h> -int main(int argc, char *argv[]) +static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0; +struct nl_sock *sock; + +static void print_usage(void) { - struct nl_handle *nlh; - struct rtnl_neigh *neigh; - struct nl_addr *addr; - int err = 1; + printf( + "Usage: nl-neigh-delete [OPTION]... [NEIGHBOUR]\n" + "\n" + "Options\n" + " -i, --interactive Run interactively\n" + " --yes Set default answer to yes\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Neighbour Options\n" + " -a, --addr=ADDR Destination address of neighbour\n" + " -l, --lladdr=ADDR Link layer address of neighbour\n" + " -d, --dev=DEV Device the neighbour is connected to\n" + " --family=FAMILY Destination address family\n" + " --state=STATE Neighbour state, (default = permanent)\n" + ); - if (nltool_init(argc, argv) < 0) - return -1; + exit(0); +} - if (argc < 3 || !strcmp(argv[1], "-h")) { - printf("Usage: nl-neigh-delete <addr> <ifindex>\n"); - return 2; - } +static void delete_cb(struct nl_object *obj, void *arg) +{ + struct rtnl_neigh *neigh = nl_object_priv(obj); + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; + if (interactive && !nl_cli_confirm(obj, ¶ms, default_yes)) + return; - neigh = rtnl_neigh_alloc(); - if (neigh == NULL) - goto errout; + if ((err = rtnl_neigh_delete(sock, neigh, 0)) < 0) + nl_cli_fatal(err, "Unable to delete neighbour: %s\n", + nl_geterror(err)); - if (nl_connect(nlh, NETLINK_ROUTE) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_free; + if (!quiet) { + printf("Deleted "); + nl_object_dump(obj, ¶ms); } - addr = nl_addr_parse(argv[1], AF_UNSPEC); - if (addr == NULL) { - fprintf(stderr, "Invalid address \"%s\"\n", argv[1]); - goto errout_close; - } - rtnl_neigh_set_dst(neigh, addr); - nl_addr_put(addr); + deleted++; +} + +int main(int argc, char *argv[]) +{ + struct rtnl_neigh *neigh; + struct nl_cache *link_cache, *neigh_cache; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + neigh_cache = nl_cli_neigh_alloc_cache(sock); + neigh = nl_cli_neigh_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_STATE = 258, + ARG_YES, + }; + static struct option long_opts[] = { + { "interactive", 0, 0, 'i' }, + { "yes", 0, 0, ARG_YES }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "addr", 1, 0, 'a' }, + { "lladdr", 1, 0, 'l' }, + { "dev", 1, 0, 'd' }, + { "family", 1, 0, ARG_FAMILY }, + { "state", 1, 0, ARG_STATE }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx); + if (c == -1) + break; - rtnl_neigh_set_ifindex(neigh, strtoul(argv[2], NULL, 0)); + switch (c) { + case 'i': interactive = 1; break; + case ARG_YES: default_yes = 1; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'a': nl_cli_neigh_parse_dst(neigh, optarg); break; + case 'l': nl_cli_neigh_parse_lladdr(neigh, optarg); break; + case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break; + case ARG_FAMILY: nl_cli_neigh_parse_family(neigh, optarg); break; + case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break; + } + } - if (rtnl_neigh_delete(nlh, neigh, 0) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_close; - } + nl_cache_foreach_filter(neigh_cache, OBJ_CAST(neigh), delete_cb, NULL); - err = 0; + if (!quiet) + printf("Deleted %d neighbours\n", deleted); -errout_close: - nl_close(nlh); -errout_free: - rtnl_neigh_put(neigh); -errout: - nl_handle_destroy(nlh); - return err; + return 0; } diff --git a/src/nl-neigh-dump.c b/src/nl-neigh-dump.c deleted file mode 100644 index 4553f2e..0000000 --- a/src/nl-neigh-dump.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * src/nl-neigh-dump.c Dump neighbour attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-neigh-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n" - " filter := [dev DEV] [dst ADDR] [lladdr ADDR]\n"); - exit(1); -} - -#include "f_neigh.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *neigh_cache; - struct rtnl_neigh *neigh; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - neigh = rtnl_neigh_alloc(); - if (neigh == NULL) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - neigh_cache = nltool_alloc_neigh_cache(nlh); - if (!neigh_cache) - goto errout_link_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_neigh_cache; - - get_filter(neigh, argc, argv, 2, neigh_cache); - - nl_cache_dump_filter(neigh_cache, ¶ms, (struct nl_object *) neigh); - - err = 0; - -errout_neigh_cache: - nl_cache_free(neigh_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_neigh_put(neigh); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-neigh-list.c b/src/nl-neigh-list.c new file mode 100644 index 0000000..ebf5486 --- /dev/null +++ b/src/nl-neigh-list.c @@ -0,0 +1,89 @@ +/* + * src/nl-neigh-list.c List Neighbours + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/neigh.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf( + "Usage: nl-neigh-list [OPTION]... [NEIGHBOUR]\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Neighbour Options\n" + " -a, --addr=ADDR Destination address of neighbour\n" + " -l, --lladdr=ADDR Link layer address of neighbour\n" + " -d, --dev=DEV Device the neighbour is connected to\n" + " --family=FAMILY Destination address family\n" + " --state=STATE Neighbour state, (default = permanent)\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_neigh *neigh; + struct nl_cache *link_cache, *neigh_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + neigh_cache = nl_cli_neigh_alloc_cache(sock); + neigh = nl_cli_neigh_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_STATE = 258, + }; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "addr", 1, 0, 'a' }, + { "lladdr", 1, 0, 'l' }, + { "dev", 1, 0, 'd' }, + { "family", 1, 0, ARG_FAMILY }, + { "state", 1, 0, ARG_STATE }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:hva:l:d:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'a': nl_cli_neigh_parse_dst(neigh, optarg); break; + case 'l': nl_cli_neigh_parse_lladdr(neigh, optarg); break; + case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break; + case ARG_FAMILY: nl_cli_neigh_parse_family(neigh, optarg); break; + case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break; + } + } + + nl_cache_dump_filter(neigh_cache, ¶ms, OBJ_CAST(neigh)); + + return 0; +} diff --git a/src/nl-neightbl-dump.c b/src/nl-neightbl-dump.c deleted file mode 100644 index 0d79711..0000000 --- a/src/nl-neightbl-dump.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * src/nl-neightbl-dump.c Dump neighbour tables - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-neightbl-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n" - " filter :=\n"); - exit(1); -} - -int main(int argc, char *argv[]) -{ - int err = -1; - struct nl_handle *nlh; - struct nl_cache *ntc, *lc; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF, - }; - - if (argc < 2) - print_usage(); - - if (nltool_init(argc, argv) < 0) - return -1; - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout; - - ntc = nltool_alloc_neightbl_cache(nlh); - if (!ntc) - goto errout_close; - - lc = nltool_alloc_link_cache(nlh); - if (!lc) - goto errout_ntbl_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_link_cache; - - nl_cache_dump(ntc, ¶ms); - err = 0; - -errout_link_cache: - nl_cache_free(lc); -errout_ntbl_cache: - nl_cache_free(ntc); -errout_close: - nl_close(nlh); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-neightbl-list.c b/src/nl-neightbl-list.c new file mode 100644 index 0000000..5010b92 --- /dev/null +++ b/src/nl-neightbl-list.c @@ -0,0 +1,66 @@ +/* + * src/nl-neightbl-list.c Dump neighbour tables + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf( + "Usage: nl-neightbl-list [OPTION]...\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *link_cache, *neightbl_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + neightbl_cache = nl_cli_alloc_cache(sock, "neighbour table", + rtnl_neightbl_alloc_cache); + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:hv", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + } + } + + nl_cache_dump(neightbl_cache, ¶ms); + + return 0; +} diff --git a/src/nl-pktloc-lookup.c b/src/nl-pktloc-lookup.c new file mode 100644 index 0000000..09b04b2 --- /dev/null +++ b/src/nl-pktloc-lookup.c @@ -0,0 +1,37 @@ +/* + * src/nl-pktloc-lookup.c Lookup packet location alias + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/route/pktloc.h> + +static void print_usage(void) +{ + printf("Usage: nl-pktloc-lookup <name>\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct rtnl_pktloc *loc; + int err; + + if (argc < 2) + print_usage(); + + if ((err = rtnl_pktloc_lookup(argv[1], &loc)) < 0) + nl_cli_fatal(err, "Unable to lookup packet location: %s", + nl_geterror(err)); + + printf("%s: %u %u+%u 0x%x %u\n", loc->name, loc->align, + loc->layer, loc->offset, loc->mask, loc->flags); + + return 0; +} diff --git a/src/nl-qdisc-delete.c b/src/nl-qdisc-delete.c index b8a17ca..5cb7aa3 100644 --- a/src/nl-qdisc-delete.c +++ b/src/nl-qdisc-delete.c @@ -1,76 +1,116 @@ /* - * src/nl-qdisc-delete.c Delete Qdiscs + * src/nl-qdisc-delete.c Delete Queuing Disciplines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/qdisc.h> +#include <netlink/cli/link.h> + +static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0; +struct nl_sock *sock; static void print_usage(void) { - printf("Usage: nl-qdisc-delete <ifindex> <parent> <handle>\n"); - exit(1); + printf( + "Usage: nl-qdisc-delete [OPTION]... [QDISC]\n" + "\n" + "Options\n" + " -i, --interactive Run interactively\n" + " --yes Set default answer to yes\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "QDisc Options\n" + " -d, --dev=DEV Device the qdisc is attached to\n" + " -p, --parent=HANDLE Identifier of parent qdisc\n" + " -H, --handle=HANDLE Identifier\n" + " -k, --kind=NAME Kind of qdisc (e.g. pfifo_fast)\n" + ); + + exit(0); } -int main(int argc, char *argv[]) +static void delete_cb(struct nl_object *obj, void *arg) { - struct nl_handle *nlh; - struct rtnl_qdisc *qdisc; - uint32_t handle, parent; - int err = 1; + struct rtnl_qdisc *qdisc = nl_object_priv(obj); + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; - if (nltool_init(argc, argv) < 0) - return -1; + if (interactive && !nl_cli_confirm(obj, ¶ms, default_yes)) + return; - if (argc < 3 || !strcmp(argv[1], "-h")) - print_usage(); + if ((err = rtnl_qdisc_delete(sock, qdisc)) < 0) + nl_cli_fatal(err, "Unable to delete qdisc: %s\n", nl_geterror(err)); - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - qdisc = rtnl_qdisc_alloc(); - if (!qdisc) - goto errout_free_handle; - - rtnl_qdisc_set_ifindex(qdisc, strtoul(argv[1], NULL, 0)); - - if (rtnl_tc_str2handle(argv[2], &parent) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_free_qdisc; + if (!quiet) { + printf("Deleted "); + nl_object_dump(obj, ¶ms); } - if (argc > 3) { - if (rtnl_tc_str2handle(argv[3], &handle) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_free_qdisc; - } + deleted++; +} - rtnl_qdisc_set_handle(qdisc, handle); - } +int main(int argc, char *argv[]) +{ + struct rtnl_qdisc *qdisc; + struct nl_cache *link_cache, *qdisc_cache; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + qdisc_cache = nl_cli_qdisc_alloc_cache(sock); + qdisc = nl_cli_qdisc_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_YES = 257, + }; + static struct option long_opts[] = { + { "interactive", 0, 0, 'i' }, + { "yes", 0, 0, ARG_YES }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dev", 1, 0, 'd' }, + { "parent", 1, 0, 'p' }, + { "handle", 1, 0, 'H' }, + { "kind", 1, 0, 'k' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "iqhvd:p:H:k:", long_opts, &optidx); + if (c == -1) + break; - rtnl_qdisc_set_parent(qdisc, parent); + switch (c) { + case 'i': interactive = 1; break; + case ARG_YES: default_yes = 1; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'd': nl_cli_qdisc_parse_dev(qdisc, link_cache, optarg); break; + case 'p': nl_cli_qdisc_parse_parent(qdisc, optarg); break; + case 'H': nl_cli_qdisc_parse_handle(qdisc, optarg); break; + case 'k': nl_cli_qdisc_parse_kind(qdisc, optarg); break; + } + } - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free_qdisc; + nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(qdisc), delete_cb, NULL); - if (rtnl_qdisc_delete(nlh, qdisc) < 0) { - fprintf(stderr, "Unable to delete Qdisc: %s\n", nl_geterror()); - goto errout_close; - } + if (!quiet) + printf("Deleted %d qdiscs\n", deleted); - err = 0; -errout_close: - nl_close(nlh); -errout_free_qdisc: - rtnl_qdisc_put(qdisc); -errout_free_handle: - nl_handle_destroy(nlh); -errout: - return err; + return 0; } diff --git a/src/nl-qdisc-dump.c b/src/nl-qdisc-dump.c deleted file mode 100644 index 167dc7f..0000000 --- a/src/nl-qdisc-dump.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * src/nl-qdisc-dump.c Dump qdisc attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( -"Usage: nl-qdisc-dump <mode>\n" -" mode := { brief | detailed | stats | xml }\n"); - exit(1); -} - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *qdisc_cache; - struct rtnl_qdisc *qdisc; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - return -1; - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - qdisc = rtnl_qdisc_alloc(); - if (!qdisc) - goto errout_no_put; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout; - - qdisc_cache = nltool_alloc_qdisc_cache(nlh); - if (!qdisc_cache) - goto errout_link_cache; - - nl_cache_dump_filter(qdisc_cache, ¶ms, (struct nl_object *) qdisc); - nl_cache_free(qdisc_cache); - err = 0; - -errout_link_cache: - nl_cache_free(link_cache); -errout: - rtnl_qdisc_put(qdisc); -errout_no_put: - nl_close(nlh); - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-qdisc-list.c b/src/nl-qdisc-list.c new file mode 100644 index 0000000..ec6e25f --- /dev/null +++ b/src/nl-qdisc-list.c @@ -0,0 +1,90 @@ +/* + * src/nl-qdisc-list.c List Qdiscs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/qdisc.h> +#include <netlink/cli/link.h> + +static int quiet = 0; + +static void print_usage(void) +{ + printf( + "Usage: nl-qdisc-list [OPTION]... [QDISC]\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "QDisc Options\n" + " -d, --dev=DEV Device the qdisc is attached to\n" + " -p, --parent=HANDLE Identifier of parent qdisc\n" + " -H, --handle=HANDLE Identifier\n" + " -k, --kind=NAME Kind of qdisc (e.g. pfifo_fast)\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_qdisc *qdisc; + struct nl_cache *link_cache, *qdisc_cache; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + qdisc_cache = nl_cli_qdisc_alloc_cache(sock); + qdisc = nl_cli_qdisc_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_YES = 257, + }; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dev", 1, 0, 'd' }, + { "parent", 1, 0, 'p' }, + { "handle", 1, 0, 'H' }, + { "kind", 1, 0, 'k' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:qhvd:p:H:k:", + long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'd': nl_cli_qdisc_parse_dev(qdisc, link_cache, optarg); break; + case 'p': nl_cli_qdisc_parse_parent(qdisc, optarg); break; + case 'H': nl_cli_qdisc_parse_handle(qdisc, optarg); break; + case 'k': nl_cli_qdisc_parse_kind(qdisc, optarg); break; + } + } + + nl_cache_dump_filter(qdisc_cache, ¶ms, OBJ_CAST(qdisc)); + + return 0; +} diff --git a/src/nl-route-add.c b/src/nl-route-add.c index 2686397..2f187df 100644 --- a/src/nl-route-add.c +++ b/src/nl-route-add.c @@ -1,76 +1,132 @@ /* - * src/nl-route-dump.c Dump route attributes + * src/nl-route-add.c Route addition utility * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/route.h> +#include <netlink/cli/link.h> + +static int quiet = 0; +static struct nl_cache *link_cache, *route_cache; static void print_usage(void) { printf( - "Usage: nl-route-add [<filter>]\n"); - exit(1); + "Usage: nl-route-add [OPTION]... [ROUTE]\n" + "\n" + "Options\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Route Options\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nexthop=NH nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -t, --table=TABLE Routing table\n" + " --family=FAMILY Address family\n" + " --src=ADDR Source prefix\n" + " --iif=DEV Incomming interface\n" + " --pref-src=ADDR Preferred source address\n" + " --metrics=OPTS Metrics configurations\n" + " --priority=NUM Priotity\n" + " --scope=SCOPE Scope\n" + " --protocol=PROTO Protocol\n" + " --type=TYPE { unicast | local | broadcast | multicast }\n" + ); + exit(0); } -#include "f_route.c" - int main(int argc, char *argv[]) { - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; + struct nl_sock *sock; struct rtnl_route *route; + struct nl_dump_params dp = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; int err = 1; - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + route_cache = nl_cli_route_alloc_cache(sock, 0); + route = nl_cli_route_alloc(); - route = rtnl_route_alloc(); - if (!route) - goto errout; + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_SRC = 258, + ARG_IIF, + ARG_PREF_SRC, + ARG_METRICS, + ARG_PRIORITY, + ARG_SCOPE, + ARG_PROTOCOL, + ARG_TYPE, + }; + static struct option long_opts[] = { + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dst", 1, 0, 'd' }, + { "nexthop", 1, 0, 'n' }, + { "table", 1, 0, 't' }, + { "family", 1, 0, ARG_FAMILY }, + { "src", 1, 0, ARG_SRC }, + { "iif", 1, 0, ARG_IIF }, + { "pref-src", 1, 0, ARG_PREF_SRC }, + { "metrics", 1, 0, ARG_METRICS }, + { "priority", 1, 0, ARG_PRIORITY }, + { "scope", 1, 0, ARG_SCOPE }, + { "protocol", 1, 0, ARG_PROTOCOL }, + { "type", 1, 0, ARG_TYPE }, + { 0, 0, 0, 0 } + }; - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; + c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; + switch (c) { + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'd': nl_cli_route_parse_dst(route, optarg); break; + case 'n': nl_cli_route_parse_nexthop(route, optarg, link_cache); break; + case 't': nl_cli_route_parse_table(route, optarg); break; + case ARG_FAMILY: nl_cli_route_parse_family(route, optarg); break; + case ARG_SRC: nl_cli_route_parse_src(route, optarg); break; + case ARG_IIF: nl_cli_route_parse_iif(route, optarg, link_cache); break; + case ARG_PREF_SRC: nl_cli_route_parse_pref_src(route, optarg); break; + case ARG_METRICS: nl_cli_route_parse_metric(route, optarg); break; + case ARG_PRIORITY: nl_cli_route_parse_prio(route, optarg); break; + case ARG_SCOPE: nl_cli_route_parse_scope(route, optarg); break; + case ARG_PROTOCOL: nl_cli_route_parse_protocol(route, optarg); break; + case ARG_TYPE: nl_cli_route_parse_type(route, optarg); break; + } + } - get_filter(route, argc, argv, 1, route_cache, link_cache); + if ((err = rtnl_route_add(sock, route, 0)) < 0) + nl_cli_fatal(err, "Unable to add route: %s", nl_geterror(err)); - if (rtnl_route_add(nlh, route, 0) < 0) { - fprintf(stderr, "rtnl_route_add failed: %s\n", - nl_geterror()); - goto errout_route_cache; + if (!quiet) { + printf("Added "); + nl_object_dump(OBJ_CAST(route), &dp); } - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; + return 0; } diff --git a/src/nl-route-del.c b/src/nl-route-del.c deleted file mode 100644 index 9d912e1..0000000 --- a/src/nl-route-del.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * src/nl-route-del.c Delete Routes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-route-del [<filter>]\n"); - exit(1); -} - -#include "f_route.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; - struct rtnl_route *route; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - route = rtnl_route_alloc(); - if (!route) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; - - get_filter(route, argc, argv, 1, route_cache, link_cache); - - if (rtnl_route_del(nlh, route, 0) < 0) { - fprintf(stderr, "rtnl_route_del failed: %s\n", - nl_geterror()); - goto errout_route_cache; - } - - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-route-delete.c b/src/nl-route-delete.c new file mode 100644 index 0000000..884fd7f --- /dev/null +++ b/src/nl-route-delete.c @@ -0,0 +1,168 @@ +/* + * src/nl-route-delete.c Delete Routes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/route.h> +#include <netlink/cli/link.h> + +static int interactive = 0, default_yes = 0, quiet = 0; +static int deleted = 0; +static struct nl_sock *sock; + +static void print_version(void) +{ + fprintf(stderr, "%s\n", LIBNL_STRING); + exit(0); +} + +static void print_usage(void) +{ + printf( + "Usage: nl-route-delete [OPTION]... [ROUTE]\n" + "\n" + "Options\n" + " -i, --interactive Run interactively\n" + " --yes Set default answer to yes\n" + " -q, --quiet Do not print informal notifications\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Route Options\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nexthop=NH nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -t, --table=TABLE Routing table\n" + " --family=FAMILY Address family\n" + " --src=ADDR Source prefix\n" + " --iif=DEV Incomming interface\n" + " --pref-src=ADDR Preferred source address\n" + " --metrics=OPTS Metrics configurations\n" + " --priority=NUM Priotity\n" + " --scope=SCOPE Scope\n" + " --protocol=PROTO Protocol\n" + " --type=TYPE { unicast | local | broadcast | multicast }\n" + ); + exit(0); +} + +static void delete_cb(struct nl_object *obj, void *arg) +{ + struct rtnl_route *route = (struct rtnl_route *) obj; + struct nl_dump_params params = { + .dp_type = NL_DUMP_LINE, + .dp_fd = stdout, + }; + int err; + + if (interactive && !nl_cli_confirm(obj, ¶ms, default_yes)) + return; + + if ((err = rtnl_route_delete(sock, route, 0)) < 0) + nl_cli_fatal(err, "Unable to delete route: %s", nl_geterror(err)); + + if (!quiet) { + printf("Deleted "); + nl_object_dump(obj, ¶ms); + } + + deleted++; +} + +int main(int argc, char *argv[]) +{ + struct nl_cache *link_cache, *route_cache; + struct rtnl_route *route; + int nf = 0; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + route_cache = nl_cli_route_alloc_cache(sock, 0); + route = nl_cli_route_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_SRC = 258, + ARG_IIF, + ARG_PREF_SRC, + ARG_METRICS, + ARG_PRIORITY, + ARG_SCOPE, + ARG_PROTOCOL, + ARG_TYPE, + ARG_YES, + }; + static struct option long_opts[] = { + { "interactive", 0, 0, 'i' }, + { "yes", 0, 0, ARG_YES }, + { "quiet", 0, 0, 'q' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dst", 1, 0, 'd' }, + { "nexthop", 1, 0, 'n' }, + { "table", 1, 0, 't' }, + { "family", 1, 0, ARG_FAMILY }, + { "src", 1, 0, ARG_SRC }, + { "iif", 1, 0, ARG_IIF }, + { "pref-src", 1, 0, ARG_PREF_SRC }, + { "metrics", 1, 0, ARG_METRICS }, + { "priority", 1, 0, ARG_PRIORITY }, + { "scope", 1, 0, ARG_SCOPE }, + { "protocol", 1, 0, ARG_PROTOCOL }, + { "type", 1, 0, ARG_TYPE }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "iqhvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'i': interactive = 1; break; + case ARG_YES: default_yes = 1; break; + case 'q': quiet = 1; break; + case 'h': print_usage(); break; + case 'v': print_version(); break; + case 'd': nf++; nl_cli_route_parse_dst(route, optarg); break; + case 'n': nf++; nl_cli_route_parse_nexthop(route, optarg, link_cache); break; + case 't': nf++; nl_cli_route_parse_table(route, optarg); break; + case ARG_FAMILY: nf++; nl_cli_route_parse_family(route, optarg); break; + case ARG_SRC: nf++; nl_cli_route_parse_src(route, optarg); break; + case ARG_IIF: nf++; nl_cli_route_parse_iif(route, optarg, link_cache); break; + case ARG_PREF_SRC: nf++; nl_cli_route_parse_pref_src(route, optarg); break; + case ARG_METRICS: nf++; nl_cli_route_parse_metric(route, optarg); break; + case ARG_PRIORITY: nf++; nl_cli_route_parse_prio(route, optarg); break; + case ARG_SCOPE: nf++; nl_cli_route_parse_scope(route, optarg); break; + case ARG_PROTOCOL: nf++; nl_cli_route_parse_protocol(route, optarg); break; + case ARG_TYPE: nf++; nl_cli_route_parse_type(route, optarg); break; + } + } + + if (nf == 0 && !interactive && !default_yes) { + fprintf(stderr, "You attempted to delete all routes in " + "non-interactive mode, aborting.\n"); + exit(0); + } + + nl_cache_foreach_filter(route_cache, OBJ_CAST(route), delete_cb, NULL); + + if (!quiet) + printf("Deleted %d routes\n", deleted); + + return 0; +} diff --git a/src/nl-route-dump.c b/src/nl-route-dump.c deleted file mode 100644 index aed9bd2..0000000 --- a/src/nl-route-dump.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * src/nl-route-dump.c Dump route attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-route-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n"); - exit(1); -} - -#include "f_route.c" - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *route_cache; - struct rtnl_route *route; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - route = rtnl_route_alloc(); - if (!route) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_link_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_route_cache; - - get_filter(route, argc, argv, 2, route_cache, link_cache); - - nl_cache_dump_filter(route_cache, ¶ms, (struct nl_object *) route); - - err = 0; - -errout_route_cache: - nl_cache_free(route_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - rtnl_route_put(route); -errout: - nl_handle_destroy(nlh); - return err; -} diff --git a/src/nl-route-get.c b/src/nl-route-get.c index fd7a503..c2f07d4 100644 --- a/src/nl-route-get.c +++ b/src/nl-route-get.c @@ -6,10 +6,12 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/route.h> +#include <netlink/cli/link.h> static void print_usage(void) { @@ -17,48 +19,43 @@ static void print_usage(void) exit(1); } +static void parse_cb(struct nl_object *obj, void *arg) +{ + //struct rtnl_route *route = (struct rtnl_route *) obj; + struct nl_dump_params params = { + .dp_fd = stdout, + .dp_type = NL_DUMP_DETAILS, + }; + + nl_object_dump(obj, ¶ms); +} + static int cb(struct nl_msg *msg, void *arg) { - nl_cache_parse_and_add(arg, msg); + int err; + + if ((err = nl_msg_parse(msg, &parse_cb, NULL)) < 0) + nl_cli_fatal(err, "Unable to parse object: %s", nl_geterror(err)); return 0; } int main(int argc, char *argv[]) { - struct nl_handle *nlh; + struct nl_sock *sock; struct nl_cache *link_cache, *route_cache; struct nl_addr *dst; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; int err = 1; if (argc < 2 || !strcmp(argv[1], "-h")) print_usage(); - if (nltool_init(argc, argv) < 0) - goto errout; - - nlh = nltool_alloc_handle(); - if (!nlh) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free_handle; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + route_cache = nl_cli_route_alloc_cache(sock, 0); - dst = nltool_addr_parse(argv[1]); - if (!dst) - goto errout_link_cache; - - route_cache = nltool_alloc_route_cache(nlh); - if (!route_cache) - goto errout_addr_put; + dst = nl_cli_addr_parse(argv[1], AF_INET); { struct nl_msg *m; @@ -71,36 +68,18 @@ int main(int argc, char *argv[]) nlmsg_append(m, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO); nla_put_addr(m, RTA_DST, dst); - if ((err = nl_send_auto_complete(nlh, m)) < 0) { - nlmsg_free(m); - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_route_cache; - } - + err = nl_send_auto_complete(sock, m); nlmsg_free(m); + if (err < 0) + nl_cli_fatal(err, "%s", nl_geterror(err)); - nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, cb, - route_cache); + nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL); - if (nl_recvmsgs_default(nlh) < 0) { - fprintf(stderr, "%s\n", nl_geterror()); - goto errout_route_cache; - } + if (nl_recvmsgs_default(sock) < 0) + nl_cli_fatal(err, "%s", nl_geterror(err)); } - nl_cache_dump(route_cache, ¶ms); - - err = 0; -errout_route_cache: - nl_cache_free(route_cache); -errout_addr_put: - nl_addr_put(dst); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free_handle: - nl_handle_destroy(nlh); -errout: - return err; + //nl_cache_dump(route_cache, ¶ms); + + return 0; } diff --git a/src/nl-route-list.c b/src/nl-route-list.c new file mode 100644 index 0000000..e0e57be --- /dev/null +++ b/src/nl-route-list.c @@ -0,0 +1,129 @@ +/* + * src/nl-route-list.c List route attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/route.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf( + "Usage: nl-route-list [OPTION]... [ROUTE]\n" + "\n" + "Options\n" + " -c, --cache List the contents of the route cache\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Route Options\n" + " -d, --dst=ADDR destination prefix, e.g. 10.10.0.0/16\n" + " -n, --nexthop=NH nexthop configuration:\n" + " dev=DEV route via device\n" + " weight=WEIGHT weight of nexthop\n" + " flags=FLAGS\n" + " via=GATEWAY route via other node\n" + " realms=REALMS\n" + " e.g. dev=eth0,via=192.168.1.12\n" + " -t, --table=TABLE Routing table\n" + " --family=FAMILY Address family\n" + " --src=ADDR Source prefix\n" + " --iif=DEV Incomming interface\n" + " --pref-src=ADDR Preferred source address\n" + " --metrics=OPTS Metrics configurations\n" + " --priority=NUM Priotity\n" + " --scope=SCOPE Scope\n" + " --protocol=PROTO Protocol\n" + " --type=TYPE { unicast | local | broadcast | multicast }\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct nl_cache *link_cache, *route_cache; + struct rtnl_route *route; + struct nl_dump_params params = { + .dp_fd = stdout, + .dp_type = NL_DUMP_LINE, + }; + int print_cache = 0; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + route = nl_cli_route_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + ARG_SRC = 258, + ARG_IIF, + ARG_PREF_SRC, + ARG_METRICS, + ARG_PRIORITY, + ARG_SCOPE, + ARG_PROTOCOL, + ARG_TYPE, + }; + static struct option long_opts[] = { + { "cache", 0, 0, 'c' }, + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "dst", 1, 0, 'd' }, + { "nexthop", 1, 0, 'n' }, + { "table", 1, 0, 't' }, + { "family", 1, 0, ARG_FAMILY }, + { "src", 1, 0, ARG_SRC }, + { "iif", 1, 0, ARG_IIF }, + { "pref-src", 1, 0, ARG_PREF_SRC }, + { "metrics", 1, 0, ARG_METRICS }, + { "priority", 1, 0, ARG_PRIORITY }, + { "scope", 1, 0, ARG_SCOPE }, + { "protocol", 1, 0, ARG_PROTOCOL }, + { "type", 1, 0, ARG_TYPE }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "cf:hvd:n:t:", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'c': print_cache = 1; break; + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'd': nl_cli_route_parse_dst(route, optarg); break; + case 'n': nl_cli_route_parse_nexthop(route, optarg, link_cache); break; + case 't': nl_cli_route_parse_table(route, optarg); break; + case ARG_FAMILY: nl_cli_route_parse_family(route, optarg); break; + case ARG_SRC: nl_cli_route_parse_src(route, optarg); break; + case ARG_IIF: nl_cli_route_parse_iif(route, optarg, link_cache); break; + case ARG_PREF_SRC: nl_cli_route_parse_pref_src(route, optarg); break; + case ARG_METRICS: nl_cli_route_parse_metric(route, optarg); break; + case ARG_PRIORITY: nl_cli_route_parse_prio(route, optarg); break; + case ARG_SCOPE: nl_cli_route_parse_scope(route, optarg); break; + case ARG_PROTOCOL: nl_cli_route_parse_protocol(route, optarg); break; + case ARG_TYPE: nl_cli_route_parse_type(route, optarg); break; + } + } + + route_cache = nl_cli_route_alloc_cache(sock, + print_cache ? ROUTE_CACHE_CONTENT : 0); + + nl_cache_dump_filter(route_cache, ¶ms, OBJ_CAST(route)); + + return 0; +} diff --git a/src/nl-rule-dump.c b/src/nl-rule-dump.c deleted file mode 100644 index f9e483a..0000000 --- a/src/nl-rule-dump.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * src/nl-rule-dump.c Dump rule attributes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -static void print_usage(void) -{ - printf( - "Usage: nl-rule-dump <mode> [<filter>]\n" - " mode := { brief | detailed | stats | xml }\n"); - exit(1); -} - -int main(int argc, char *argv[]) -{ - struct nl_handle *nlh; - struct nl_cache *link_cache, *rule_cache; - struct rtnl_rule *rule; - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_BRIEF - }; - int err = 1; - - if (nltool_init(argc, argv) < 0) - return -1; - - if (argc < 2 || !strcmp(argv[1], "-h")) - print_usage(); - - nlh = nltool_alloc_handle(); - if (!nlh) - return -1; - - rule = rtnl_rule_alloc(); - if (!rule) - goto errout; - - if (nltool_connect(nlh, NETLINK_ROUTE) < 0) - goto errout_free; - - link_cache = nltool_alloc_link_cache(nlh); - if (!link_cache) - goto errout_close; - - rule_cache = nltool_alloc_rule_cache(nlh); - if (!rule_cache) - goto errout_link_cache; - - params.dp_type = nltool_parse_dumptype(argv[1]); - if (params.dp_type < 0) - goto errout_rule_cache; - - //get_filter(route, argc, argv, 2, route_cache); - - nl_cache_dump_filter(rule_cache, ¶ms, (struct nl_object *) rule); - - err = 0; - -errout_rule_cache: - nl_cache_free(rule_cache); -errout_link_cache: - nl_cache_free(link_cache); -errout_close: - nl_close(nlh); -errout_free: - nl_object_put((struct nl_object *) rule); -errout: - return err; -} diff --git a/src/nl-rule-list.c b/src/nl-rule-list.c new file mode 100644 index 0000000..8b474fa --- /dev/null +++ b/src/nl-rule-list.c @@ -0,0 +1,77 @@ +/* + * src/nl-rule-dump.c Dump rule attributes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> + */ + +#include <netlink/cli/utils.h> +#include <netlink/cli/rule.h> +#include <netlink/cli/link.h> + +static void print_usage(void) +{ + printf( + "Usage: nl-rule-list [OPTION]... [ROUTE]\n" + "\n" + "Options\n" + " -c, --cache List the contents of the route cache\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + "\n" + "Rule Options\n" + " --family Address family\n" + ); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct nl_sock *sock; + struct rtnl_rule *rule; + struct nl_cache *link_cache, *rule_cache; + struct nl_dump_params params = { + .dp_fd = stdout, + .dp_type = NL_DUMP_LINE, + }; + + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + rule_cache = nl_cli_rule_alloc_cache(sock); + rule = nl_cli_rule_alloc(); + + for (;;) { + int c, optidx = 0; + enum { + ARG_FAMILY = 257, + }; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "family", 1, 0, ARG_FAMILY }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:hv", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case ARG_FAMILY: nl_cli_rule_parse_family(rule, optarg); break; + } + } + + nl_cache_dump_filter(rule_cache, ¶ms, OBJ_CAST(rule)); + + return 0; +} diff --git a/src/nl-tctree-dump.c b/src/nl-tctree-list.c index 8b45e7b..a074a51 100644 --- a/src/nl-tctree-dump.c +++ b/src/nl-tctree-list.c @@ -1,26 +1,41 @@ /* - * src/nl-tctree-dump.c Dump Traffic Control Tree + * src/nl-tctree-list.c List Traffic Control Tree * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> +#include <netlink/cli/link.h> +#include <netlink/cli/qdisc.h> #include <linux/pkt_sched.h> -static struct nl_handle *nl_handle; +static struct nl_sock *sock; static struct nl_cache *qdisc_cache, *class_cache; -static struct nl_dump_params dump_params = { - .dp_type = NL_DUMP_FULL, +static struct nl_dump_params params = { + .dp_type = NL_DUMP_DETAILS, }; static int ifindex; static void print_qdisc(struct nl_object *, void *); +static void print_usage(void) +{ + printf( + "Usage: nl-tctree-list [OPTION]...\n" + "\n" + "Options\n" + " -f, --format=TYPE Output format { brief | details | stats }\n" + " -h, --help Show this help\n" + " -v, --version Show versioning information\n" + ); + exit(0); +} + static void print_class(struct nl_object *obj, void *arg) { struct rtnl_qdisc *leaf; @@ -28,8 +43,8 @@ static void print_class(struct nl_object *obj, void *arg) struct nl_cache *cls_cache; uint32_t parent = rtnl_class_get_handle(class); - dump_params.dp_prefix = (int)(long) arg; - nl_object_dump(obj, &dump_params); + params.dp_prefix = (int)(long) arg; + nl_object_dump(obj, ¶ms); leaf = rtnl_class_leaf_qdisc(class, qdisc_cache); if (leaf) @@ -37,12 +52,11 @@ static void print_class(struct nl_object *obj, void *arg) rtnl_class_foreach_child(class, class_cache, &print_class, arg + 2); - cls_cache = rtnl_cls_alloc_cache(nl_handle, ifindex, parent); - if (!cls_cache) + if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0) return; - dump_params.dp_prefix = (int)(long) arg + 2; - nl_cache_dump(cls_cache, &dump_params); + params.dp_prefix = (int)(long) arg + 2; + nl_cache_dump(cls_cache, ¶ms); nl_cache_free(cls_cache); } @@ -52,17 +66,16 @@ static void print_qdisc(struct nl_object *obj, void *arg) struct nl_cache *cls_cache; uint32_t parent = rtnl_qdisc_get_handle(qdisc); - dump_params.dp_prefix = (int)(long) arg; - nl_object_dump(obj, &dump_params); + params.dp_prefix = (int)(long) arg; + nl_object_dump(obj, ¶ms); rtnl_qdisc_foreach_child(qdisc, class_cache, &print_class, arg + 2); - cls_cache = rtnl_cls_alloc_cache(nl_handle, ifindex, parent); - if (!cls_cache) + if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0) return; - dump_params.dp_prefix = (int)(long) arg + 2; - nl_cache_dump(cls_cache, &dump_params); + params.dp_prefix = (int)(long) arg + 2; + nl_cache_dump(cls_cache, ¶ms); nl_cache_free(cls_cache); } @@ -72,11 +85,10 @@ static void print_link(struct nl_object *obj, void *arg) struct rtnl_qdisc *qdisc; ifindex = rtnl_link_get_ifindex(link); - dump_params.dp_prefix = 0; - nl_object_dump(obj, &dump_params); + params.dp_prefix = 0; + nl_object_dump(obj, ¶ms); - class_cache = rtnl_class_alloc_cache(nl_handle, ifindex); - if (!class_cache) + if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0) return; qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT); @@ -104,41 +116,34 @@ int main(int argc, char *argv[]) { struct nl_cache *link_cache; - if (nltool_init(argc, argv) < 0) - return -1; - - dump_params.dp_fd = stdout; - - if (argc > 1) { - if (!strcasecmp(argv[1], "brief")) - dump_params.dp_type = NL_DUMP_BRIEF; - else if (!strcasecmp(argv[1], "full")) - dump_params.dp_type = NL_DUMP_FULL; - else if (!strcasecmp(argv[1], "stats")) - dump_params.dp_type = NL_DUMP_STATS; + sock = nl_cli_alloc_socket(); + nl_cli_connect(sock, NETLINK_ROUTE); + link_cache = nl_cli_link_alloc_cache(sock); + qdisc_cache = nl_cli_qdisc_alloc_cache(sock); + + params.dp_fd = stdout; + + for (;;) { + int c, optidx = 0; + static struct option long_opts[] = { + { "format", 1, 0, 'f' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "f:hv", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break; + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + } } - nl_handle = nltool_alloc_handle(); - if (!nl_handle) - return 1; - - if (nltool_connect(nl_handle, NETLINK_ROUTE) < 0) - return 1; - - link_cache = nltool_alloc_link_cache(nl_handle); - if (!link_cache) - return 1; - - qdisc_cache = nltool_alloc_qdisc_cache(nl_handle); - if (!qdisc_cache) - return 1; - nl_cache_foreach(link_cache, &print_link, NULL); - nl_cache_free(qdisc_cache); - nl_cache_free(link_cache); - - nl_close(nl_handle); - nl_handle_destroy(nl_handle); return 0; } diff --git a/src/nl-util-addr.c b/src/nl-util-addr.c index 9f12795..5f0738d 100644 --- a/src/nl-util-addr.c +++ b/src/nl-util-addr.c @@ -6,10 +6,10 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> + * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch> */ -#include "utils.h" +#include <netlink/cli/utils.h> int main(int argc, char *argv[]) { @@ -21,19 +21,12 @@ int main(int argc, char *argv[]) fprintf(stderr, "Usage: nl-util-addr <address>\n"); return -1; } - - a = nl_addr_parse(argv[1], AF_UNSPEC); - if (a == NULL) { - fprintf(stderr, "Cannot parse address \"%s\"\n", argv[1]); - return -1; - } + a = nl_cli_addr_parse(argv[1], AF_UNSPEC); err = nl_addr_resolve(a, host, sizeof(host)); - if (err != 0) { - fprintf(stderr, "Cannot resolve address \"%s\": %d\n", - argv[1], err); - return -1; - } + if (err != 0) + nl_cli_fatal(err, "Unable to resolve address \"%s\": %s", + argv[1], nl_geterror(err)); printf("%s\n", host); diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index b43758a..0000000 --- a/src/utils.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * src/utils.c Utilities - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> - */ - -#include "utils.h" - -#include <stdlib.h> - -int nltool_init(int argc, char *argv[]) -{ - return 0; -} - -int nltool_connect(struct nl_handle *nlh, int protocol) -{ - int err; - - err = nl_connect(nlh, protocol); - if (err < 0) - fprintf(stderr, "Unable to connect netlink socket%s\n", - nl_geterror()); - - return err; -} - -struct nl_handle *nltool_alloc_handle(void) -{ - return nl_handle_alloc(); -} - -struct nl_addr *nltool_addr_parse(const char *str) -{ - struct nl_addr *addr; - - addr = nl_addr_parse(str, AF_UNSPEC); - if (!addr) - fprintf(stderr, "Unable to parse address \"%s\": %s\n", - str, nl_geterror()); - - return addr; -} - -int nltool_parse_dumptype(const char *str) -{ - if (!strcasecmp(str, "brief")) - return NL_DUMP_BRIEF; - else if (!strcasecmp(str, "detailed")) - return NL_DUMP_FULL; - else if (!strcasecmp(str, "stats")) - return NL_DUMP_STATS; - else if (!strcasecmp(str, "xml")) - return NL_DUMP_XML; - else if (!strcasecmp(str, "env")) - return NL_DUMP_ENV; - else { - fprintf(stderr, "Invalid dump type \"%s\".\n", str); - return -1; - } -} - -struct nl_cache *nltool_alloc_link_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_link_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve link cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_addr_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_addr_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve address cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_neigh_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_neigh_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve neighbour cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_neightbl_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_neightbl_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve neighbour table " - "cache: %s\n", nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_route_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_route_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve route cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_rule_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_rule_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve rule cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_qdisc_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = rtnl_qdisc_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve qdisc cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} - -struct nl_cache *nltool_alloc_genl_family_cache(struct nl_handle *nlh) -{ - struct nl_cache *cache; - - cache = genl_ctrl_alloc_cache(nlh); - if (!cache) - fprintf(stderr, "Unable to retrieve genl family cache: %s\n", - nl_geterror()); - else - nl_cache_mngt_provide(cache); - - return cache; -} diff --git a/tests/Makefile b/tests/Makefile index b5cec34..8494eea 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -23,7 +23,7 @@ $(TOOLS): ../src/utils.o test-%: test-%.c @echo " LD $@"; \ - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -lnl-genl -lnl-route clean: @echo " CLEAN src"; \ diff --git a/tests/test-cache-mngr.c b/tests/test-cache-mngr.c index 4d70e31..777bce8 100644 --- a/tests/test-cache-mngr.c +++ b/tests/test-cache-mngr.c @@ -1,10 +1,13 @@ #include "../src/utils.h" +#include <signal.h> + +static int quit = 0; static void change_cb(struct nl_cache *cache, struct nl_object *obj, int action) { struct nl_dump_params dp = { - .dp_type = NL_DUMP_BRIEF, + .dp_type = NL_DUMP_LINE, .dp_fd = stdout, }; @@ -18,56 +21,51 @@ static void change_cb(struct nl_cache *cache, struct nl_object *obj, nl_object_dump(obj, &dp); } +static void sigint(int arg) +{ + quit = 1; +} + int main(int argc, char *argv[]) { struct nl_cache_mngr *mngr; struct nl_cache *lc, *nc, *ac, *rc; - struct nl_handle *handle; - - nltool_init(argc, argv); + struct nl_sock *sock; + int err; - handle = nltool_alloc_handle(); + signal(SIGINT, sigint); - mngr = nl_cache_mngr_alloc(handle, NETLINK_ROUTE, NL_AUTO_PROVIDE); - if (!mngr) { - nl_perror("nl_cache_mngr_alloc"); - return -1; - } + sock = nlt_alloc_socket(); + err = nl_cache_mngr_alloc(sock, NETLINK_ROUTE, NL_AUTO_PROVIDE, &mngr); + if (err < 0) + fatal(err, "Unable to allocate cache manager: %s", + nl_geterror(err)); - lc = nl_cache_mngr_add(mngr, "route/link", &change_cb); - if (lc == NULL) { - nl_perror("nl_cache_mngr_add(route/link"); - return -1; - } + if ((err = nl_cache_mngr_add(mngr, "route/link", &change_cb, &lc)) < 0) + fatal(err, "Unable to add cache route/link: %s", + nl_geterror(err)); - nc = nl_cache_mngr_add(mngr, "route/neigh", &change_cb); - if (nc == NULL) { - nl_perror("nl_cache_mngr_add(route/neigh"); - return -1; - } + if ((err = nl_cache_mngr_add(mngr, "route/neigh", &change_cb, &nc)) < 0) + fatal(err, "Unable to add cache route/neigh: %s", + nl_geterror(err)); - ac = nl_cache_mngr_add(mngr, "route/addr", &change_cb); - if (ac == NULL) { - nl_perror("nl_cache_mngr_add(route/addr"); - return -1; - } + if ((err = nl_cache_mngr_add(mngr, "route/addr", &change_cb, &ac)) < 0) + fatal(err, "Unable to add cache route/addr: %s", + nl_geterror(err)); - rc = nl_cache_mngr_add(mngr, "route/route", &change_cb); - if (rc == NULL) { - nl_perror("nl_cache_mngr_add(route/route"); - return -1; - } + if ((err = nl_cache_mngr_add(mngr, "route/route", &change_cb, &rc)) < 0) + fatal(err, "Unable to add cache route/route: %s", + nl_geterror(err)); - for (;;) { + while (!quit) { int err = nl_cache_mngr_poll(mngr, 5000); - if (err < 0) { - nl_perror("nl_cache_mngr_poll()"); - return -1; - } + if (err < 0 && err != -NLE_INTR) + fatal(err, "Polling failed: %s", nl_geterror(err)); } nl_cache_mngr_free(mngr); + nl_socket_free(sock); return 0; } diff --git a/tests/test-genl.c b/tests/test-genl.c index e44b3fb..8bf60c5 100644 --- a/tests/test-genl.c +++ b/tests/test-genl.c @@ -2,55 +2,35 @@ int main(int argc, char *argv[]) { - struct nl_handle *h; + struct nl_sock *sock; struct nl_msg *msg; void *hdr; + int err; - if (nltool_init(argc, argv) < 0) - return -1; - - h = nltool_alloc_handle(); - if (!h) { - nl_perror("nl_handle_alloc"); - return -1; - } - - if (genl_connect(h) < 0) { - nl_perror("genl_connect"); - return -1; - } + sock = nlt_alloc_socket(); + nlt_connect(sock, NETLINK_GENERIC); msg = nlmsg_alloc(); - if (msg == NULL) { - nl_perror("nlmsg_alloc"); - return -1; - } + if (msg == NULL) + fatal(NLE_NOMEM, "Unable to allocate netlink message"); hdr = genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, 1); - if (hdr == NULL) { - nl_perror("genlmsg_put"); - return -1; - } - - if (nla_put_u32(msg, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL) < 0) { - nl_perror("nla_put_u32(CTRL_ATTR_FAMILY_ID)"); - return -1; - } - - if (nl_send_auto_complete(h, msg) < 0) { - nl_perror("nl_send_auto_complete"); - return -1; - } - - if (nl_recvmsgs_default(h) < 0) { - nl_perror("nl_recvmsgs_def"); - return -1; - } + if (hdr == NULL) + fatal(ENOMEM, "Unable to write genl header"); - nlmsg_free(msg); + if ((err = nla_put_u32(msg, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL)) < 0) + fatal(err, "Unable to add attribute: %s", nl_geterror(err)); - nl_close(h); + if ((err = nl_send_auto_complete(sock, msg)) < 0) + fatal(err, "Unable to send message: %s", nl_geterror(err)); + + if ((err = nl_recvmsgs_default(sock)) < 0) + fatal(err, "Unable to receive message: %s", nl_geterror(err)); + + nlmsg_free(msg); + nl_close(sock); + nl_socket_free(sock); return 0; } diff --git a/tests/test-nf-cache-mngr.c b/tests/test-nf-cache-mngr.c index 86cbabb..05485bf 100644 --- a/tests/test-nf-cache-mngr.c +++ b/tests/test-nf-cache-mngr.c @@ -12,7 +12,7 @@ static void change_cb(struct nl_cache *cache, struct nl_object *obj, if (!nl_addr_cmp(hack, nfnl_ct_get_src(ct, 1)) || !nl_addr_cmp(hack, nfnl_ct_get_dst(ct, 1))) { struct nl_dump_params dp = { - .dp_type = NL_DUMP_BRIEF, + .dp_type = NL_DUMP_LINE, .dp_fd = stdout, }; @@ -24,14 +24,12 @@ static void change_cb(struct nl_cache *cache, struct nl_object *obj, int main(int argc, char *argv[]) { struct nl_cache_mngr *mngr; - struct nl_handle *handle; + struct nl_sock *sock; struct nl_cache *ct; - nltool_init(argc, argv); + sock = nlt_socket_alloc(); - handle = nltool_alloc_handle(); - - mngr = nl_cache_mngr_alloc(handle, NETLINK_NETFILTER, NL_AUTO_PROVIDE); + mngr = nl_cache_mngr_alloc(sock, NETLINK_NETFILTER, NL_AUTO_PROVIDE); if (!mngr) { nl_perror("nl_cache_mngr_alloc"); return -1; diff --git a/tests/test-socket-creation.c b/tests/test-socket-creation.c index 4066eef..a170ccd 100644 --- a/tests/test-socket-creation.c +++ b/tests/test-socket-creation.c @@ -2,7 +2,7 @@ int main(int argc, char *argv[]) { - struct nl_handle *h[1025]; + struct nl_sock *h[1025]; int i; h[0] = nl_handle_alloc(); |