summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJP Abgrall <jpa@google.com>2014-02-14 13:27:00 -0800
committerJP Abgrall <jpa@google.com>2014-02-14 13:27:00 -0800
commit823435f737de20d5ca9f4aa2ba0ae2950dbb5d4f (patch)
treee146cd87948eb11eb195d463b49dc8b1bdeb0db0
parent0021213ea39d6a889b6ed6e24dc1c2142ae175bf (diff)
parent515d3af751f58f1645d09f0a750b759cdc7820c3 (diff)
downloadandroid_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
-rw-r--r--.gitignore37
-rw-r--r--Android.mk7
-rw-r--r--Makefile64
-rw-r--r--Makefile.am20
-rw-r--r--Makefile.opts.in39
-rw-r--r--Makefile.rules37
-rw-r--r--aclocal.m4831
-rwxr-xr-xautogen.sh4
-rw-r--r--configure.in81
-rw-r--r--doc/Doxyfile.in1
-rw-r--r--doc/Makefile35
-rw-r--r--doc/Makefile.am9
-rw-r--r--doc/libnl.css297
-rw-r--r--etc/pktloc44
-rw-r--r--include/Makefile38
-rw-r--r--include/Makefile.am63
-rw-r--r--include/linux/if_bad.h6
-rw-r--r--include/linux/if_vlan.h61
-rw-r--r--include/linux/netfilter.h39
-rw-r--r--include/linux/netfilter/nfnetlink.h8
-rw-r--r--include/linux/netfilter/nfnetlink_log.h1
-rw-r--r--include/linux/netfilter/nfnetlink_queue.h94
-rw-r--r--include/linux/pkt_cls.h78
-rw-r--r--include/linux/rtnetlink.h49
-rw-r--r--include/netlink-local.h260
-rw-r--r--include/netlink-tc.h13
-rw-r--r--include/netlink-types.h187
-rw-r--r--include/netlink/.gitignore1
-rw-r--r--include/netlink/addr.h7
-rw-r--r--include/netlink/attr.h238
-rw-r--r--include/netlink/cache-api.h4
-rw-r--r--include/netlink/cache.h37
-rw-r--r--include/netlink/cli/addr.h32
-rw-r--r--include/netlink/cli/ct.h34
-rw-r--r--include/netlink/cli/link.h30
-rw-r--r--include/netlink/cli/neigh.h27
-rw-r--r--include/netlink/cli/qdisc.h28
-rw-r--r--include/netlink/cli/route.h34
-rw-r--r--include/netlink/cli/rule.h21
-rw-r--r--include/netlink/cli/utils.h (renamed from src/utils.h)57
-rw-r--r--include/netlink/data.h3
-rw-r--r--include/netlink/errno.h60
-rw-r--r--include/netlink/fib_lookup/lookup.h9
-rw-r--r--include/netlink/genl/ctrl.h7
-rw-r--r--include/netlink/genl/genl.h6
-rw-r--r--include/netlink/genl/mngt.h9
-rw-r--r--include/netlink/handlers.h13
-rw-r--r--include/netlink/list.h8
-rw-r--r--include/netlink/msg.h6
-rw-r--r--include/netlink/netfilter/ct.h127
-rw-r--r--include/netlink/netfilter/log.h112
-rw-r--r--include/netlink/netfilter/log_msg.h98
-rw-r--r--include/netlink/netfilter/netfilter.h31
-rw-r--r--include/netlink/netfilter/nfnl.h6
-rw-r--r--include/netlink/netfilter/queue.h90
-rw-r--r--include/netlink/netfilter/queue_msg.h104
-rw-r--r--include/netlink/netlink.h32
-rw-r--r--include/netlink/object-api.h26
-rw-r--r--include/netlink/object.h11
-rw-r--r--include/netlink/route/addr.h86
-rw-r--r--include/netlink/route/class-modules.h4
-rw-r--r--include/netlink/route/class.h21
-rw-r--r--include/netlink/route/classifier-modules.h16
-rw-r--r--include/netlink/route/classifier.h40
-rw-r--r--include/netlink/route/cls/basic.h33
-rw-r--r--include/netlink/route/cls/cgroup.h31
-rw-r--r--include/netlink/route/cls/ematch.h73
-rw-r--r--include/netlink/route/cls/ematch/cmp.h31
-rw-r--r--include/netlink/route/link.h136
-rw-r--r--include/netlink/route/link/info-api.h4
-rw-r--r--include/netlink/route/neighbour.h42
-rw-r--r--include/netlink/route/neightbl.h11
-rw-r--r--include/netlink/route/nexthop.h32
-rw-r--r--include/netlink/route/pktloc.h44
-rw-r--r--include/netlink/route/qdisc-modules.h6
-rw-r--r--include/netlink/route/qdisc.h96
-rw-r--r--include/netlink/route/route.h157
-rw-r--r--include/netlink/route/rtnl.h6
-rw-r--r--include/netlink/route/rule.h23
-rw-r--r--include/netlink/route/sch/htb.h6
-rw-r--r--include/netlink/route/sch/netem.h13
-rw-r--r--include/netlink/socket.h60
-rw-r--r--include/netlink/types.h14
-rw-r--r--include/netlink/utils.h11
-rw-r--r--include/netlink/version.h18
-rw-r--r--include/netlink/version.h.in18
-rwxr-xr-xinstall-sh294
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/Makefile76
-rw-r--r--lib/Makefile.am57
-rw-r--r--lib/addr.c105
-rw-r--r--lib/attr.c1021
-rw-r--r--lib/cache.c131
-rw-r--r--lib/cache_mngr.c102
-rw-r--r--lib/cache_mngt.c25
-rw-r--r--lib/data.c22
-rw-r--r--lib/defs.h.in28
-rw-r--r--lib/doc.c382
-rw-r--r--lib/error.c110
-rw-r--r--lib/family.c62
-rw-r--r--lib/fib_lookup/lookup.c57
-rw-r--r--lib/fib_lookup/request.c8
-rw-r--r--lib/genl/ctrl.c43
-rw-r--r--lib/genl/family.c40
-rw-r--r--lib/genl/genl.c21
-rw-r--r--lib/genl/mngt.c34
-rw-r--r--lib/handlers.c74
-rw-r--r--lib/msg.c68
-rw-r--r--lib/netfilter/ct.c237
-rw-r--r--lib/netfilter/ct_obj.c240
-rw-r--r--lib/netfilter/log.c353
-rw-r--r--lib/netfilter/log_msg.c209
-rw-r--r--lib/netfilter/log_msg_obj.c458
-rw-r--r--lib/netfilter/log_obj.c426
-rw-r--r--lib/netfilter/netfilter.c53
-rw-r--r--lib/netfilter/nfnl.c23
-rw-r--r--lib/netfilter/queue.c251
-rw-r--r--lib/netfilter/queue_msg.c284
-rw-r--r--lib/netfilter/queue_msg_obj.c492
-rw-r--r--lib/netfilter/queue_obj.c215
-rw-r--r--lib/nl.c368
-rw-r--r--lib/object.c29
-rw-r--r--lib/route/.gitignore4
-rw-r--r--lib/route/addr.c514
-rw-r--r--lib/route/class.c147
-rw-r--r--lib/route/class_api.c6
-rw-r--r--lib/route/class_obj.c52
-rw-r--r--lib/route/cls.c (renamed from lib/route/classifier.c)159
-rw-r--r--lib/route/cls/basic.c211
-rw-r--r--lib/route/cls/cgroup.c141
-rw-r--r--lib/route/cls/ematch.c410
-rw-r--r--lib/route/cls/ematch/cmp.c116
-rw-r--r--lib/route/cls/ematch/container.c39
-rw-r--r--lib/route/cls/fw.c143
-rw-r--r--lib/route/cls/u32.c234
-rw-r--r--lib/route/cls_api.c6
-rw-r--r--lib/route/cls_obj.c122
-rw-r--r--lib/route/link.c343
-rw-r--r--lib/route/link/api.c8
-rw-r--r--lib/route/link/vlan.c100
-rw-r--r--lib/route/neigh.c325
-rw-r--r--lib/route/neightbl.c193
-rw-r--r--lib/route/nexthop.c239
-rw-r--r--lib/route/pktloc.c168
-rw-r--r--lib/route/pktloc_grammar.l42
-rw-r--r--lib/route/pktloc_syntax.y108
-rw-r--r--lib/route/qdisc.c159
-rw-r--r--lib/route/qdisc_api.c4
-rw-r--r--lib/route/qdisc_obj.c49
-rw-r--r--lib/route/route.c354
-rw-r--r--lib/route/route_obj.c1080
-rw-r--r--lib/route/route_utils.c33
-rw-r--r--lib/route/rtnl.c11
-rw-r--r--lib/route/rule.c328
-rw-r--r--lib/route/sch/cbq.c100
-rw-r--r--lib/route/sch/dsmark.c68
-rw-r--r--lib/route/sch/fifo.c28
-rw-r--r--lib/route/sch/htb.c59
-rw-r--r--lib/route/sch/netem.c444
-rw-r--r--lib/route/sch/prio.c66
-rw-r--r--lib/route/sch/red.c33
-rw-r--r--lib/route/sch/sfq.c41
-rw-r--r--lib/route/sch/tbf.c65
-rw-r--r--lib/route/tc.c78
-rw-r--r--lib/socket.c405
-rw-r--r--lib/utils.c444
-rw-r--r--libnl-2.0.pc.in (renamed from libnl-1.pc.in)6
-rw-r--r--m4/.gitignore2
-rw-r--r--src/.gitignore24
-rw-r--r--src/COPYING676
-rw-r--r--src/Makefile45
-rw-r--r--src/Makefile.am101
-rw-r--r--src/cls/basic.c90
-rw-r--r--src/cls/cgroup.c78
-rw-r--r--src/cls/utils.c105
-rw-r--r--src/cls/utils.h51
-rw-r--r--src/disabled-nl-qdisc-add.c (renamed from src/nl-qdisc-add.c)2
-rw-r--r--src/f_addr.c107
-rw-r--r--src/f_ct.c170
-rw-r--r--src/f_link.c106
-rw-r--r--src/f_neigh.c51
-rw-r--r--src/f_route.c81
-rw-r--r--src/genl-ctrl-dump.c65
-rw-r--r--src/genl-ctrl-list.c69
-rw-r--r--src/lib/Makefile.am41
-rw-r--r--src/lib/addr.c135
-rw-r--r--src/lib/ct.c162
-rw-r--r--src/lib/link.c73
-rw-r--r--src/lib/neigh.c88
-rw-r--r--src/lib/qdisc.c72
-rw-r--r--src/lib/route.c270
-rw-r--r--src/lib/rule.c55
-rw-r--r--src/lib/utils.c147
-rw-r--r--src/nf-ct-dump.c91
-rw-r--r--src/nf-ct-list.c136
-rw-r--r--src/nf-log.c145
-rw-r--r--src/nf-monitor.c66
-rw-r--r--src/nf-queue.c172
-rw-r--r--src/nl-addr-add.c156
-rw-r--r--src/nl-addr-delete.c170
-rw-r--r--src/nl-addr-dump.c82
-rw-r--r--src/nl-addr-list.c193
-rw-r--r--src/nl-cls-add.c117
-rw-r--r--src/nl-cls-delete.c133
-rw-r--r--src/nl-cls-list.c113
-rw-r--r--src/nl-fib-lookup.c51
-rw-r--r--src/nl-link-dump.c75
-rw-r--r--src/nl-link-ifindex2name.c59
-rw-r--r--src/nl-link-list.c106
-rw-r--r--src/nl-link-name2ifindex.c52
-rw-r--r--src/nl-link-set.c155
-rw-r--r--src/nl-link-stats.c130
-rw-r--r--src/nl-list-caches.c7
-rw-r--r--src/nl-list-sockets.c19
-rw-r--r--src/nl-monitor.c50
-rw-r--r--src/nl-neigh-add.c149
-rw-r--r--src/nl-neigh-delete.c140
-rw-r--r--src/nl-neigh-dump.c82
-rw-r--r--src/nl-neigh-list.c89
-rw-r--r--src/nl-neightbl-dump.c70
-rw-r--r--src/nl-neightbl-list.c66
-rw-r--r--src/nl-pktloc-lookup.c37
-rw-r--r--src/nl-qdisc-delete.c140
-rw-r--r--src/nl-qdisc-dump.c74
-rw-r--r--src/nl-qdisc-list.c90
-rw-r--r--src/nl-route-add.c152
-rw-r--r--src/nl-route-del.c76
-rw-r--r--src/nl-route-delete.c168
-rw-r--r--src/nl-route-dump.c81
-rw-r--r--src/nl-route-get.c89
-rw-r--r--src/nl-route-list.c129
-rw-r--r--src/nl-rule-dump.c78
-rw-r--r--src/nl-rule-list.c77
-rw-r--r--src/nl-tctree-list.c (renamed from src/nl-tctree-dump.c)113
-rw-r--r--src/nl-util-addr.c19
-rw-r--r--src/utils.c178
-rw-r--r--tests/Makefile2
-rw-r--r--tests/test-cache-mngr.c68
-rw-r--r--tests/test-genl.c58
-rw-r--r--tests/test-nf-cache-mngr.c10
-rw-r--r--tests/test-socket-creation.c2
241 files changed, 16414 insertions, 9794 deletions
diff --git a/.gitignore b/.gitignore
index ce140c3..17a67a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/Android.mk b/Android.mk
index 4d61c47..b01e375 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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
diff --git a/lib/addr.c b/lib/addr.c
index 68f7741..1f000e7 100644
--- a/lib/addr.c
+++ b/lib/addr.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) {
diff --git a/lib/attr.c b/lib/attr.c
index 8568d32..298fbb1 100644
--- a/lib/attr.c
+++ b/lib/attr.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>
@@ -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);
diff --git a/lib/data.c b/lib/data.c
index 9399389..03cd9fe 100644
--- a/lib/data.c
+++ b/lib/data.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 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
diff --git a/lib/doc.c b/lib/doc.c
index 8fee8c8..7e68bb3 100644
--- a/lib/doc.c
+++ b/lib/doc.c
@@ -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;
}
diff --git a/lib/msg.c b/lib/msg.c
index 3d4fbc6..9fe9d54 100644
--- a/lib/msg.c
+++ b/lib/msg.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 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), &params) < 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,
+};
+
+/** @} */
diff --git a/lib/nl.c b/lib/nl.c
index b425302..c453b60 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -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, &params);
- 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, &params);
+
+ 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, &params, (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, &params, 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, &params, 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, &params);
+ }
+
+ 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, &params, (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,
+ &params);
+ else
+ nl_cache_dump_filter(addr_cache, &params, 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, &params, 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, &params);
+ }
+
+ 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, &params, 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, &params);
- 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, &params, (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, &params, 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), &params);
+ }
+}
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, &params, 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, &params);
}
- 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, &params, (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, &params, 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, &params);
- 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, &params);
+
+ 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, &params, 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, &params);
}
- 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, &params, (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, &params, 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, &params, 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, &params);
+ }
+
+ 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, &params, (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, &params);
+}
+
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, &params);
-
- 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, &params);
+
+ 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, &params, 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, &params, (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, &params, 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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
- 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();