Merge "libnl: Add to recovery" into main
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 708928e..6ad5fd2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,11 +4,14 @@
push:
pull_request:
+env:
+ NLTST_IN_CI: 1
+
jobs:
clang-format:
runs-on: ubuntu-latest
container:
- image: fedora:39
+ image: fedora:40
steps:
- name: Install packages
run: |
@@ -70,21 +73,24 @@
set -x
export CC="${{ matrix.cc }}"
- export CFLAGS="-DNL_MORE_ASSERTS=1000 -O2 -Werror -Wall -Wdeclaration-after-statement -Wvla -std=gnu11 -fexceptions"
+ export CFLAGS="-DNL_MORE_ASSERTS=1000 -O2 -Werror -std=gnu11 -fexceptions"
+ CONFIGURE_ARGS=
if [ "$CC" = "clang" ]; then
CFLAGS="$CFLAGS -Wno-error=unused-command-line-argument -Wno-error=unused-function"
export LDFLAGS="-Wl,--no-undefined-version,--fatal-warnings"
+ CONFIGURE_ARGS="--enable-debug=no"
else
export LDFLAGS="-Wl,--no-undefined-version"
fi
./autogen.sh
- ./configure
- make -j 5
+ ./configure $CONFIGURE_ARGS
+ make -j 15
shell: bash
- name: Build Unit Tests
- run: make -j 5 check-progs
+ run: |
+ make -j 15 check-build
- name: Run Unit Tests
run: |
@@ -93,7 +99,7 @@
for i in `seq 1 5`; do
tests/check-direct
tests/check-all
- make -j check
+ make -j 15 check || (cat ./test-suite.log; false)
done
- name: Run Unit Tests w/Valgrind
@@ -128,7 +134,7 @@
set -x
git clean -fdx
export CC="${{ matrix.cc }}"
- export CFLAGS="-Werror -Wall -Wdeclaration-after-statement -Wvla -std=gnu11 -fexceptions"
+ export CFLAGS="-Werror -std=gnu11 -fexceptions"
if [ "$CC" = "clang" ]; then
CFLAGS="$CFLAGS -Wno-error=unused-command-line-argument -Wno-error=unused-function"
fi
@@ -137,10 +143,10 @@
mkdir build
cd build
../configure --disable-static
- make -j 5
- make -j 5 check-progs
+ make -j 15
+ make -j 15 check-build
export NLTST_SEED_RAND=
- make -j 5 check
+ make -j 15 check || (cat ./test-suite.log; false)
- name: Link with mold
run: |
@@ -150,7 +156,7 @@
export LDFLAGS="-fuse-ld=mold -Wl,--fatal-warnings"
./autogen.sh
./configure
- make -j 5 V=1
+ make -j 15 V=1
- run: echo "🍏 This job's status is ${{ job.status }}."
@@ -188,7 +194,7 @@
set -x
export CC="${{ matrix.cc }}"
- export CFLAGS="-DNL_MORE_ASSERTS=1000 -O2 -Werror -Wall -Wdeclaration-after-statement -Wvla -std=gnu11 -fexceptions"
+ export CFLAGS="-DNL_MORE_ASSERTS=1000 -O2 -Werror -std=gnu11 -fexceptions"
if [ "$CC" = "clang" ]; then
CFLAGS="$CFLAGS -Wno-error=unused-command-line-argument -Wno-error=unused-function"
export LDFLAGS="-Wl,--no-undefined-version,--fatal-warnings"
@@ -198,8 +204,11 @@
./autogen.sh
./configure
- make -j 5
- make -j 5 check-progs
+ make -j 15
+
+ - name: Build Unit Tests
+ run: |
+ make -j 15 check-build
- name: Run Unit Tests
run: |
@@ -210,5 +219,5 @@
# unshare() does not work (EPERM). This test currently cannot pass
# (odd).
# tests/check-all
- # make -j check
+ # make -j 15 check || (cat ./test-suite.log; false)
done
diff --git a/Android.bp b/Android.bp
index cd75e3f..e711be0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -98,11 +98,12 @@
"-Wno-pointer-arith",
"-UNDEBUG",
"-D_GNU_SOURCE",
- "-DSYSCONFDIR=\"\\\"/etc/libnl\\\"\"",
+ "-D_NL_SYSCONFDIR_LIBNL=\"\\\"/etc/libnl\\\"\"",
],
sanitize: {
integer_overflow: true,
+ blocklist: "libnl_blocklist.txt",
},
apex_available: [
"//apex_available:platform",
diff --git a/METADATA b/METADATA
index 5e52a66..8b03e00 100644
--- a/METADATA
+++ b/METADATA
@@ -8,13 +8,13 @@
license_type: RESTRICTED
last_upgrade_date {
year: 2024
- month: 4
+ month: 6
day: 4
}
homepage: "https://github.com/thom311/libnl"
identifier {
type: "Git"
value: "https://github.com/thom311/libnl.git"
- version: "libnl3_9_0"
+ version: "5248e1a45576617b349465997822cef34cbc5053"
}
}
diff --git a/Makefile.am b/Makefile.am
index 1e76649..227fa56 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,6 +9,7 @@
check_PROGRAMS =
check_programs =
check_local =
+check_build =
bin_PROGRAMS =
sbin_PROGRAMS =
@@ -34,11 +35,18 @@
warn_cppflags = \
-Wall \
-Wextra \
+ \
+ -Wdeclaration-after-statement \
-Wmissing-prototypes \
- -Wno-unused-parameter \
- -Wno-sign-compare \
- -Wno-missing-field-initializers \
-Wpointer-arith \
+ -Wvla \
+ \
+ -Wno-unused-parameter \
+ $(NULL)
+
+defines_cppflags = \
+ -D_NL_SYSCONFDIR_LIBNL=\"$(sysconfdir)/libnl\" \
+ -D_NL_PKGLIBDIR=\"$(pkglibdir)\" \
$(NULL)
###############################################################################
@@ -387,8 +395,7 @@
lib_cppflags = \
$(warn_cppflags) \
- -D_GNU_SOURCE \
- -DSYSCONFDIR=\"$(sysconfdir)/libnl\" \
+ $(defines_cppflags) \
$(default_includes) \
$(NULL)
@@ -705,9 +712,7 @@
libnl-cli-3.sym
src_lib_libnl_cli_3_la_CPPFLAGS = \
$(warn_cppflags) \
- -D_GNU_SOURCE \
- -DPKGLIBDIR=\"$(pkglibdir)\" \
- -DSYSCONFDIR=\"$(sysconfdir)\" \
+ $(defines_cppflags) \
$(default_includes) \
$(NULL)
src_lib_libnl_cli_3_la_LDFLAGS = \
@@ -725,8 +730,7 @@
src_cppflags = \
$(warn_cppflags) \
- -D_GNU_SOURCE \
- -DSYSCONFDIR=\"$(sysconfdir)/libnl\" \
+ $(defines_cppflags) \
$(default_includes) \
$(NULL)
@@ -905,8 +909,7 @@
tests_cppflags = \
$(warn_cppflags) \
- -D_GNU_SOURCE \
- -DSYSCONFDIR=\"$(sysconfdir)/libnl\" \
+ $(defines_cppflags) \
$(default_includes) \
$(NULL)
@@ -1136,24 +1139,43 @@
%.build-headers-test.c: %
mkdir -p "$(dir $@)"
- printf "#include <$$(echo "$<" | sed 's|.*\<include/netlink/|netlink/|')>\nint main(int argc, char **argv) { return 0; }" > $@
+ printf "#include <$$(echo "$<" | sed 's|.*\<include/netlink/|netlink/|')>\nint main(void) { return 0; }" > $@
%.build-headers-test.o: %.build-headers-test.c
- $(COMPILE) -Wall -Werror -Wno-error=cpp -I$(srcdir)/include -I$(builddir)/include -c -o $@ $<
+ $(CC) -Wall -Werror -D_NL_NO_WARN_DEPRECATED_HEADER -I$(srcdir)/include -I$(builddir)/include -c -o $@ $<
BUILD_HEADERS_OBJS = $(patsubst %,%.build-headers-test.o,$(public_headers))
# Test whether the public headers are all self-contained and can be build.
# This test is not hooked up as `make check`.
-check-local-build-headers: $(BUILD_HEADERS_OBJS)
+check-build-headers: $(BUILD_HEADERS_OBJS)
CLEANFILES += $(BUILD_HEADERS_OBJS)
-check_local += check-local-build-headers
+check_build += check-build-headers
###############################################################################
-check-local: $(check_local)
+if HAS_CXX
+%.build-headers-test-cxx.cpp: %
+ mkdir -p "$(dir $@)"
+ printf "#include <cstdio>\n#include <$$(echo "$<" | sed 's|.*\<include/netlink/|netlink/|')>\nint main(void) { return 0; }" > $@
+
+%.build-headers-test-cxx.o: %.build-headers-test-cxx.cpp %.build-headers-test.o
+ $(CXX) -Wall -Werror -D_NL_NO_WARN_DEPRECATED_HEADER -I$(srcdir)/include -I$(builddir)/include -c -o $@ $<
+
+BUILD_HEADERS_OBJS_CXX = $(patsubst %,%.build-headers-test-cxx.o,$(public_headers))
+
+CLEANFILES += $(BUILD_HEADERS_OBJS_CXX)
+
+check-build-headers-cxx: $(BUILD_HEADERS_OBJS_CXX)
+
+check_build += check-build-headers-cxx
+endif
+
+###############################################################################
+
+check-local: $(check_build) $(check_local)
.PHONY: $(check_local)
@@ -1182,8 +1204,10 @@
###############################################################################
-check-progs: all $(check_PROGRAMS) $(check_LTLIBRARIES)
+check-build: all $(check_PROGRAMS) $(check_LTLIBRARIES) $(check_build)
-.PHONY: check-progs
+check-progs: check-build
+
+.PHONY: check-progs check-build
###############################################################################
diff --git a/configure.ac b/configure.ac
index bc8b390..4db4385 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,8 +61,11 @@
LT_AGE=libnl_lt_age
AC_SUBST(LT_AGE)
+AC_USE_SYSTEM_EXTENSIONS
+
AC_PROG_CC
AM_PROG_CC_C_O
+AC_PROG_CXX
AC_PROG_INSTALL
LT_INIT
AC_PROG_MKDIR_P
@@ -72,6 +75,15 @@
AC_C_CONST
AC_C_INLINE
+AC_LANG_PUSH([C++])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+ [[#ifndef __cplusplus
+ #error "broken C++"
+ #endif]])],,
+ [CXX=;])
+AC_LANG_POP([C++])
+AM_CONDITIONAL([HAS_CXX], [test "x$CXX" != x])
+
PKG_CHECK_MODULES([CHECK], [check >= 0.9.0],
[has_check="yes"],
[AC_MSG_WARN([*** Disabling building of unit tests])
@@ -110,10 +122,13 @@
AM_CONDITIONAL([ENABLE_STATIC], [test "$enable_static" != "no"])
AC_ARG_ENABLE([debug],
- AS_HELP_STRING([--disable-debug], [Do not include debugging statements]),
- [enable_debug="$enableval"], [enable_debug="yes"])
-if test "x$enable_debug" = "xyes"; then
+ AS_HELP_STRING([--disable-debug], [Do not include debugging statements]),
+ [enable_debug="$enableval"], [enable_debug="yes"])
+if test "$enable_debug" = "yes"; then
AC_DEFINE([NL_DEBUG], [1], [Define to 1 to enable debugging])
+else
+ enable_debug=no
+ AC_DEFINE([NL_DEBUG], [0], [Define to 1 to enable debugging])
fi
AC_CONFIG_SUBDIRS([doc])
@@ -152,6 +167,11 @@
AC_OUTPUT
+CXX_MSG="none"
+if test "x$CXX" != x ; then
+ CXX_MSG="[$CXX]"
+fi
+
echo
echo "libnl $LIBNL_VERSION configuration${LIBNL_GIT_SHA:+ (git:$LIBNL_GIT_SHA)}:"
echo " --enable-pthreads=$enable_pthreads"
@@ -161,4 +181,5 @@
echo " --enable-cli=$enable_cli"
echo
echo " check: $has_check"
+echo " CXX: $CXX_MSG (only used for tests)"
echo
diff --git a/include/base/nl-base-utils.h b/include/base/nl-base-utils.h
index 03d568e..a2bedee 100644
--- a/include/base/nl-base-utils.h
+++ b/include/base/nl-base-utils.h
@@ -754,10 +754,7 @@
const char *a;
};
-#define __ADD(id, name) \
- { \
- .i = id, .a = #name \
- }
+#define __ADD(id, name) { .i = id, .a = #name }
#define BUG() \
do { \
@@ -816,8 +813,8 @@
}
#else
-#define NL_LOCK(NAME) int __unused_lock_##NAME __attribute__((unused))
-#define NL_RW_LOCK(NAME) int __unused_lock_##NAME __attribute__((unused))
+#define NL_LOCK(NAME) int __unused_lock_##NAME _nl_unused
+#define NL_RW_LOCK(NAME) int __unused_lock_##NAME _nl_unused
#define nl_lock(LOCK) \
do { \
diff --git a/include/config.h b/include/config.h
index a64cb61..3ce6d50 100644
--- a/include/config.h
+++ b/include/config.h
@@ -56,7 +56,7 @@
#undef LT_OBJDIR
/* Define to 1 to enable debugging */
-#undef NL_DEBUG
+#define NL_DEBUG 0
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
diff --git a/include/netlink/cache-api.h b/include/netlink/cache-api.h
index 851eca0..e8a4170 100644
--- a/include/netlink/cache-api.h
+++ b/include/netlink/cache-api.h
@@ -9,6 +9,8 @@
#include <netlink/netlink.h>
#include <netlink/cache.h>
+#ifndef _NL_NO_WARN_DEPRECATED_HEADER
#warning "You are including a deprecated header file, include <netlink/cache.h>."
+#endif
#endif
diff --git a/include/netlink/cache.h b/include/netlink/cache.h
index abeeccb..955f979 100644
--- a/include/netlink/cache.h
+++ b/include/netlink/cache.h
@@ -140,12 +140,16 @@
struct nl_cache_mngr;
-#define NL_AUTO_PROVIDE 1
-#define NL_ALLOCATED_SOCK 2 /* For internal use only, do not use */
+#define NL_AUTO_PROVIDE 1
+#define NL_ALLOCATED_SOCK 2 /* For internal use only, do not use */
extern int nl_cache_mngr_alloc(struct nl_sock *,
int, int,
struct nl_cache_mngr **);
+extern int nl_cache_mngr_alloc_ex(struct nl_sock *,
+ struct nl_sock *,
+ int, int,
+ struct nl_cache_mngr **);
extern int nl_cache_mngr_add(struct nl_cache_mngr *,
const char *,
change_func_t,
diff --git a/include/netlink/route/link/api.h b/include/netlink/route/link/api.h
index abdd8b2..ef11d2f 100644
--- a/include/netlink/route/link/api.h
+++ b/include/netlink/route/link/api.h
@@ -9,6 +9,8 @@
#include <netlink/netlink.h>
#include <netlink/route/link.h>
+#ifndef _NL_NO_WARN_DEPRECATED_HEADER
#warning "You are including a deprecated header file, include <netlink/route/link.h>."
+#endif
#endif
diff --git a/include/netlink/route/link/bridge.h b/include/netlink/route/link/bridge.h
index e606bd4..0de59c4 100644
--- a/include/netlink/route/link/bridge.h
+++ b/include/netlink/route/link/bridge.h
@@ -61,6 +61,7 @@
extern int rtnl_link_bridge_get_flags(struct rtnl_link *);
extern int rtnl_link_bridge_set_self(struct rtnl_link *);
+extern int rtnl_link_bridge_set_master(struct rtnl_link *);
extern int rtnl_link_bridge_get_hwmode(struct rtnl_link *, uint16_t *);
extern int rtnl_link_bridge_set_hwmode(struct rtnl_link *, uint16_t);
@@ -76,6 +77,10 @@
extern int rtnl_link_bridge_add(struct nl_sock *sk, const char *name);
+extern int rtnl_link_bridge_enable_vlan(struct rtnl_link *link);
+extern int rtnl_link_bridge_set_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end, int untagged);
+extern int rtnl_link_bridge_unset_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end);
+extern int rtnl_link_bridge_set_port_vlan_pvid (struct rtnl_link *link, uint16_t pvid);
extern int rtnl_link_bridge_pvid(struct rtnl_link *link);
extern int rtnl_link_bridge_has_vlan(struct rtnl_link *link);
diff --git a/include/netlink/route/link/bridge_info.h b/include/netlink/route/link/bridge_info.h
index 09689b3..bb7bf0b 100644
--- a/include/netlink/route/link/bridge_info.h
+++ b/include/netlink/route/link/bridge_info.h
@@ -13,6 +13,11 @@
extern "C" {
#endif
+extern void rtnl_link_bridge_set_ageing_time(struct rtnl_link *link,
+ uint32_t ageing_time);
+extern int rtnl_link_bridge_get_ageing_time(struct rtnl_link *link,
+ uint32_t *ageing_time);
+
extern void rtnl_link_bridge_set_vlan_filtering(struct rtnl_link *link,
uint8_t vlan_filtering);
extern int rtnl_link_bridge_get_vlan_filtering(struct rtnl_link *link,
@@ -23,10 +28,21 @@
extern int rtnl_link_bridge_get_vlan_protocol(struct rtnl_link *link,
uint16_t *vlan_protocol);
+extern void rtnl_link_bridge_set_vlan_default_pvid(struct rtnl_link *link,
+ uint16_t default_pvid);
+extern int rtnl_link_bridge_get_vlan_default_pvid(struct rtnl_link *link,
+ uint16_t *default_pvid);
+
extern void rtnl_link_bridge_set_vlan_stats_enabled(struct rtnl_link *link,
uint8_t vlan_stats_enabled);
extern int rtnl_link_bridge_get_vlan_stats_enabled(struct rtnl_link *link,
uint8_t *vlan_stats_enabled);
+extern void rtnl_link_bridge_set_nf_call_iptables(struct rtnl_link *link,
+ uint8_t call_enabled);
+extern void rtnl_link_bridge_set_nf_call_ip6tables(struct rtnl_link *link,
+ uint8_t call_enabled);
+extern void rtnl_link_bridge_set_nf_call_arptables(struct rtnl_link *link,
+ uint8_t call_enabled);
#ifdef __cplusplus
}
diff --git a/include/netlink/route/link/info-api.h b/include/netlink/route/link/info-api.h
index 11cffcf..88461bb 100644
--- a/include/netlink/route/link/info-api.h
+++ b/include/netlink/route/link/info-api.h
@@ -9,6 +9,8 @@
#include <netlink/netlink.h>
#include <netlink/route/link.h>
+#ifndef _NL_NO_WARN_DEPRECATED_HEADER
#warning "You are including a deprecated header file, include <netlink/route/link.h>."
+#endif
#endif
diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h
index c4a2604..1beb9fa 100644
--- a/include/netlink/route/nexthop.h
+++ b/include/netlink/route/nexthop.h
@@ -30,6 +30,9 @@
struct rtnl_nexthop *,
uint32_t, int);
+extern int rtnl_route_nh_identical(struct rtnl_nexthop *,
+ struct rtnl_nexthop *);
+
extern void rtnl_route_nh_dump(struct rtnl_nexthop *,
struct nl_dump_params *);
diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h
index 3824762..4377062 100644
--- a/include/netlink/route/route.h
+++ b/include/netlink/route/route.h
@@ -94,6 +94,8 @@
extern void rtnl_route_set_ttl_propagate(struct rtnl_route *route,
uint8_t ttl_prop);
extern int rtnl_route_get_ttl_propagate(struct rtnl_route *route);
+extern void rtnl_route_set_nhid(struct rtnl_route *, uint32_t);
+extern uint32_t rtnl_route_get_nhid(struct rtnl_route *);
extern void rtnl_route_add_nexthop(struct rtnl_route *,
struct rtnl_nexthop *);
diff --git a/include/netlink/route/tc-api.h b/include/netlink/route/tc-api.h
index 3f400ba..36b1b0f 100644
--- a/include/netlink/route/tc-api.h
+++ b/include/netlink/route/tc-api.h
@@ -10,6 +10,8 @@
#include <netlink/msg.h>
#include <netlink/route/tc.h>
+#ifndef _NL_NO_WARN_DEPRECATED_HEADER
#warning "You are including a deprecated header file, include <netlink/route/tc.h>."
+#endif
#endif
diff --git a/include/netlink/utils.h b/include/netlink/utils.h
index 11a6b93..b3a5951 100644
--- a/include/netlink/utils.h
+++ b/include/netlink/utils.h
@@ -331,6 +331,24 @@
NL_CAPABILITY_VERSION_3_9_0 = 35,
#define NL_CAPABILITY_VERSION_3_9_0 NL_CAPABILITY_VERSION_3_9_0
+ /**
+ * The library version is libnl3 3.10.0 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_10_0 = 36,
+#define NL_CAPABILITY_VERSION_3_10_0 NL_CAPABILITY_VERSION_3_10_0
+
+ /**
+ * The library version is libnl3 3.11.0 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_11_0 = 37,
+#define NL_CAPABILITY_VERSION_3_11_0 NL_CAPABILITY_VERSION_3_11_0
+
+ /**
+ * The library version is libnl3 3.12.0 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_12_0 = 38,
+#define NL_CAPABILITY_VERSION_3_12_0 NL_CAPABILITY_VERSION_3_12_0
+
__NL_CAPABILITY_MAX,
NL_CAPABILITY_MAX = (__NL_CAPABILITY_MAX - 1),
#define NL_CAPABILITY_MAX NL_CAPABILITY_MAX
diff --git a/include/nl-aux-core/nl-core.h b/include/nl-aux-core/nl-core.h
index 5b34bcb..79cec27 100644
--- a/include/nl-aux-core/nl-core.h
+++ b/include/nl-aux-core/nl-core.h
@@ -5,21 +5,16 @@
#include "base/nl-base-utils.h"
-#ifdef NL_DEBUG
#define NL_DBG(LVL, FMT, ARG...) \
do { \
- if (LVL <= nl_debug) { \
- int _errsv = errno; \
+ if ((NL_DEBUG) && (LVL) <= nl_debug) { \
+ const int _errsv = errno; \
+ \
fprintf(stderr, "DBG<" #LVL ">%20s:%-4u %s: " FMT, \
__FILE__, __LINE__, __func__, ##ARG); \
errno = _errsv; \
} \
} while (0)
-#else /* NL_DEBUG */
-#define NL_DBG(LVL, FMT, ARG...) \
- do { \
- } while (0)
-#endif /* NL_DEBUG */
struct nl_addr;
void nl_addr_put(struct nl_addr *);
@@ -49,6 +44,12 @@
_NL_AUTO_DEFINE_FCN_TYPED0(struct nl_sock *, _nl_auto_nl_socket_fcn,
nl_socket_free);
+struct nl_cache_mngr;
+void nl_cache_mngr_free(struct nl_cache_mngr *mngr);
+#define _nl_auto_nl_cache_mngr _nl_auto(_nl_auto_nl_cache_mngr_fcn)
+_NL_AUTO_DEFINE_FCN_TYPED0(struct nl_cache_mngr *, _nl_auto_nl_cache_mngr_fcn,
+ nl_cache_mngr_free);
+
struct nl_addr *nl_addr_build(int, const void *, size_t);
static inline struct nl_addr *_nl_addr_build(int family, const void *buf)
@@ -56,4 +57,12 @@
return nl_addr_build(family, buf, _nl_addr_family_to_size(family));
}
+static inline uint16_t _nla_len(const struct nlattr *nla)
+{
+ _nl_assert(nla);
+ _nl_assert(nla->nla_len >= (uint16_t)NLA_HDRLEN);
+
+ return nla->nla_len - (uint16_t)NLA_HDRLEN;
+}
+
#endif /* NETLINK_NL_AUTO_H_ */
diff --git a/include/nl-priv-dynamic-route/nl-priv-dynamic-route.h b/include/nl-priv-dynamic-route/nl-priv-dynamic-route.h
index c8168a3..b6192a7 100644
--- a/include/nl-priv-dynamic-route/nl-priv-dynamic-route.h
+++ b/include/nl-priv-dynamic-route/nl-priv-dynamic-route.h
@@ -93,4 +93,19 @@
struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *);
+struct rtnl_nexthop {
+ uint8_t rtnh_flags;
+ uint8_t rtnh_flag_mask;
+ uint8_t rtnh_weight;
+ /* 1 byte spare */
+ uint32_t rtnh_ifindex;
+ struct nl_addr *rtnh_gateway;
+ uint32_t ce_mask; /* HACK to support attr macros */
+ struct nl_list_head rtnh_list;
+ uint32_t rtnh_realms;
+ struct nl_addr *rtnh_newdst;
+ struct nl_addr *rtnh_via;
+ struct rtnl_nh_encap *rtnh_encap;
+};
+
#endif /* __NL_PRIVATE_TYPES_NL_ROUTE_H__ */
diff --git a/include/nl-priv-static-route/nl-priv-static-route.h b/include/nl-priv-static-route/nl-priv-static-route.h
index 65ff531..ad9f98f 100644
--- a/include/nl-priv-static-route/nl-priv-static-route.h
+++ b/include/nl-priv-static-route/nl-priv-static-route.h
@@ -3,6 +3,10 @@
#ifndef NETLINK_ROUTE_UTILS_PRIV_H_
#define NETLINK_ROUTE_UTILS_PRIV_H_
+#include <netlink/route/link/bridge.h>
+
extern const uint8_t *const _nltst_map_stat_id_from_IPSTATS_MIB_v2;
+extern int _nl_bridge_fill_vlan_info(struct nl_msg *msg,
+ struct rtnl_link_bridge_vlan *vlan_info);
#endif
diff --git a/lib/addr.c b/lib/addr.c
index 89a3b38..a3e9f99 100644
--- a/lib/addr.c
+++ b/lib/addr.c
@@ -1042,8 +1042,8 @@
prefix:
if (addr->a_family != AF_MPLS &&
- addr->a_prefixlen != (8 * addr->a_len)) {
- snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
+ (unsigned)addr->a_prefixlen != (8u * ((size_t)addr->a_len))) {
+ snprintf(tmp, sizeof(tmp), "/%d", addr->a_prefixlen);
strncat(buf, tmp, size - strlen(buf) - 1);
}
diff --git a/lib/attr.c b/lib/attr.c
index b8b9837..a365cf2 100644
--- a/lib/attr.c
+++ b/lib/attr.c
@@ -129,7 +129,7 @@
*/
int nla_len(const struct nlattr *nla)
{
- return nla->nla_len - NLA_HDRLEN;
+ return _nla_len(nla);
}
/**
@@ -146,6 +146,8 @@
*/
int nla_ok(const struct nlattr *nla, int remaining)
{
+ _NL_STATIC_ASSERT(sizeof(*nla) == NLA_HDRLEN);
+
return remaining >= (int) sizeof(*nla) &&
nla->nla_len >= sizeof(*nla) &&
nla->nla_len <= remaining;
@@ -204,7 +206,7 @@
else if (pt->type != NLA_UNSPEC)
minlen = nla_attr_minlen[pt->type];
- if (nla_len(nla) < minlen)
+ if (_nla_len(nla) < minlen)
return -NLE_RANGE;
if (pt->maxlen && nla_len(nla) > pt->maxlen)
@@ -457,14 +459,14 @@
struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
{
struct nlattr *nla;
- int tlen;
+ size_t tlen;
if (attrlen < 0)
return NULL;
tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
- if (tlen > msg->nm_size)
+ if (tlen > msg->nm_size || tlen > UINT32_MAX)
return NULL;
nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
@@ -736,7 +738,7 @@
{
int64_t tmp = 0;
- if (nla && nla_len(nla) >= sizeof(tmp))
+ if (nla && _nla_len(nla) >= sizeof(tmp))
memcpy(&tmp, nla_data(nla), sizeof(tmp));
return tmp;
@@ -766,7 +768,7 @@
{
uint64_t tmp = 0;
- if (nla && nla_len(nla) >= sizeof(tmp))
+ if (nla && _nla_len(nla) >= sizeof(tmp))
memcpy(&tmp, nla_data(nla), sizeof(tmp));
return tmp;
diff --git a/lib/cache.c b/lib/cache.c
index dd059c1..bae641d 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -808,7 +808,7 @@
*/
if (nl_object_update(old, obj) == 0) {
if (cb_v2) {
- cb_v2(cache, clone, obj, diff,
+ cb_v2(cache, clone, old, diff,
NL_ACT_CHANGE, data);
nl_object_put(clone);
} else if (cb)
diff --git a/lib/cache_mngr.c b/lib/cache_mngr.c
index f16882f..8d8e262 100644
--- a/lib/cache_mngr.c
+++ b/lib/cache_mngr.c
@@ -37,6 +37,8 @@
#include "nl-priv-dynamic-core/cache-api.h"
#include "nl-aux-core/nl-core.h"
+#define NL_ALLOCATED_SYNC_SOCK 4
+
/** @cond SKIP */
struct nl_cache_mngr
{
@@ -58,10 +60,9 @@
struct nl_cache_ops *ops = ca->ca_cache->c_ops;
NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
-#ifdef NL_DEBUG
- if (nl_debug >= 4)
+
+ if (NL_DEBUG && nl_debug >= 4)
nl_object_dump(obj, &nl_debug_dp);
-#endif
if (ops->co_event_filter)
if (ops->co_event_filter(ca->ca_cache, obj) != NL_OK)
@@ -93,10 +94,9 @@
NL_DBG(2, "Cache manager %p, handling new message %p as event\n",
mngr, msg);
-#ifdef NL_DEBUG
- if (nl_debug >= 4)
+
+ if (NL_DEBUG && nl_debug >= 4)
nl_msg_dump(msg, stderr);
-#endif
if (mngr->cm_protocol != protocol)
BUG();
@@ -151,62 +151,75 @@
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;
+ return nl_cache_mngr_alloc_ex(sk, NULL, protocol, flags, result);
+}
+
+/**
+ * Allocate new cache manager, with custom callback on refill socket
+ * @arg sk Netlink socket or NULL to auto allocate
+ * @arg sync_sk Blocking Netlink socket for cache refills
+ * @arg protocol Netlink protocol this manager is used for
+ * @arg flags Flags (\c NL_AUTO_PROVIDE)
+ * @arg result Result pointer
+ *
+ * Same as \f nl_cache_mngr_alloc, but sets custom refill socket
+ * Note: ownership of the sync_sk passes to the cache manager
+ */
+int nl_cache_mngr_alloc_ex(struct nl_sock *sk, struct nl_sock *sync_sk, int protocol, int flags,
+ struct nl_cache_mngr **result)
+{
+ _nl_auto_nl_cache_mngr struct nl_cache_mngr *mngr = NULL;
+ int err;
/* Catch abuse of flags */
if (flags & NL_ALLOCATED_SOCK)
BUG();
+ flags = flags & NL_AUTO_PROVIDE;
mngr = calloc(1, sizeof(*mngr));
if (!mngr)
return -NLE_NOMEM;
+ mngr->cm_flags = flags;
+
if (!sk) {
if (!(sk = nl_socket_alloc()))
- goto errout;
-
- flags |= NL_ALLOCATED_SOCK;
+ return -NLE_NOMEM;
+ mngr->cm_flags |= NL_ALLOCATED_SOCK;
}
-
mngr->cm_sock = sk;
+
+ if(!sync_sk) {
+ if (!(sync_sk = nl_socket_alloc()))
+ return -NLE_NOMEM;
+ mngr->cm_flags |= NL_ALLOCATED_SYNC_SOCK;
+ }
+ mngr->cm_sync_sock = sync_sk;
+
mngr->cm_nassocs = NASSOC_INIT;
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 errout;
+ return -NLE_NOMEM;
/* Required to receive async event notifications */
nl_socket_disable_seq_check(mngr->cm_sock);
if ((err = nl_connect(mngr->cm_sock, protocol)) < 0)
- goto errout;
+ return err;
if ((err = nl_socket_set_nonblocking(mngr->cm_sock)) < 0)
- goto errout;
+ return err;
- /* Create and allocate socket for sync cache fills */
- mngr->cm_sync_sock = nl_socket_alloc();
- if (!mngr->cm_sync_sock) {
- err = -NLE_NOMEM;
- goto errout;
- }
if ((err = nl_connect(mngr->cm_sync_sock, protocol)) < 0)
- goto errout_free_sync_sock;
+ return err;
NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
mngr, protocol, mngr->cm_nassocs);
- *result = mngr;
+ *result = _nl_steal_pointer(&mngr);
return 0;
-
-errout_free_sync_sock:
- nl_socket_free(mngr->cm_sync_sock);
-errout:
- nl_cache_mngr_free(mngr);
- return err;
}
/**
@@ -624,14 +637,15 @@
if (mngr->cm_sock)
nl_close(mngr->cm_sock);
- if (mngr->cm_sync_sock) {
+ if (mngr->cm_sync_sock)
nl_close(mngr->cm_sync_sock);
- nl_socket_free(mngr->cm_sync_sock);
- }
if (mngr->cm_flags & NL_ALLOCATED_SOCK)
nl_socket_free(mngr->cm_sock);
+ if (mngr->cm_flags & NL_ALLOCATED_SYNC_SOCK)
+ nl_socket_free(mngr->cm_sync_sock);
+
for (i = 0; i < mngr->cm_nassocs; i++) {
if (mngr->cm_assocs[i].ca_cache) {
nl_cache_mngt_unprovide(mngr->cm_assocs[i].ca_cache);
diff --git a/lib/fib_lookup/lookup.c b/lib/fib_lookup/lookup.c
index 7ff2684..260f1d9 100644
--- a/lib/fib_lookup/lookup.c
+++ b/lib/fib_lookup/lookup.c
@@ -236,7 +236,7 @@
fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
fr.fl_tos = tos >= 0 ? tos : 0;
fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
- fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
+ fr.tb_id_in = table >= 0 ? (unsigned)table : (unsigned)RT_TABLE_UNSPEC;
addr = flnl_request_get_addr(req);
if (!addr)
diff --git a/lib/genl/genl.c b/lib/genl/genl.c
index 2e52aae..41add3a 100644
--- a/lib/genl/genl.c
+++ b/lib/genl/genl.c
@@ -116,12 +116,14 @@
int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
{
struct genlmsghdr *ghdr;
+ int l;
if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
return 0;
ghdr = nlmsg_data(nlh);
- if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
+ l = genlmsg_len(ghdr);
+ if (l < 0 || ((unsigned)l) < NLMSG_ALIGN(hdrlen))
return 0;
return 1;
diff --git a/lib/genl/mngt.c b/lib/genl/mngt.c
index e55256c..06a0253 100644
--- a/lib/genl/mngt.c
+++ b/lib/genl/mngt.c
@@ -248,7 +248,7 @@
goto errout;
}
- if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
+ if (ops->co_hdrsize < (int)GENL_HDRSIZE(0)) {
err = -NLE_INVAL;
goto errout;
}
diff --git a/lib/mpls.c b/lib/mpls.c
index d0189bf..f5b4f27 100644
--- a/lib/mpls.c
+++ b/lib/mpls.c
@@ -26,7 +26,7 @@
uint32_t label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
int len = snprintf(dest, destlen, "%u", label);
- if (len >= destlen)
+ if (len < 0 || (unsigned)len >= destlen)
break;
/* Is this the end? */
diff --git a/lib/msg.c b/lib/msg.c
index 0e1592a..64e6b2f 100644
--- a/lib/msg.c
+++ b/lib/msg.c
@@ -36,7 +36,7 @@
#include "nl-priv-dynamic-core/cache-api.h"
#include "nl-aux-core/nl-core.h"
-static size_t default_msg_size;
+static size_t default_msg_size; /* GLOBAL! */
static void _nl_init init_msg_size(void)
{
@@ -168,7 +168,10 @@
int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
{
- if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+ int s;
+
+ s = nlmsg_msg_size(hdrlen);
+ if (s < 0 || nlh->nlmsg_len < ((unsigned)s))
return 0;
return 1;
@@ -183,7 +186,7 @@
{
return (remaining >= (int)sizeof(struct nlmsghdr) &&
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
- nlh->nlmsg_len <= remaining);
+ nlh->nlmsg_len <= ((unsigned)remaining));
}
/**
@@ -369,8 +372,11 @@
*/
void nlmsg_set_default_size(size_t max)
{
- if (max < nlmsg_total_size(0))
- max = nlmsg_total_size(0);
+ size_t s;
+
+ s = nlmsg_total_size(0);
+ if (max < s)
+ max = s;
default_msg_size = max;
}
@@ -841,7 +847,7 @@
{
char *data = nlmsg_data(hdr);
- if (*payloadlen < GENL_HDRLEN)
+ if (*payloadlen < (int)GENL_HDRLEN)
return data;
print_genl_hdr(ofd, data);
@@ -917,10 +923,12 @@
{
struct nlmsghdr *hdr = nlmsg_hdr(msg);
struct nlmsgerr *err = nlmsg_data(hdr);
+ int l;
fprintf(ofd, " [ERRORMSG] %zu octets\n", sizeof(*err));
- if (nlmsg_len(hdr) >= sizeof(*err)) {
+ l = nlmsg_len(hdr);
+ if (l >= 0 && ((unsigned)l) >= sizeof(*err)) {
struct nl_msg *errmsg;
fprintf(ofd, " .error = %d \"%s\"\n", err->error,
diff --git a/lib/netfilter/log_msg_obj.c b/lib/netfilter/log_msg_obj.c
index 6b6ff07..6e8b554 100644
--- a/lib/netfilter/log_msg_obj.c
+++ b/lib/netfilter/log_msg_obj.c
@@ -377,7 +377,9 @@
void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *msg, uint8_t *hwaddr, int len)
{
- if (len > sizeof(msg->log_msg_hwaddr))
+ if (len < 0)
+ len = 0;
+ else if (((unsigned)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);
diff --git a/lib/netfilter/queue_msg_obj.c b/lib/netfilter/queue_msg_obj.c
index 000669b..210351b 100644
--- a/lib/netfilter/queue_msg_obj.c
+++ b/lib/netfilter/queue_msg_obj.c
@@ -378,9 +378,10 @@
void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr,
int len)
{
- if (len > sizeof(msg->queue_msg_hwaddr))
+ if (len < 0)
+ len = 0;
+ else if (((unsigned)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;
diff --git a/lib/nl.c b/lib/nl.c
index 7d729a7..a24c026 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -659,7 +659,7 @@
{
ssize_t n;
int flags = 0;
- static int page_size = 0;
+ static int page_size = 0; /* GLOBAL! */
struct iovec iov;
struct msghdr msg = {
.msg_name = (void *) nla,
@@ -680,7 +680,7 @@
if (page_size == 0)
page_size = getpagesize() * 4;
- iov.iov_len = sk->s_bufsize ? sk->s_bufsize : page_size;
+ iov.iov_len = sk->s_bufsize ? sk->s_bufsize : ((size_t)page_size);
iov.iov_base = malloc(iov.iov_len);
if (!iov.iov_base) {
@@ -734,7 +734,7 @@
goto retry;
}
- if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
+ if (iov.iov_len < ((size_t)n) || (msg.msg_flags & MSG_TRUNC)) {
void *tmp;
/* respond with error to an incomplete message */
@@ -964,7 +964,8 @@
else if (hdr->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *e = nlmsg_data(hdr);
- if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) {
+ if (hdr->nlmsg_len <
+ ((unsigned)nlmsg_size(sizeof(*e)))) {
/* Truncated error message, the default action
* is to stop parsing. The user may overrule
* this action by returning NL_SKIP or
diff --git a/lib/route/addr.c b/lib/route/addr.c
index 1f72c53..34b834e 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -642,7 +642,7 @@
return NULL;
nl_list_for_each_entry(a, &cache->c_items, ce_list) {
- if (ifindex && a->a_ifindex != ifindex)
+ if (ifindex != 0 && a->a_ifindex != ((unsigned)ifindex))
continue;
if (a->ce_mask & ADDR_ATTR_LOCAL &&
diff --git a/lib/route/class.c b/lib/route/class.c
index 29ba809..c04b112 100644
--- a/lib/route/class.c
+++ b/lib/route/class.c
@@ -359,7 +359,8 @@
return NULL;
nl_list_for_each_entry(class, &cache->c_items, ce_list) {
- if (class->c_handle == handle && class->c_ifindex == ifindex) {
+ if (class->c_handle == handle &&
+ class->c_ifindex == ((unsigned)ifindex)) {
nl_object_get((struct nl_object *) class);
return class;
}
@@ -390,7 +391,8 @@
return NULL;
nl_list_for_each_entry(class, &cache->c_items, ce_list) {
- if (class->c_parent == parent && class->c_ifindex == ifindex) {
+ if (class->c_parent == parent &&
+ class->c_ifindex == ((unsigned)ifindex)) {
nl_object_get((struct nl_object *) class);
return class;
}
diff --git a/lib/route/cls.c b/lib/route/cls.c
index 8f970b1..b207a09 100644
--- a/lib/route/cls.c
+++ b/lib/route/cls.c
@@ -393,7 +393,7 @@
nl_list_for_each_entry(cls, &cache->c_items, ce_list) {
if ((cls->c_parent == parent) &&
- (cls->c_ifindex == ifindex)&&
+ cls->c_ifindex == ((unsigned)ifindex) &&
(cls->c_handle == handle)) {
nl_object_get((struct nl_object *) cls);
return cls;
@@ -429,9 +429,9 @@
nl_list_for_each_entry(cls, &cache->c_items, ce_list) {
if ((cls->c_parent == parent) &&
- (cls->c_ifindex == ifindex) &&
+ cls->c_ifindex == ((unsigned)ifindex) &&
(cls->c_prio == prio)) {
- nl_object_get((struct nl_object *) cls);
+ nl_object_get((struct nl_object *)cls);
return cls;
}
}
diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c
index 5a5a210..6b4dfde 100644
--- a/lib/route/cls/ematch.c
+++ b/lib/route/cls/ematch.c
@@ -451,7 +451,7 @@
NL_DBG(3, "parsing ematch attribute %d, len=%u\n",
nmatches+1, nla_len(a));
- if (nla_len(a) < sizeof(*hdr)) {
+ if (_nla_len(a) < sizeof(*hdr)) {
err = -NLE_INVAL;
goto errout;
}
diff --git a/lib/route/cls/ematch/container.c b/lib/route/cls/ematch/container.c
index ea2d166..d7e5a3a 100644
--- a/lib/route/cls/ematch/container.c
+++ b/lib/route/cls/ematch/container.c
@@ -10,7 +10,7 @@
#include "nl-route.h"
-static int container_parse(struct rtnl_ematch *e, void *data, size_t len __attribute__((unused)))
+static int container_parse(struct rtnl_ematch *e, void *data, size_t len)
{
/*
The kernel may provide more than 4 bytes of data in the future and we want
diff --git a/lib/route/cls/ematch_grammar.l b/lib/route/cls/ematch_grammar.l
index 1035079..c78c41c 100644
--- a/lib/route/cls/ematch_grammar.l
+++ b/lib/route/cls/ematch_grammar.l
@@ -3,6 +3,9 @@
* Copyright (c) 2010-2013 Thomas Graf <[email protected]>
*/
+%top{
+ #include "nl-default.h"
+}
%{
#include <linux/tc_ematch/tc_em_cmp.h>
diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y
index 961ee43..bc0cc9c 100644
--- a/lib/route/cls/ematch_syntax.y
+++ b/lib/route/cls/ematch_syntax.y
@@ -4,8 +4,9 @@
*/
%{
-#include <linux/tc_ematch/tc_em_meta.h>
+#include "nl-default.h"
+#include <linux/tc_ematch/tc_em_meta.h>
#include <linux/tc_ematch/tc_em_cmp.h>
#include <netlink/netlink.h>
diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c
index 52f6e31..9821c77 100644
--- a/lib/route/cls/u32.c
+++ b/lib/route/cls/u32.c
@@ -154,7 +154,7 @@
sel = u->cu_selector->d_data;
pcnt_size = sizeof(struct tc_u32_pcnt) +
(sel->nkeys * sizeof(uint64_t));
- if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
+ if (_nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
err = -NLE_INVAL;
goto errout;
}
diff --git a/lib/route/link.c b/lib/route/link.c
index ce1355b..e634a8b 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -440,7 +440,7 @@
/* beware: @st might not be the full struct, only fields up to
* tx_compressed are present. See _nl_offsetofend() above. */
- if (nla_len(tb[IFLA_STATS]) >= _nl_offsetofend (struct rtnl_link_stats, rx_nohandler))
+ if (_nla_len(tb[IFLA_STATS]) >= _nl_offsetofend (struct rtnl_link_stats, rx_nohandler))
link->l_stats[RTNL_LINK_RX_NOHANDLER] = st->rx_nohandler;
else
link->l_stats[RTNL_LINK_RX_NOHANDLER] = 0;
@@ -1320,7 +1320,7 @@
return NULL;
nl_list_for_each_entry(link, &cache->c_items, ce_list) {
- if (link->l_index == ifindex) {
+ if (link->l_index == ((unsigned)ifindex)) {
nl_object_get((struct nl_object *) link);
return link;
}
diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c
index 5b44164..a9c7eea 100644
--- a/lib/route/link/bridge.c
+++ b/lib/route/link/bridge.c
@@ -23,6 +23,7 @@
#include "nl-route.h"
#include "link-api.h"
#include "nl-priv-dynamic-core/nl-core.h"
+#include "nl-priv-static-route/nl-priv-static-route.h"
#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
@@ -33,7 +34,7 @@
#define BRIDGE_ATTR_FLAGS (1 << 3)
#define BRIDGE_ATTR_PORT_VLAN (1 << 4)
#define BRIDGE_ATTR_HWMODE (1 << 5)
-#define BRIDGE_ATTR_SELF (1 << 6)
+#define BRIDGE_ATTR_CONFIG_MODE (1 << 6)
#define PRIV_FLAG_NEW_ATTRS (1 << 0)
@@ -43,7 +44,7 @@
uint8_t b_priv_flags; /* internal flags */
uint16_t b_hwmode;
uint16_t b_priority;
- uint16_t b_self; /* here for comparison reasons */
+ uint16_t b_config_mode;
uint32_t b_cost;
uint32_t b_flags;
uint32_t b_flags_mask;
@@ -57,6 +58,24 @@
addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
}
+static void unset_bit(unsigned nr, uint32_t *addr)
+{
+ if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
+ addr[nr / 32] &= ~(((uint32_t) 1) << (nr % 32));
+}
+
+static bool vlan_id_untagged(struct rtnl_link_bridge_vlan *vlan_info, uint16_t vid)
+{
+ uint32_t mask, bit;
+
+ _nl_assert(vid / 32u < ARRAY_SIZE(vlan_info->untagged_bitmap));
+
+ mask = vlan_info->untagged_bitmap[vid / 32];
+ bit = (((uint32_t) 1) << vid % 32);
+
+ return mask & bit;
+}
+
static int find_next_bit(int i, uint32_t x)
{
int j;
@@ -239,16 +258,149 @@
return 0;
}
+int _nl_bridge_fill_vlan_info(struct nl_msg *msg, struct rtnl_link_bridge_vlan * vlan_info)
+{
+ struct bridge_vlan_info vinfo;
+ int i = -1, j, k;
+ int start = -1, prev = -1;
+ int done;
+ bool untagged = false;
+
+ for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++)
+ {
+ int base_bit;
+ uint32_t a = vlan_info->vlan_bitmap[k];
+
+ base_bit = k * 32;
+ i = -1;
+ done = 0;
+ while (!done)
+ {
+ j = find_next_bit(i, a);
+ if (j > 0)
+ {
+ /* Skip if id equal to pvid */
+ if (vlan_info->pvid != 0 && j - 1 + base_bit == vlan_info->pvid)
+ goto nxt;
+ /* first hit of any bit */
+ if (start < 0 && prev < 0)
+ {
+ start = prev = j - 1 + base_bit;
+ /* Start range attribute */
+ untagged = vlan_id_untagged(vlan_info,start);
+ vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = start;
+ goto nxt;
+ }
+ /* this bit is a continuation of prior bits */
+ if (j - 2 + base_bit == prev)
+ {
+ prev++;
+ /* Hit end of untagged/tagged range */
+ if (untagged != vlan_id_untagged(vlan_info,prev))
+ {
+ /* put vlan into attributes */
+ if (start == prev-1)
+ {
+ /* only 1 vid in range */
+ vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+ }
+ else
+ {
+ /* end of untagged/tagged range */
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+
+ vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
+ vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = prev-1;
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+ }
+ /* start of new range */
+ untagged = !untagged;
+ vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = prev;
+ }
+ goto nxt;
+ }
+ }
+ else
+ done = 1;
+
+ if (start >= 0)
+ {
+ if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
+ break;
+
+ if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN && start != prev)
+ {
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+
+ vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
+ vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = prev;
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+ }
+ else if (start == prev)
+ {
+ vinfo.flags = untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = start;
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+ }
+
+ if (done)
+ break;
+ }
+ if (j > 0)
+ {
+ start = prev = j - 1 + base_bit;
+ untagged = vlan_id_untagged(vlan_info,start);
+ vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = start;
+ }
+nxt:
+ i = j;
+ }
+ }
+
+ if (vlan_info->pvid != 0)
+ {
+ untagged = vlan_id_untagged(vlan_info,vlan_info->pvid);
+ vinfo.flags = BRIDGE_VLAN_INFO_PVID;
+ vinfo.flags |= untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0;
+ vinfo.vid = vlan_info->pvid;
+ NLA_PUT(msg,IFLA_BRIDGE_VLAN_INFO,sizeof(vinfo),&vinfo);
+ }
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
void *data)
{
struct bridge_data *bd = data;
- if ((bd->ce_mask & BRIDGE_ATTR_SELF)||(bd->ce_mask & BRIDGE_ATTR_HWMODE))
- NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
-
if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
+ {
NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
+ bd->b_config_mode = BRIDGE_FLAGS_SELF;
+ bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
+ }
+
+ if (bd->ce_mask & BRIDGE_ATTR_CONFIG_MODE)
+ NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, bd->b_config_mode);
+
+ if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
+ if (_nl_bridge_fill_vlan_info(msg, &bd->vlan_info)) {
+ goto nla_put_failure;
+ }
+ }
return 0;
@@ -445,7 +597,7 @@
memcmp(&a->vlan_info, &b->vlan_info,
sizeof(struct rtnl_link_bridge_vlan)));
diff |= _DIFF(BRIDGE_ATTR_HWMODE, a->b_hwmode != b->b_hwmode);
- diff |= _DIFF(BRIDGE_ATTR_SELF, a->b_self != b->b_self);
+ diff |= _DIFF(BRIDGE_ATTR_CONFIG_MODE, a->b_config_mode != b->b_config_mode);
if (flags & LOOSE_COMPARISON)
diff |= _DIFF(BRIDGE_ATTR_FLAGS,
@@ -773,8 +925,31 @@
IS_BRIDGE_LINK_ASSERT(link);
- bd->b_self |= 1;
- bd->ce_mask |= BRIDGE_ATTR_SELF;
+ bd->b_config_mode = BRIDGE_FLAGS_SELF;
+ bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
+
+ return 0;
+}
+
+/**
+ * Set link change type to master
+ * @arg link Link Object of type bridge
+ *
+ * This will set the bridge change flag to master, meaning that changes to
+ * be applied with this link object will be applied directly to the virtual
+ * device in a bridge instead of the physical device.
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ */
+int rtnl_link_bridge_set_master(struct rtnl_link *link)
+{
+ struct bridge_data *bd = bridge_data(link);
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ bd->b_config_mode = BRIDGE_FLAGS_MASTER;
+ bd->ce_mask |= BRIDGE_ATTR_CONFIG_MODE;
return 0;
}
@@ -915,6 +1090,146 @@
/** @} */
+/**
+ * Enable the ability to set vlan info
+ * @arg link Link object of type bridge
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ */
+int rtnl_link_bridge_enable_vlan(struct rtnl_link *link)
+{
+ struct bridge_data *bd = bridge_data(link);
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
+
+ return 0;
+}
+
+/**
+ * @name Quality of Service
+ * @{
+ */
+
+/**
+ * Set port vlan membership range
+ * @arg link Link object of type bridge
+ * @arg start Start of membership range.
+ * @arg end End of membership range.
+ * @arg untagged Set membership range to be untagged.
+ *
+ * This will set the vlan membership range for a bridge port.
+ * This will unset the untagged membership if untagged is false.
+ * Supported range is 1-4094
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_NOATTR if port vlan attribute not present
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ * @return -NLE_INVAL range is not in supported range.
+ */
+int rtnl_link_bridge_set_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end, int untagged)
+{
+ struct rtnl_link_bridge_vlan * vinfo;
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ vinfo = rtnl_link_bridge_get_port_vlan(link);
+
+ if (!vinfo)
+ return -NLE_NOATTR;
+
+ if (start == 0 || start > end || end >= VLAN_VID_MASK)
+ return -NLE_INVAL;
+
+ for (uint16_t i = start; i <= end; i++)
+ {
+ set_bit(i,vinfo->vlan_bitmap);
+ if (untagged) {
+ set_bit(i,vinfo->untagged_bitmap);
+ } else {
+ unset_bit(i,vinfo->untagged_bitmap);
+ }
+ }
+ return 0;
+}
+
+/**
+ * Unset port vlan membership range
+ * @arg link Link object of type bridge
+ * @arg start Start of membership range.
+ * @arg end End of membership range.
+ *
+ * This will unset the vlan membership range for a bridge port
+ * for both tagged and untagged membership.
+ * Supported range is 1-4094
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_NOATTR if port vlan attribute not present
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ * @return -NLE_INVAL range is not in supported range.
+ */
+int rtnl_link_bridge_unset_port_vlan_map_range (struct rtnl_link *link, uint16_t start, uint16_t end)
+{
+ struct rtnl_link_bridge_vlan * vinfo;
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ vinfo = rtnl_link_bridge_get_port_vlan(link);
+
+ if (!vinfo)
+ return -NLE_NOATTR;
+
+ if (start == 0 || start > end || end >= VLAN_VID_MASK)
+ return -NLE_INVAL;
+
+ for (uint16_t i = start; i <= end; i++)
+ {
+ unset_bit(i,vinfo->vlan_bitmap);
+ unset_bit(i,vinfo->untagged_bitmap);
+ }
+ return 0;
+}
+
+/**
+ * Set port primary vlan id
+ * @arg link Link object of type bridge
+ * @arg pvid PVID to set.
+ * @arg untagged Set vlan id to be untagged.
+ *
+ * This will set the primary vlan id for a bridge port.
+ * Supported range is 0-4094, Setting pvid to 0 will unset it.
+ * You will most likely want to set/unset pvid in the vlan map.
+ * @see rtnl_link_bridge_set_port_vlan_map_range()
+ * @see rtnl_link_bridge_unset_port_vlan_map_range()
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_NOATTR if port vlan attribute not present
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ * @return -NLE_INVAL PVID is above supported range.
+ */
+int rtnl_link_bridge_set_port_vlan_pvid (struct rtnl_link *link, uint16_t pvid)
+{
+ struct rtnl_link_bridge_vlan * vinfo;
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ vinfo = rtnl_link_bridge_get_port_vlan(link);
+
+ if (!vinfo)
+ return -NLE_NOATTR;
+
+ if (pvid >= VLAN_VID_MASK)
+ return -NLE_INVAL;
+
+ vinfo->pvid = pvid;
+
+ return 0;
+}
+
+/** @} */
+
int rtnl_link_bridge_pvid(struct rtnl_link *link)
{
struct bridge_data *bd;
diff --git a/lib/route/link/bridge_info.c b/lib/route/link/bridge_info.c
index 61b885f..5d69b5c 100644
--- a/lib/route/link/bridge_info.c
+++ b/lib/route/link/bridge_info.c
@@ -21,18 +21,33 @@
#define BRIDGE_ATTR_VLAN_FILTERING (1 << 0)
#define BRIDGE_ATTR_VLAN_PROTOCOL (1 << 1)
#define BRIDGE_ATTR_VLAN_STATS_ENABLED (1 << 2)
+#define BRIDGE_ATTR_AGEING_TIME (1 << 3)
+#define BRIDGE_ATTR_VLAN_DEFAULT_PVID (1 << 4)
+#define BRIDGE_ATTR_NF_CALL_IPTABLES (1 << 5)
+#define BRIDGE_ATTR_NF_CALL_IP6TABLES (1 << 6)
+#define BRIDGE_ATTR_NF_CALL_ARPTABLES (1 << 7)
struct bridge_info {
uint32_t ce_mask; /* to support attr macros */
+ uint32_t b_ageing_time;
uint16_t b_vlan_protocol;
+ uint16_t b_vlan_default_pvid;
uint8_t b_vlan_filtering;
uint8_t b_vlan_stats_enabled;
+ uint8_t b_nf_call_iptables;
+ uint8_t b_nf_call_ip6tables;
+ uint8_t b_nf_call_arptables;
};
static const struct nla_policy bi_attrs_policy[IFLA_BR_MAX + 1] = {
+ [IFLA_BR_AGEING_TIME] = { .type = NLA_U32 },
+ [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NLA_U16 },
[IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 },
[IFLA_BR_VLAN_PROTOCOL] = { .type = NLA_U16 },
[IFLA_BR_VLAN_STATS_ENABLED] = { .type = NLA_U8 },
+ [IFLA_BR_NF_CALL_IPTABLES] = { .type = NLA_U8 },
+ [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NLA_U8 },
+ [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NLA_U8 },
};
static inline struct bridge_info *bridge_info(struct rtnl_link *link)
@@ -75,6 +90,17 @@
bi = link->l_info;
+ if (tb[IFLA_BR_AGEING_TIME]) {
+ bi->b_ageing_time = nla_get_u32(tb[IFLA_BR_AGEING_TIME]);
+ bi->ce_mask |= BRIDGE_ATTR_AGEING_TIME;
+ }
+
+ if (tb[IFLA_BR_VLAN_DEFAULT_PVID]) {
+ bi->b_vlan_default_pvid =
+ nla_get_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]);
+ bi->ce_mask |= BRIDGE_ATTR_VLAN_DEFAULT_PVID;
+ }
+
if (tb[IFLA_BR_VLAN_FILTERING]) {
bi->b_vlan_filtering = nla_get_u8(tb[IFLA_BR_VLAN_FILTERING]);
bi->ce_mask |= BRIDGE_ATTR_VLAN_FILTERING;
@@ -92,6 +118,24 @@
bi->ce_mask |= BRIDGE_ATTR_VLAN_STATS_ENABLED;
}
+ if (tb[IFLA_BR_NF_CALL_IPTABLES]) {
+ bi->b_nf_call_iptables =
+ nla_get_u8(tb[IFLA_BR_NF_CALL_IPTABLES]);
+ bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IPTABLES;
+ }
+
+ if (tb[IFLA_BR_NF_CALL_IP6TABLES]) {
+ bi->b_nf_call_ip6tables =
+ nla_get_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]);
+ bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IP6TABLES;
+ }
+
+ if (tb[IFLA_BR_NF_CALL_ARPTABLES]) {
+ bi->b_nf_call_arptables =
+ nla_get_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]);
+ bi->ce_mask |= BRIDGE_ATTR_NF_CALL_ARPTABLES;
+ }
+
return 0;
}
@@ -104,9 +148,16 @@
if (!data)
return -NLE_MSGSIZE;
+ if (bi->ce_mask & BRIDGE_ATTR_AGEING_TIME)
+ NLA_PUT_U32(msg, IFLA_BR_AGEING_TIME, bi->b_ageing_time);
+
if (bi->ce_mask & BRIDGE_ATTR_VLAN_FILTERING)
NLA_PUT_U8(msg, IFLA_BR_VLAN_FILTERING, bi->b_vlan_filtering);
+ if (bi->ce_mask & BRIDGE_ATTR_VLAN_DEFAULT_PVID)
+ NLA_PUT_U16(msg, IFLA_BR_VLAN_DEFAULT_PVID,
+ bi->b_vlan_default_pvid);
+
if (bi->ce_mask & BRIDGE_ATTR_VLAN_PROTOCOL)
NLA_PUT_U16(msg, IFLA_BR_VLAN_PROTOCOL,
htons(bi->b_vlan_protocol));
@@ -115,6 +166,18 @@
NLA_PUT_U8(msg, IFLA_BR_VLAN_STATS_ENABLED,
bi->b_vlan_stats_enabled);
+ if (bi->ce_mask & BRIDGE_ATTR_NF_CALL_IPTABLES)
+ NLA_PUT_U8(msg, IFLA_BR_NF_CALL_IPTABLES,
+ bi->b_nf_call_iptables);
+
+ if (bi->ce_mask & BRIDGE_ATTR_NF_CALL_IP6TABLES)
+ NLA_PUT_U8(msg, IFLA_BR_NF_CALL_IP6TABLES,
+ bi->b_nf_call_ip6tables);
+
+ if (bi->ce_mask & BRIDGE_ATTR_NF_CALL_ARPTABLES)
+ NLA_PUT_U8(msg, IFLA_BR_NF_CALL_ARPTABLES,
+ bi->b_nf_call_arptables);
+
nla_nest_end(msg, data);
return 0;
@@ -144,6 +207,53 @@
} while (0)
/**
+ * Set ageing time for dynamic forwarding entries
+ * @arg link Link object of type bridge
+ * @arg ageing_time Interval to set.
+ *
+ * @return void
+ */
+void rtnl_link_bridge_set_ageing_time(struct rtnl_link *link,
+ uint32_t ageing_time)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ bi->b_ageing_time = ageing_time;
+
+ bi->ce_mask |= BRIDGE_ATTR_AGEING_TIME;
+}
+
+/**
+ * Get ageing time for dynamic forwarding entries
+ * @arg link Link object of type bridge
+ * @arg ageing_time Output argument.
+ *
+ * @see rtnl_link_bridge_set_ageing_time()
+ * @return Zero on success, otherwise a negative error code.
+ * @retval -NLE_NOATTR
+ * @retval -NLE_INVAL
+ */
+int rtnl_link_bridge_get_ageing_time(struct rtnl_link *link,
+ uint32_t *ageing_time)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ if (!(bi->ce_mask & BRIDGE_ATTR_AGEING_TIME))
+ return -NLE_NOATTR;
+
+ if (!ageing_time)
+ return -NLE_INVAL;
+
+ *ageing_time = bi->b_ageing_time;
+
+ return 0;
+}
+
+/**
* Set VLAN filtering flag
* @arg link Link object of type bridge
* @arg vlan_filtering VLAN_filtering boolean flag to set.
@@ -244,6 +354,56 @@
}
/**
+ * Set VLAN default pvid
+ * @arg link Link object of type bridge
+ * @arg default pvid VLAN default pvid to set.
+ *
+ * @see rtnl_link_bridge_get_vlan_default_pvid()
+ *
+ * @return void
+ */
+void rtnl_link_bridge_set_vlan_default_pvid(struct rtnl_link *link,
+ uint16_t default_pvid)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ bi->b_vlan_default_pvid = default_pvid;
+
+ bi->ce_mask |= BRIDGE_ATTR_VLAN_DEFAULT_PVID;
+}
+
+/**
+ * Get VLAN default pvid
+ * @arg link Link object of type bridge
+ * @arg default_pvid Output argument.
+ *
+ * @see rtnl_link_bridge_set_vlan_default_pvid()
+ *
+ * @return Zero on success, otherwise a negative error code.
+ * @retval -NLE_NOATTR
+ * @retval -NLE_INVAL
+ */
+int rtnl_link_bridge_get_vlan_default_pvid(struct rtnl_link *link,
+ uint16_t *default_pvid)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ if (!(bi->ce_mask & BRIDGE_ATTR_VLAN_DEFAULT_PVID))
+ return -NLE_NOATTR;
+
+ if (!default_pvid)
+ return -NLE_INVAL;
+
+ *default_pvid = bi->b_vlan_default_pvid;
+
+ return 0;
+}
+
+/**
* Set VLAN stats enabled flag
* @arg link Link object of type bridge
* @arg vlan_stats_enabled VLAN stats enabled flag to set
@@ -293,6 +453,63 @@
return 0;
}
+/**
+ * Set call enabled flag for passing IPv4 traffic to iptables
+ * @arg link Link object of type bridge
+ * @arg call_enabled call enabled boolean flag to set.
+ *
+ * @return void
+ */
+void rtnl_link_bridge_set_nf_call_iptables(struct rtnl_link *link,
+ uint8_t call_enabled)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ bi->b_nf_call_iptables = call_enabled;
+
+ bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IPTABLES;
+}
+
+/**
+ * Set call enabled flag for passing IPv6 traffic to ip6tables
+ * @arg link Link object of type bridge
+ * @arg call_enabled call enabled boolean flag to set.
+ *
+ * @return void
+ */
+void rtnl_link_bridge_set_nf_call_ip6tables(struct rtnl_link *link,
+ uint8_t call_enabled)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ bi->b_nf_call_ip6tables = call_enabled;
+
+ bi->ce_mask |= BRIDGE_ATTR_NF_CALL_IP6TABLES;
+}
+
+/**
+ * Set call enabled flag for passing ARP traffic to arptables
+ * @arg link Link object of type bridge
+ * @arg call_enabled call enabled boolean flag to set.
+ *
+ * @return void
+ */
+void rtnl_link_bridge_set_nf_call_arptables(struct rtnl_link *link,
+ uint8_t call_enabled)
+{
+ struct bridge_info *bi = bridge_info(link);
+
+ IS_BRIDGE_INFO_ASSERT(link);
+
+ bi->b_nf_call_arptables = call_enabled;
+
+ bi->ce_mask |= BRIDGE_ATTR_NF_CALL_ARPTABLES;
+}
+
static void _nl_init bridge_info_init(void)
{
rtnl_link_register_info(&bridge_info_ops);
diff --git a/lib/route/link/can.c b/lib/route/link/can.c
index da00144..86e6684 100644
--- a/lib/route/link/can.c
+++ b/lib/route/link/can.c
@@ -168,7 +168,7 @@
ci->ci_mask |= CAN_HAS_DATA_BITTIMING_CONST;
}
- if (xstats && nla_len(xstats) >= sizeof(ci->ci_device_stats)) {
+ if (xstats && _nla_len(xstats) >= sizeof(ci->ci_device_stats)) {
nla_memcpy(&ci->ci_device_stats, xstats, sizeof(ci->ci_device_stats));
ci->ci_mask |= CAN_HAS_DEVICE_STATS;
}
diff --git a/lib/route/link/macsec.c b/lib/route/link/macsec.c
index a989eed..7f4f568 100644
--- a/lib/route/link/macsec.c
+++ b/lib/route/link/macsec.c
@@ -369,7 +369,8 @@
struct macsec_info *a = link_a->l_info;
struct macsec_info *b = link_b->l_info;
int diff = 0;
- uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0;
+ uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask :
+ ~((uint32_t)0u);
#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
if (a->ce_mask & MACSEC_ATTR_SCI && b->ce_mask & MACSEC_ATTR_SCI)
diff --git a/lib/route/link/macvlan.c b/lib/route/link/macvlan.c
index 5452d9e..fa7d0bb 100644
--- a/lib/route/link/macvlan.c
+++ b/lib/route/link/macvlan.c
@@ -225,7 +225,7 @@
{
struct macvlan_info *mvi = link->l_info;
struct nlattr *data, *datamac = NULL;
- int i, ret;
+ int ret;
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
return -NLE_MSGSIZE;
@@ -239,6 +239,8 @@
NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
if (mvi->mvi_mask & MACVLAN_HAS_MACADDR) {
+ uint32_t i;
+
NLA_PUT_U32(msg, IFLA_MACVLAN_MACADDR_MODE, mvi->mvi_macmode);
datamac = nla_nest_start(msg, IFLA_MACVLAN_MACADDR_DATA);
if (!datamac)
@@ -345,7 +347,6 @@
int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
{
struct macvlan_info *mvi = link->l_info;
- int i;
IS_MACVLAN_LINK_ASSERT(link);
@@ -353,6 +354,8 @@
mvi->mvi_mask |= MACVLAN_HAS_MODE;
if (mode != MACVLAN_MODE_SOURCE) {
+ uint32_t i;
+
for (i = 0; i < mvi->mvi_maccount; i++)
nl_addr_put(mvi->mvi_macaddr[i]);
free(mvi->mvi_macaddr);
diff --git a/lib/route/link/sriov.c b/lib/route/link/sriov.c
index d47d1dd..98087e2 100644
--- a/lib/route/link/sriov.c
+++ b/lib/route/link/sriov.c
@@ -633,7 +633,7 @@
if (t[IFLA_VF_SPOOFCHK]) {
vf_spoofchk = nla_data(t[IFLA_VF_SPOOFCHK]);
- if (vf_spoofchk->setting != -1) {
+ if (vf_spoofchk->setting != ((uint32_t)-1)) {
vf_data->vf_spoofchk = vf_spoofchk->setting ? 1 : 0;
vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
}
@@ -662,7 +662,7 @@
if (t[IFLA_VF_RSS_QUERY_EN]) {
vf_rss_query = nla_data(t[IFLA_VF_RSS_QUERY_EN]);
- if (vf_rss_query->setting != -1) {
+ if (vf_rss_query->setting != ((uint32_t)-1)) {
vf_data->vf_rss_query_en = vf_rss_query->setting ? 1 : 0;
vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
}
@@ -702,7 +702,7 @@
if (t[IFLA_VF_TRUST]) {
vf_trust = nla_data(t[IFLA_VF_TRUST]);
- if (vf_trust->setting != -1) {
+ if (vf_trust->setting != ((uint32_t)-1)) {
vf_data->vf_trust = vf_trust->setting ? 1 : 0;
vf_data->ce_mask |= SRIOV_ATTR_TRUST;
}
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
index 60e4358..75842d8 100644
--- a/lib/route/link/vlan.c
+++ b/lib/route/link/vlan.c
@@ -123,7 +123,7 @@
memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
- if (nla_len(nla) < sizeof(*map))
+ if (_nla_len(nla) < sizeof(*map))
return -NLE_INVAL;
map = nla_data(nla);
@@ -154,7 +154,7 @@
int remaining, i = 0;
nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
- if (nla_len(nla) < sizeof(*map))
+ if (_nla_len(nla) < sizeof(*map))
return -NLE_INVAL;
i++;
}
diff --git a/lib/route/link/vxlan.c b/lib/route/link/vxlan.c
index 4606dd5..0603bf5 100644
--- a/lib/route/link/vxlan.c
+++ b/lib/route/link/vxlan.c
@@ -617,7 +617,8 @@
struct vxlan_info *a = link_a->l_info;
struct vxlan_info *b = link_b->l_info;
int diff = 0;
- uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0;
+ uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask :
+ ~((uint32_t)0u);
#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
diff |= _DIFF(VXLAN_ATTR_ID, a->vxi_id != b->vxi_id);
diff --git a/lib/route/neigh.c b/lib/route/neigh.c
index 9150024..56c1e09 100644
--- a/lib/route/neigh.c
+++ b/lib/route/neigh.c
@@ -242,9 +242,7 @@
uint16_t n_vlan;
char n_addr[0];
} _nl_packed *nkey;
-#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
-#endif
if (neigh->n_family == AF_BRIDGE) {
if (neigh->n_lladdr)
@@ -678,8 +676,8 @@
struct rtnl_neigh *neigh;
nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
- if (neigh->n_ifindex == ifindex &&
- neigh->n_family == dst->a_family &&
+ if (neigh->n_ifindex == ((unsigned)ifindex) &&
+ neigh->n_family == ((unsigned)dst->a_family) &&
!nl_addr_cmp(neigh->n_dst, dst)) {
nl_object_get((struct nl_object *) neigh);
return neigh;
@@ -704,9 +702,9 @@
struct rtnl_neigh *neigh;
nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
- if (neigh->n_ifindex == ifindex &&
- neigh->n_vlan == vlan &&
- neigh->n_lladdr && !nl_addr_cmp(neigh->n_lladdr, lladdr)) {
+ if ((neigh->n_ifindex == (unsigned)ifindex) &&
+ neigh->n_vlan == vlan && neigh->n_lladdr &&
+ !nl_addr_cmp(neigh->n_lladdr, lladdr)) {
nl_object_get((struct nl_object *) neigh);
return neigh;
}
@@ -1014,7 +1012,7 @@
{
if (!nocheck) {
if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
- if (new->a_family != neigh->n_family)
+ if (neigh->n_family != ((unsigned)new->a_family))
return -NLE_AF_MISMATCH;
} else {
neigh->n_family = new->a_family;
diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c
index a699867..8d5db8a 100644
--- a/lib/route/neightbl.c
+++ b/lib/route/neightbl.c
@@ -534,8 +534,7 @@
nl_list_for_each_entry(nt, &cache->c_items, ce_list) {
if (!strcasecmp(nt->nt_name, name) &&
- ((!ifindex && !nt->nt_parms.ntp_ifindex) ||
- (ifindex && ifindex == nt->nt_parms.ntp_ifindex))) {
+ ((unsigned)ifindex) == nt->nt_parms.ntp_ifindex) {
nl_object_get((struct nl_object *)nt);
return nt;
}
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c
index 962f2ba..7e0df61 100644
--- a/lib/route/nexthop.c
+++ b/lib/route/nexthop.c
@@ -136,6 +136,23 @@
return diff;
}
+/**
+ * Check if the fixed attributes of two nexthops are identical, and may
+ * only differ in flags or weight.
+ *
+ * @arg a a nexthop
+ * @arg b another nexthop
+ *
+ * @return true if both nexthop have equal attributes, otherwise false.
+ */
+int rtnl_route_nh_identical(struct rtnl_nexthop *a, struct rtnl_nexthop *b)
+{
+ return !rtnl_route_nh_compare(a, b,
+ NH_ATTR_IFINDEX | NH_ATTR_REALMS |
+ NH_ATTR_GATEWAY | NH_ATTR_NEWDST |
+ NH_ATTR_VIA | NH_ATTR_ENCAP, 0);
+}
+
static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
{
struct nl_cache *link_cache;
diff --git a/lib/route/nh.c b/lib/route/nh.c
index 1072172..3dfe558 100644
--- a/lib/route/nh.c
+++ b/lib/route/nh.c
@@ -176,7 +176,7 @@
unsigned int lkey_sz;
struct nexthop_hash_key {
uint32_t nh_id;
- } __attribute__((packed)) lkey;
+ } _nl_packed lkey;
lkey_sz = sizeof(lkey);
lkey.nh_id = nexthop->nh_id;
@@ -336,7 +336,7 @@
unsigned len;
data = nla_data(tb[NHA_GROUP]);
- len = nla_len(tb[NHA_GROUP]);
+ len = _nla_len(tb[NHA_GROUP]);
size = len / sizeof(struct nexthop_grp);
err = rtnl_nh_grp_info(size, (const struct nexthop_grp *)data,
@@ -454,7 +454,7 @@
return NULL;
nl_list_for_each_entry(nh, &cache->c_items, ce_list) {
- if (nh->nh_id == nhid) {
+ if (nh->nh_id == ((unsigned)nhid)) {
nl_object_get((struct nl_object *)nh);
return nh;
}
diff --git a/lib/route/nl-route.h b/lib/route/nl-route.h
index 28d0166..3b7679b 100644
--- a/lib/route/nl-route.h
+++ b/lib/route/nl-route.h
@@ -80,21 +80,6 @@
void *priv; /* private data for encap type */
};
-struct rtnl_nexthop {
- uint8_t rtnh_flags;
- uint8_t rtnh_flag_mask;
- uint8_t rtnh_weight;
- /* 1 byte spare */
- uint32_t rtnh_ifindex;
- struct nl_addr *rtnh_gateway;
- uint32_t ce_mask; /* HACK to support attr macros */
- struct nl_list_head rtnh_list;
- uint32_t rtnh_realms;
- struct nl_addr *rtnh_newdst;
- struct nl_addr *rtnh_via;
- struct rtnl_nh_encap *rtnh_encap;
-};
-
struct rtnl_ratespec {
uint64_t rs_rate64;
uint16_t rs_overhead;
@@ -171,7 +156,7 @@
sysconfdir = getenv("NLSYSCONFDIR");
if (!sysconfdir)
- sysconfdir = SYSCONFDIR;
+ sysconfdir = _NL_SYSCONFDIR_LIBNL;
return asprintf(strp, "%s/%s", sysconfdir, filename);
}
diff --git a/lib/route/pktloc_grammar.l b/lib/route/pktloc_grammar.l
index 2db229d..b2a2236 100644
--- a/lib/route/pktloc_grammar.l
+++ b/lib/route/pktloc_grammar.l
@@ -1,3 +1,6 @@
+%top{
+ #include "nl-default.h"
+}
%{
#include <linux/tc_ematch/tc_em_cmp.h>
diff --git a/lib/route/pktloc_syntax.y b/lib/route/pktloc_syntax.y
index 661463a..505f4c8 100644
--- a/lib/route/pktloc_syntax.y
+++ b/lib/route/pktloc_syntax.y
@@ -1,4 +1,6 @@
%{
+#include "nl-default.h"
+
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/pktloc.h>
diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c
index 67ea358..9887e0d 100644
--- a/lib/route/qdisc.c
+++ b/lib/route/qdisc.c
@@ -388,7 +388,8 @@
return NULL;
nl_list_for_each_entry(q, &cache->c_items, ce_list) {
- if (q->q_parent == parent && q->q_ifindex == ifindex) {
+ if (q->q_parent == parent &&
+ q->q_ifindex == ((unsigned)ifindex)) {
nl_object_get((struct nl_object *) q);
return q;
}
@@ -420,7 +421,8 @@
return NULL;
nl_list_for_each_entry(q, &cache->c_items, ce_list) {
- if ((q->q_ifindex == ifindex) && (!strcmp(q->q_kind, kind))) {
+ if ((q->q_ifindex == ((unsigned)ifindex)) &&
+ (!strcmp(q->q_kind, kind))) {
nl_object_get((struct nl_object *) q);
return q;
}
@@ -452,7 +454,8 @@
return NULL;
nl_list_for_each_entry(q, &cache->c_items, ce_list) {
- if (q->q_handle == handle && q->q_ifindex == ifindex) {
+ if (q->q_handle == handle &&
+ q->q_ifindex == ((unsigned)ifindex)) {
nl_object_get((struct nl_object *) q);
return q;
}
diff --git a/lib/route/qdisc/netem.c b/lib/route/qdisc/netem.c
index 6dde4f0..8ced034 100644
--- a/lib/route/qdisc/netem.c
+++ b/lib/route/qdisc/netem.c
@@ -972,7 +972,7 @@
return -nl_syserr2nlerr(errno);
data = (int16_t *) calloc(MAXDIST, sizeof(int16_t));
- line = (char *) calloc(sizeof(char), len + 1);
+ line = (char *) calloc(len + 1, sizeof(char));
if (!data || !line) {
fclose(f);
return -NLE_NOMEM;
diff --git a/lib/route/qdisc/tbf.c b/lib/route/qdisc/tbf.c
index 67996eb..a054a14 100644
--- a/lib/route/qdisc/tbf.c
+++ b/lib/route/qdisc/tbf.c
@@ -139,9 +139,9 @@
uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
struct tc_tbf_qopt opts;
struct rtnl_tbf *tbf = data;
- int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
+ const uint32_t REQUIRED = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
- if ((tbf->qt_mask & required) != required)
+ if ((tbf->qt_mask & REQUIRED) != REQUIRED)
return -NLE_MISSING_ATTR;
memset(&opts, 0, sizeof(opts));
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index ce68259..094ae53 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.c
@@ -48,8 +48,6 @@
NLHDR_COMMON
uint8_t rt_family;
- uint8_t rt_dst_len;
- uint8_t rt_src_len;
uint8_t rt_tos;
uint8_t rt_protocol;
uint8_t rt_scope;
@@ -65,6 +63,7 @@
uint32_t rt_metrics[RTAX_MAX];
uint32_t rt_metrics_mask;
uint32_t rt_nr_nh;
+ uint32_t rt_nhid;
struct nl_addr *rt_pref_src;
struct nl_list_head rt_nexthops;
struct rtnl_rtcacheinfo rt_cacheinfo;
@@ -90,6 +89,7 @@
#define ROUTE_ATTR_REALMS 0x010000
#define ROUTE_ATTR_CACHEINFO 0x020000
#define ROUTE_ATTR_TTL_PROPAGATE 0x040000
+#define ROUTE_ATTR_NHID 0x080000
/** @endcond */
static void route_constructor(struct nl_object *c)
@@ -194,6 +194,9 @@
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_NHID)
+ nl_dump(p, "nhid %u ", r->rt_nhid);
+
if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
struct rtnl_nexthop *nh;
@@ -284,6 +287,9 @@
r->rt_ttl_propagate ? "enabled" : "disabled");
}
+ if (r->ce_mask & ROUTE_ATTR_NHID)
+ nl_dump(p, "nhid %u ", r->rt_nhid);
+
nl_dump(p, "\n");
if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
@@ -345,9 +351,7 @@
uint32_t rt_prio;
char rt_addr[0];
} _nl_packed *rkey = NULL;
-#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
-#endif
if (route->rt_dst)
addr = route->rt_dst;
@@ -371,10 +375,11 @@
*hashkey = nl_hash(rkey, rkey_sz, 0) % table_sz;
- NL_DBG(5, "route %p key (fam %d tos %d table %d addr %s) keysz %d "
- "hash 0x%x\n", route, rkey->rt_family, rkey->rt_tos,
- rkey->rt_table, nl_addr2str(addr, buf, sizeof(buf)),
- rkey_sz, *hashkey);
+ NL_DBG(5,
+ "route %p key (fam %d tos %d table %d prio %d addr %s) keysz %d hash 0x%x\n",
+ route, rkey->rt_family, rkey->rt_tos, rkey->rt_table,
+ rkey->rt_prio, nl_addr2str(addr, buf, sizeof(buf)), rkey_sz,
+ *hashkey);
return;
}
@@ -416,6 +421,7 @@
nl_addr_cmp(a->rt_pref_src, b->rt_pref_src));
diff |= _DIFF(ROUTE_ATTR_TTL_PROPAGATE,
a->rt_ttl_propagate != b->rt_ttl_propagate);
+ diff |= _DIFF(ROUTE_ATTR_NHID, a->rt_nhid != b->rt_nhid);
if (flags & LOOSE_COMPARISON) {
nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
@@ -451,7 +457,7 @@
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)) {
+ if (rtnl_route_nh_identical(nh_a, nh_b)) {
found = 1;
break;
}
@@ -466,7 +472,7 @@
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)) {
+ if (rtnl_route_nh_identical(nh_a, nh_b)) {
found = 1;
break;
}
@@ -502,9 +508,7 @@
struct rtnl_route *old_route = (struct rtnl_route *) old_obj;
struct rtnl_nexthop *new_nh;
int action = new_obj->ce_msgtype;
-#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
-#endif
/*
* ipv6 ECMP route notifications from the kernel come as
@@ -542,7 +546,7 @@
* Do not add the nexthop to old route if it was already added before
*/
nl_list_for_each_entry(old_nh, &old_route->rt_nexthops, rtnh_list) {
- if (!rtnl_route_nh_compare(old_nh, new_nh, ~0, 0)) {
+ if (rtnl_route_nh_identical(old_nh, new_nh)) {
return 0;
}
}
@@ -578,7 +582,7 @@
*/
nl_list_for_each_entry(old_nh, &old_route->rt_nexthops,
rtnh_list) {
- if (!rtnl_route_nh_compare(old_nh, new_nh, ~0, 0)) {
+ if (rtnl_route_nh_identical(old_nh, new_nh)) {
rtnl_route_remove_nexthop(old_route, old_nh);
@@ -623,6 +627,7 @@
__ADD(ROUTE_ATTR_REALMS, realms),
__ADD(ROUTE_ATTR_CACHEINFO, cacheinfo),
__ADD(ROUTE_ATTR_TTL_PROPAGATE, ttl_propagate),
+ __ADD(ROUTE_ATTR_NHID, nhid),
};
static char *route_attrs2str(int attrs, char *buf, size_t len)
@@ -943,9 +948,11 @@
struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
{
struct rtnl_nexthop *nh;
- uint32_t i;
- if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
+ if (r->ce_mask & ROUTE_ATTR_MULTIPATH && n >= 0 &&
+ ((unsigned)n) < r->rt_nr_nh) {
+ int i;
+
i = 0;
nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
if (i == n) return nh;
@@ -970,6 +977,21 @@
return route->rt_ttl_propagate;
}
+void rtnl_route_set_nhid(struct rtnl_route *route, uint32_t nhid)
+{
+ route->rt_nhid = nhid;
+
+ if (nhid > 0)
+ route->ce_mask |= ROUTE_ATTR_NHID;
+ else
+ route->ce_mask &= ~ROUTE_ATTR_NHID;
+}
+
+uint32_t rtnl_route_get_nhid(struct rtnl_route *route)
+{
+ return route->rt_nhid;
+}
+
/** @} */
/**
@@ -1006,7 +1028,7 @@
* is not directly connected
*/
nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
- if (nh->rtnh_gateway)
+ if (nh->rtnh_gateway || nh->rtnh_via)
return RT_SCOPE_UNIVERSE;
}
}
@@ -1052,6 +1074,7 @@
[RTA_TTL_PROPAGATE] = { .type = NLA_U8 },
[RTA_ENCAP] = { .type = NLA_NESTED },
[RTA_ENCAP_TYPE] = { .type = NLA_U16 },
+ [RTA_NH_ID] = { .type = NLA_U32 },
};
static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
@@ -1249,7 +1272,7 @@
return err;
for (i = 1; i <= RTAX_MAX; i++) {
- if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
+ if (mtb[i] && _nla_len(mtb[i]) >= sizeof(uint32_t)) {
uint32_t m = nla_get_u32(mtb[i]);
err = rtnl_route_set_metric(route, i, m);
@@ -1343,6 +1366,10 @@
return err;
}
+ if (tb[RTA_NH_ID]) {
+ rtnl_route_set_nhid(route, nla_get_u32(tb[RTA_NH_ID]));
+ }
+
if (old_nh) {
rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
if (route->rt_nr_nh == 0) {
@@ -1445,7 +1472,10 @@
nla_nest_end(msg, metrics);
}
- if (rtnl_route_get_nnexthops(route) == 1) {
+ /* Nexthop specification and nexthop id are mutually exclusive */
+ if (route->ce_mask & ROUTE_ATTR_NHID) {
+ NLA_PUT_U32(msg, RTA_NH_ID, route->rt_nhid);
+ } else if (rtnl_route_get_nnexthops(route) == 1) {
struct rtnl_nexthop *nh;
nh = rtnl_route_nexthop_n(route, 0);
diff --git a/lib/route/tc.c b/lib/route/tc.c
index a2fd567..bbb2f8c 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.c
@@ -678,7 +678,7 @@
int i;
for (i = 0; i < 32; i++)
- if ((((uint32_t)1u) << i) == cell_size)
+ if ((((uint32_t)1u) << i) == ((uint32_t)cell_size))
return i;
return -NLE_INVAL;
diff --git a/lib/socket.c b/lib/socket.c
index 9b42f67..742cdac 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -84,7 +84,7 @@
static uint32_t generate_local_port(void)
{
int i, j, m;
- uint16_t n;
+ uint32_t n;
static uint16_t idx_state = 0;
uint32_t pid = getpid() & 0x3FFFFF;
diff --git a/lib/utils.c b/lib/utils.c
index 4f5fd1a..679078e 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -52,7 +52,6 @@
int nl_debug = 0;
/** @cond SKIP */
-#ifdef NL_DEBUG
struct nl_dump_params nl_debug_dp = {
.dp_type = NL_DUMP_DETAILS,
};
@@ -61,7 +60,7 @@
{
char *nldbg, *end;
- if ((nldbg = getenv("NLDBG"))) {
+ if (NL_DEBUG && (nldbg = getenv("NLDBG"))) {
long level = strtol(nldbg, &end, 0);
if (nldbg != end)
nl_debug = level;
@@ -69,7 +68,6 @@
nl_debug_dp.dp_fd = stderr;
}
-#endif
int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
{
@@ -1071,14 +1069,15 @@
const struct trans_tbl *tbl, size_t tbl_len)
{
size_t i;
+
for (i = 0; i < tbl_len; i++) {
- if (tbl[i].i == type) {
+ if (tbl[i].i == ((uint64_t)type)) {
snprintf(buf, len, "%s", tbl[i].a);
return buf;
}
}
- snprintf(buf, len, "0x%x", type);
+ snprintf(buf, len, "0x%x", (unsigned)type);
return buf;
}
@@ -1171,7 +1170,7 @@
p++;
t = strchr(p, ',');
- len = t ? t - p : strlen(p);
+ len = t ? ((size_t)(t - p)) : strlen(p);
for (i = 0; i < tbl_len; i++)
if (len == strlen(tbl[i].a) &&
!strncasecmp(tbl[i].a, p, len))
@@ -1285,9 +1284,9 @@
NL_CAPABILITY_VERSION_3_7_0,
NL_CAPABILITY_VERSION_3_8_0,
NL_CAPABILITY_VERSION_3_9_0,
- 0,
- 0,
- 0,
+ 0, /* NL_CAPABILITY_VERSION_3_10_0 */
+ 0, /* NL_CAPABILITY_VERSION_3_11_0 */
+ 0, /* NL_CAPABILITY_VERSION_3_12_0 */
0,
0),
/* IMPORTANT: these capability numbers are intended to be universal and stable
diff --git a/lib/xfrm/ae.c b/lib/xfrm/ae.c
index 9af73a8..1898038 100644
--- a/lib/xfrm/ae.c
+++ b/lib/xfrm/ae.c
@@ -122,6 +122,7 @@
#include "nl-default.h"
+#include <time.h>
#include <linux/xfrm.h>
#include <netlink/netlink.h>
diff --git a/lib/xfrm/sa.c b/lib/xfrm/sa.c
index 0c89c71..2fe387d 100644
--- a/lib/xfrm/sa.c
+++ b/lib/xfrm/sa.c
@@ -2372,12 +2372,12 @@
* @{
*/
-static void __attribute__ ((constructor)) xfrm_sa_init(void)
+static void _nl_init xfrm_sa_init(void)
{
nl_cache_mngt_register(&xfrmnl_sa_ops);
}
-static void __attribute__ ((destructor)) xfrm_sa_exit(void)
+static void _nl_exit xfrm_sa_exit(void)
{
nl_cache_mngt_unregister(&xfrmnl_sa_ops);
}
diff --git a/lib/xfrm/sp.c b/lib/xfrm/sp.c
index a996455..814ac48 100644
--- a/lib/xfrm/sp.c
+++ b/lib/xfrm/sp.c
@@ -41,6 +41,7 @@
#include "nl-default.h"
+#include <time.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/object.h>
@@ -1280,7 +1281,7 @@
*
* @return 0 if sucessfull, else -1
*/
-int xfrmnl_sp_set_sec_ctx (struct xfrmnl_sp* sp, unsigned int len __attribute__((unused)), unsigned int exttype, unsigned int alg, unsigned int doi, unsigned int ctx_len, char* ctx_str)
+int xfrmnl_sp_set_sec_ctx (struct xfrmnl_sp* sp, unsigned int len, unsigned int exttype, unsigned int alg, unsigned int doi, unsigned int ctx_len, char* ctx_str)
{
/* Free up the old context string and allocate new one */
if (sp->sec_ctx)
@@ -1367,12 +1368,15 @@
struct xfrmnl_user_tmpl *xfrmnl_sp_usertemplate_n(struct xfrmnl_sp *r, int n)
{
struct xfrmnl_user_tmpl *utmpl;
- uint32_t i;
- if (r->ce_mask & XFRM_SP_ATTR_TMPL && r->nr_user_tmpl > n) {
+ if (r->ce_mask & XFRM_SP_ATTR_TMPL && n >= 0 &&
+ ((unsigned)n) < r->nr_user_tmpl) {
+ uint32_t i;
+
i = 0;
nl_list_for_each_entry(utmpl, &r->usertmpl_list, utmpl_list) {
- if (i == n) return utmpl;
+ if (i == ((unsigned)n))
+ return utmpl;
i++;
}
}
@@ -1449,12 +1453,12 @@
* @{
*/
-static void __attribute__ ((constructor)) xfrm_sp_init(void)
+static void _nl_init xfrm_sp_init(void)
{
nl_cache_mngt_register(&xfrmnl_sp_ops);
}
-static void __attribute__ ((destructor)) xfrm_sp_exit(void)
+static void _nl_exit xfrm_sp_exit(void)
{
nl_cache_mngt_unregister(&xfrmnl_sp_ops);
}
diff --git a/libnl-3.sym b/libnl-3.sym
index bac4fcd..613529c 100644
--- a/libnl-3.sym
+++ b/libnl-3.sym
@@ -372,3 +372,8 @@
libnl_3_6 {
} libnl_3_5;
+
+libnl_3_10 {
+global:
+ nl_cache_mngr_alloc_ex;
+} libnl_3_6;
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
index fa7af45..9cb21f7 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -1314,3 +1314,21 @@
rtnl_link_bond_set_min_links;
rtnl_link_can_get_device_stats;
} libnl_3_8;
+
+libnl_3_10 {
+global:
+ rtnl_link_bridge_enable_vlan;
+ rtnl_link_bridge_get_ageing_time;
+ rtnl_link_bridge_get_vlan_default_pvid;
+ rtnl_link_bridge_set_ageing_time;
+ rtnl_link_bridge_set_master;
+ rtnl_link_bridge_set_nf_call_arptables;
+ rtnl_link_bridge_set_nf_call_iptables;
+ rtnl_link_bridge_set_nf_call_ip6tables;
+ rtnl_link_bridge_set_port_vlan_map_range;
+ rtnl_link_bridge_set_port_vlan_pvid;
+ rtnl_link_bridge_unset_port_vlan_map_range;
+ rtnl_route_get_nhid;
+ rtnl_route_nh_identical;
+ rtnl_route_set_nhid;
+} libnl_3_9;
diff --git a/libnl_blocklist.txt b/libnl_blocklist.txt
new file mode 100644
index 0000000..ed98696
--- /dev/null
+++ b/libnl_blocklist.txt
@@ -0,0 +1,5 @@
+[cfi]
+
+[integer]
+# Intentional overflows in multiple hash functions
+src:*/lib/hash.c
diff --git a/src/lib/utils.c b/src/lib/utils.c
index 2839e27..8afb926 100644
--- a/src/lib/utils.c
+++ b/src/lib/utils.c
@@ -223,7 +223,7 @@
char path[FILENAME_MAX+1];
snprintf(path, sizeof(path), "%s/%s/%s.so",
- PKGLIBDIR, prefix, name);
+ _NL_PKGLIBDIR, prefix, name);
#ifdef HAVE_DLFCN_H
{
diff --git a/tests/check-direct.c b/tests/check-direct.c
index db1f48d..33b7742 100644
--- a/tests/check-direct.c
+++ b/tests/check-direct.c
@@ -5,10 +5,16 @@
#include <check.h>
#include <linux/snmp.h>
+#include <linux/if_bridge.h>
#include <netlink/route/link.h>
+#include <netlink/route/link/bridge.h>
#include "nl-priv-static-route/nl-priv-static-route.h"
+#include "nl-aux-core/nl-core.h"
+
+#define CASES 5
+#define MAX_ATTR 7
START_TEST(static_checks)
{
@@ -53,12 +59,133 @@
}
END_TEST
+static void set_bitmap_range(u_int32_t start, u_int32_t end,
+ struct rtnl_link_bridge_vlan *vlan_info,
+ int untagged)
+{
+ for (u_int32_t i = start; i <= end; i++) {
+ vlan_info->vlan_bitmap[i / 32] |= (((uint32_t)1) << (i % 32));
+ if (untagged) {
+ vlan_info->untagged_bitmap[i / 32] |=
+ (((uint32_t)1) << (i % 32));
+ }
+ }
+}
+
+START_TEST(vlan_attribute_check)
+{
+ struct nlmsghdr *nlh;
+ struct nlattr *a;
+ int attr_count, rem;
+ struct bridge_vlan_info *vlan_attr;
+ struct rtnl_link_bridge_vlan vlan_info[CASES];
+ struct bridge_vlan_info expected_attr[CASES][MAX_ATTR];
+
+ for (int i = 0; i < CASES; i++) {
+ memset(&vlan_info[i], 0, sizeof(struct rtnl_link_bridge_vlan));
+ memset(&expected_attr[i], 0,
+ sizeof(struct bridge_vlan_info) * MAX_ATTR);
+ }
+
+ // Case 1 setting pvid untagged.
+ vlan_info[0].pvid = 1;
+ set_bitmap_range(1, 1, &vlan_info[0], 1);
+ expected_attr[0][0].vid = 1;
+ expected_attr[0][0].flags = BRIDGE_VLAN_INFO_PVID |
+ BRIDGE_VLAN_INFO_UNTAGGED;
+
+ // Case 2 setting vid range.
+ vlan_info[1].pvid = 0;
+ set_bitmap_range(1, 4094, &vlan_info[1], 0);
+ expected_attr[1][0].vid = 1;
+ expected_attr[1][0].flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ expected_attr[1][1].vid = 4094;
+ expected_attr[1][1].flags = BRIDGE_VLAN_INFO_RANGE_END;
+
+ // Case 3 interweaving pvid with vid range.
+ vlan_info[2].pvid = 7;
+ set_bitmap_range(1, 27, &vlan_info[2], 0);
+ set_bitmap_range(7, 7, &vlan_info[2], 1);
+ expected_attr[2][0].vid = 1;
+ expected_attr[2][0].flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ expected_attr[2][1].vid = 6;
+ expected_attr[2][1].flags = BRIDGE_VLAN_INFO_RANGE_END;
+ expected_attr[2][2].vid = 8;
+ expected_attr[2][2].flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ expected_attr[2][3].vid = 27;
+ expected_attr[2][3].flags = BRIDGE_VLAN_INFO_RANGE_END;
+ expected_attr[2][4].vid = 7;
+ expected_attr[2][4].flags = BRIDGE_VLAN_INFO_PVID |
+ BRIDGE_VLAN_INFO_UNTAGGED;
+
+ // Case 4 interweaving untagged and tagged vid ranges.
+ vlan_info[3].pvid = 1;
+ set_bitmap_range(1, 1, &vlan_info[3], 1);
+ set_bitmap_range(1, 25, &vlan_info[3], 0);
+ set_bitmap_range(26, 50, &vlan_info[3], 1);
+ set_bitmap_range(51, 75, &vlan_info[3], 0);
+ expected_attr[3][0].vid = 2;
+ expected_attr[3][0].flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ expected_attr[3][1].vid = 25;
+ expected_attr[3][1].flags = BRIDGE_VLAN_INFO_RANGE_END;
+ expected_attr[3][2].vid = 26;
+ expected_attr[3][2].flags = BRIDGE_VLAN_INFO_RANGE_BEGIN |
+ BRIDGE_VLAN_INFO_UNTAGGED;
+ expected_attr[3][3].vid = 50;
+ expected_attr[3][3].flags = BRIDGE_VLAN_INFO_RANGE_END |
+ BRIDGE_VLAN_INFO_UNTAGGED;
+ expected_attr[3][4].vid = 51;
+ expected_attr[3][4].flags = BRIDGE_VLAN_INFO_RANGE_BEGIN;
+ expected_attr[3][5].vid = 75;
+ expected_attr[3][5].flags = BRIDGE_VLAN_INFO_RANGE_END;
+ expected_attr[3][6].vid = 1;
+ expected_attr[3][6].flags = BRIDGE_VLAN_INFO_PVID |
+ BRIDGE_VLAN_INFO_UNTAGGED;
+
+ // Case 5 individual vid.
+ vlan_info[4].pvid = 0;
+ set_bitmap_range(5, 5, &vlan_info[4], 0);
+ set_bitmap_range(3067, 3067, &vlan_info[4], 1);
+ expected_attr[4][0].vid = 5;
+ expected_attr[4][0].flags = 0;
+ expected_attr[4][1].vid = 3067;
+ expected_attr[4][1].flags = BRIDGE_VLAN_INFO_UNTAGGED;
+
+ for (int i = 0; i < CASES; i++) {
+ _nl_auto_nl_msg struct nl_msg *msg = nlmsg_alloc();
+ attr_count = 0;
+ ck_assert_msg(msg, "Unable to allocate netlink message");
+ ck_assert_int_eq(0,
+ _nl_bridge_fill_vlan_info(msg, &vlan_info[i]));
+
+ nlh = nlmsg_hdr(msg);
+
+ nlmsg_for_each_attr(a, nlh, 0, rem) {
+ ck_assert_msg(expected_attr[i][attr_count].vid != 0,
+ "Attribute number %d unexpected",
+ attr_count);
+ ck_assert_msg(
+ nla_type(a) == IFLA_BRIDGE_VLAN_INFO,
+ "Expected attribute IFLA_BRIDGE_VLAN_INFO %d",
+ IFLA_BRIDGE_VLAN_INFO);
+ vlan_attr = (struct bridge_vlan_info *)nla_data(a);
+ ck_assert_int_eq(vlan_attr->vid,
+ expected_attr[i][attr_count].vid);
+ ck_assert_int_eq(vlan_attr->flags,
+ expected_attr[i][attr_count].flags);
+ attr_count++;
+ }
+ }
+}
+END_TEST
+
static Suite *make_suite(void)
{
Suite *suite = suite_create("Direct");
TCase *tc = tcase_create("Core");
tcase_add_test(tc, static_checks);
+ tcase_add_test(tc, vlan_attribute_check);
suite_add_tcase(suite, tc);
return suite;
}
diff --git a/tests/cksuite-all-addr.c b/tests/cksuite-all-addr.c
index f4ee0dd..cc53333 100644
--- a/tests/cksuite-all-addr.c
+++ b/tests/cksuite-all-addr.c
@@ -176,6 +176,14 @@
!strcmp(nl_addr2str(addr6, buf, sizeof(buf)), addr_str),
"Address translated back to string does not match original");
+ _nl_clear_pointer(&addr6, nl_addr_put);
+
+ ck_assert(nl_addr_parse("default", AF_INET6, &addr6) == 0);
+ ck_assert_int_eq(nl_addr_get_len(addr6), 16);
+ ck_assert_int_eq(nl_addr_get_prefixlen(addr6), 0);
+ ck_assert_mem_eq(nl_addr_get_binary_addr(addr6), ((uint8_t[16]){ 0 }),
+ 16);
+
nl_addr_put(addr6);
nl_addr_put(clone);
}
diff --git a/tests/cksuite-all-attr.c b/tests/cksuite-all-attr.c
index b4ac61f..86e3c6f 100644
--- a/tests/cksuite-all-attr.c
+++ b/tests/cksuite-all-attr.c
@@ -70,7 +70,7 @@
nlmsg_for_each_attr(a, nlh, 0, rem) {
ck_assert_msg(nla_type(a) == i, "Expected attribute %d", i);
i++;
- ck_assert_msg(nla_get_u32(a) == i,
+ ck_assert_msg(nla_get_u32(a) == (unsigned)i,
"Expected attribute value %d", i);
}
@@ -144,6 +144,60 @@
/*****************************************************************************/
+START_TEST(test_nltst_select_route)
+{
+ /* This is a unit test for testing the unit-test helper function
+ * _nltst_select_route_parse(). */
+
+#define _check(str, exp_addr_family, exp_addr_pattern, exp_plen) \
+ do { \
+ const char *_str = (str); \
+ const int _exp_addr_family = (exp_addr_family); \
+ const char *const _exp_addr_pattern = (exp_addr_pattern); \
+ const int _exp_plen = (exp_plen); \
+ _nltst_auto_clear_select_route NLTstSelectRoute \
+ _select_route = { 0 }; \
+ _nltst_auto_clear_select_route NLTstSelectRoute \
+ _select_route2 = { 0 }; \
+ _nl_auto_free char *_str2 = NULL; \
+ \
+ _nltst_select_route_parse(_str, &_select_route); \
+ ck_assert_int_eq(_exp_addr_family, _select_route.addr_family); \
+ if (_nltst_inet_valid(AF_UNSPEC, _exp_addr_pattern)) { \
+ ck_assert_str_eq(_exp_addr_pattern, \
+ _select_route.addr); \
+ ck_assert_ptr_null(_select_route.addr_pattern); \
+ } else { \
+ ck_assert_str_eq(_exp_addr_pattern, \
+ _select_route.addr_pattern); \
+ ck_assert_ptr_null(_select_route.addr); \
+ } \
+ ck_assert_int_eq(_exp_plen, _select_route.plen); \
+ \
+ _nltst_assert_select_route(&_select_route); \
+ \
+ _str2 = _nltst_select_route_to_string(&_select_route); \
+ ck_assert_ptr_nonnull(_str2); \
+ \
+ _nltst_select_route_parse(_str2, &_select_route2); \
+ \
+ ck_assert(_nltst_select_route_equal(&_select_route, \
+ &_select_route2)); \
+ } while (0)
+
+ _check("0.0.0.0", AF_INET, "0.0.0.0", -1);
+ _check("4 0.0.0.0/0", AF_INET, "0.0.0.0", 0);
+ _check(" 6\n 0:0::/0", AF_INET6, "::", 0);
+ _check(" \n 0:0::/100", AF_INET6, "::", 100);
+ _check("6 0:0::*/0 ", AF_INET6, "0:0::*", 0);
+ _check("6 0:0::*/128 ", AF_INET6, "0:0::*", 128);
+ _check("6 0:0::* ", AF_INET6, "0:0::*", -1);
+
+#undef _check
+}
+
+/*****************************************************************************/
+
Suite *make_nl_attr_suite(void)
{
Suite *suite = suite_create("Netlink attributes");
@@ -153,6 +207,7 @@
tcase_add_test(tc, msg_construct);
tcase_add_test(tc, clone_cls_u32);
tcase_add_test(tc, test_nltst_strtok);
+ tcase_add_test(tc, test_nltst_select_route);
suite_add_tcase(suite, tc);
return suite;
diff --git a/tests/cksuite-all-netns.c b/tests/cksuite-all-netns.c
index c6a5ce2..5b9d3a5 100644
--- a/tests/cksuite-all-netns.c
+++ b/tests/cksuite-all-netns.c
@@ -70,7 +70,7 @@
.add = false,
},
};
- int i;
+ size_t i;
int r;
for (i = 0; i < _NL_N_ELEMENTS(links); i++) {
@@ -302,6 +302,36 @@
/*****************************************************************************/
+static void _route_init(int addr_family, struct nl_sock **sk,
+ struct nl_cache **cache)
+{
+ ck_assert(sk && !*sk);
+ ck_assert(cache && !*cache);
+
+ *sk = _nltst_socket(NETLINK_ROUTE);
+ *cache = _nltst_rtnl_route_alloc_cache(*sk, addr_family);
+}
+
+START_TEST(route_1)
+{
+ _nl_auto_nl_socket struct nl_sock *sk = NULL;
+ _nl_auto_nl_cache struct nl_cache *cache = NULL;
+
+ if (_nltst_skip_no_iproute2("route_1"))
+ return;
+
+ _nltst_add_link(NULL, "v1", "dummy", NULL);
+ _nltst_system("ip -d link set v1 up");
+
+ _route_init(AF_INET6, &sk, &cache);
+
+ _nltst_assert_route_cache(cache, "fe80::/64", "6 fe80::*/128",
+ "ff00::/8");
+}
+END_TEST
+
+/*****************************************************************************/
+
Suite *make_nl_netns_suite(void)
{
Suite *suite = suite_create("netns");
@@ -311,7 +341,7 @@
nltst_netns_fixture_teardown);
tcase_add_test(tc, cache_and_clone);
tcase_add_loop_test(tc, test_create_iface, 0, 17);
-
+ tcase_add_test(tc, route_1);
suite_add_tcase(suite, tc);
return suite;
diff --git a/tests/nl-test-util.c b/tests/nl-test-util.c
index 52188a0..6bbe2ae 100644
--- a/tests/nl-test-util.c
+++ b/tests/nl-test-util.c
@@ -5,6 +5,7 @@
#include "nl-test-util.h"
#include <fcntl.h>
+#include <fnmatch.h>
#include <sched.h>
#include <stdio.h>
#include <sys/mount.h>
@@ -14,6 +15,8 @@
#include <netlink/route/route.h>
#include <netlink/socket.h>
+#include "lib/route/nl-route.h"
+
#include "nl-aux-route/nl-route.h"
/*****************************************************************************/
@@ -30,7 +33,7 @@
_nltst_assert_errno(fd >= 0);
nread = read(fd, ptr, len);
- _nltst_assert_errno(nread == len);
+ _nltst_assert_errno(nread >= 0 && ((size_t)nread) == len);
_nltst_close(fd);
}
@@ -217,11 +220,13 @@
/*****************************************************************************/
-char *_nltst_object_to_string(struct nl_object *obj)
+char *_nltst_object_to_string(const struct nl_object *obj)
{
size_t L = 1024;
size_t l;
char *s;
+ struct nl_dump_params dp;
+ char canary;
if (!obj)
return strdup("(null)");
@@ -229,11 +234,31 @@
s = malloc(L);
ck_assert_ptr_nonnull(s);
- nl_object_dump_buf(obj, s, L);
+ canary = _nltst_rand_u32();
+ s[L - 1u] = canary;
+
+ dp = (struct nl_dump_params){
+ .dp_type = NL_DUMP_LINE,
+ .dp_buf = s,
+ .dp_buflen = L - 1u,
+ };
+
+ nl_object_dump((struct nl_object *)obj, &dp);
+
l = strlen(s);
+ ck_assert_int_ge(l, 2);
ck_assert_int_lt(l, L);
+ ck_assert(canary == s[L - 1u]);
s = realloc(s, l + 1);
ck_assert_ptr_nonnull(s);
+
+ ck_assert_msg(s[l - 1u] == '\n',
+ "expects newline after dump. Got \"%s\"", s);
+ s[l - 1u] = '\0';
+
+ ck_assert_msg(!strchr(s, '\n'),
+ "no further newline expected. Got \"%s\"", s);
+
return s;
}
@@ -653,3 +678,366 @@
/* FIXME: we would expect that the cloned object is identical. It is not. */
/* _nltst_object_identical(link, link_clone); */
}
+
+/*****************************************************************************/
+
+bool _nltst_in_ci(void)
+{
+ return _nl_streq0(getenv("NLTST_IN_CI"), "1");
+}
+
+/*****************************************************************************/
+
+bool _nltst_has_iproute2(void)
+{
+ static int has = -1;
+
+ if (has == -1)
+ has = (system("ip link &>/dev/null") == 0);
+
+ return has;
+}
+
+bool _nltst_skip_no_iproute2(const char *msg)
+{
+ if (_nltst_has_iproute2())
+ return false;
+
+ ck_assert_msg(
+ !_nltst_in_ci(),
+ "We seem to not have iproute2, but we are in NLTST_IN_CI=1. This is fatal.");
+
+ printf("skip test due to missing iproute2%s%s%s\n", msg ? " (" : "",
+ msg ?: "", msg ? ")" : "");
+ return true;
+}
+
+/*****************************************************************************/
+
+void _nltst_select_route_clear(NLTstSelectRoute *select_route)
+{
+ _nltst_assert_select_route(select_route);
+
+ _nl_clear_free(&select_route->addr);
+ _nl_clear_free(&select_route->addr_pattern);
+}
+
+int _nltst_select_route_cmp(const NLTstSelectRoute *select_route1,
+ const NLTstSelectRoute *select_route2)
+{
+ _NL_CMP_SELF(select_route1, select_route2);
+ _NL_CMP_FIELD_STR0(select_route1, select_route2, addr);
+ _NL_CMP_FIELD_STR0(select_route1, select_route2, addr_pattern);
+ _NL_CMP_FIELD(select_route1, select_route2, addr_family);
+ _NL_CMP_FIELD(select_route1, select_route2, ifindex);
+ _NL_CMP_FIELD(select_route1, select_route2, plen);
+ return 0;
+}
+
+char *_nltst_select_route_to_string(const NLTstSelectRoute *select_route)
+{
+ char buf[1024];
+ const char *family;
+ char b_plen[100];
+
+ _nltst_assert_select_route(select_route);
+
+ if (select_route->addr_family == AF_INET)
+ family = "4 ";
+ else if (select_route->addr_family == AF_INET6)
+ family = "6 ";
+ else
+ family = "";
+
+ b_plen[0] = '\0';
+ if (select_route->plen != -1)
+ _nltst_sprintf_arr(b_plen, "/%d", select_route->plen);
+
+ _nltst_sprintf_arr(buf,
+ "%s"
+ "%s"
+ "%s"
+ "",
+ family,
+ select_route->addr_pattern ?: select_route->addr,
+ b_plen);
+ return _nltst_strdup(buf);
+}
+
+void _nltst_select_route_parse(const char *str,
+ NLTstSelectRoute *out_select_route)
+{
+ _nltst_auto_strfreev char **tokens0 = NULL;
+ const char *const *tokens;
+ int addr_family = AF_UNSPEC;
+ int addr_family2 = AF_UNSPEC;
+ NLTstIPAddr addr;
+ int plen = -1;
+ _nl_auto_free char *addr_free = NULL;
+ const char *s_addr_pattern;
+ const char *s_addr = NULL;
+ const char *s;
+ const char *s1;
+
+ ck_assert_ptr_nonnull(str);
+ _nltst_assert_select_route(out_select_route);
+
+ tokens0 = _nltst_strtokv(str);
+ tokens = (const char *const *)tokens0;
+
+ s = tokens[0];
+ if (!s)
+ ck_abort_msg("invalid empty route pattern \"%s\"", str);
+ if (_nl_streq(s, "4") || _nl_streq(s, "inet") ||
+ _nl_streq(s, "inet4")) {
+ addr_family = AF_INET;
+ tokens++;
+ } else if (_nl_streq(s, "6") || _nl_streq(s, "inet6")) {
+ addr_family = AF_INET6;
+ tokens++;
+ }
+
+ s_addr_pattern = tokens[0];
+ if (!s_addr_pattern) {
+ ck_abort_msg(
+ "the route pattern \"%s\" is invalid and contains no destination address",
+ str);
+ }
+ tokens++;
+
+ s = strchr(s_addr_pattern, '/');
+ if (s) {
+ long int plen2;
+
+ if (s == s_addr_pattern) {
+ ck_abort_msg(
+ "the route pattern \"%s\" contains no valid destination address",
+ str);
+ }
+ addr_free = strndup(s_addr_pattern, s - s_addr_pattern);
+ s_addr_pattern = addr_free;
+ s++;
+
+ errno = 0;
+ plen2 = strtol(s, (char **)&s1, 10);
+ if (errno != 0 || s1[0] != '\0' || plen2 < 0 || plen2 > 128 ||
+ ((_nltst_str_find_first_not_from_charset(
+ s, "0123456789"))[0] != '\0')) {
+ ck_abort_msg(
+ "the route pattern \"%s\" contains no valid destination address",
+ str);
+ }
+ plen = plen2;
+ }
+ if ((_nltst_str_find_first_not_from_charset(
+ s_addr_pattern, "abcdefABCDEF0123456789:.?*"))[0] != '\0') {
+ ck_abort_msg(
+ "the route pattern \"%s\" contains no valid destination address",
+ str);
+ }
+ if (_nltst_inet_pton(addr_family, s_addr_pattern, &addr_family2,
+ &addr)) {
+ free(addr_free);
+ addr_free = _nltst_inet_ntop_dup(addr_family2, &addr);
+ s_addr_pattern = addr_free;
+ addr_family = addr_family2;
+ } else {
+ if (addr_family == AF_UNSPEC) {
+ ck_abort_msg(
+ "the route pattern \"%s\" contains a wild card address, it requires the address family",
+ str);
+ }
+ }
+
+ ck_assert(addr_family == AF_INET || addr_family == AF_INET6);
+
+ if (plen > (addr_family == AF_INET ? 32 : 128)) {
+ ck_abort_msg(
+ "the route pattern \"%s\" contains no valid destination address (prefix length too large)",
+ str);
+ }
+ ck_assert_int_ge(plen, -1);
+
+ s = tokens[0];
+ if (s) {
+ ck_abort_msg("the route pattern \"%s\" contains extra tokens",
+ str);
+ }
+
+ if (_nltst_inet_valid(addr_family, s_addr_pattern))
+ _NL_SWAP(&s_addr, &s_addr_pattern);
+
+ _nltst_select_route_clear(out_select_route);
+ memset(out_select_route, 0, sizeof(*out_select_route));
+ *out_select_route = (NLTstSelectRoute){
+ .addr_family = addr_family,
+ .plen = plen,
+ .ifindex = 0,
+ .addr = s_addr ? strdup(s_addr) : NULL,
+ .addr_pattern = s_addr_pattern ? strdup(s_addr_pattern) : NULL,
+ };
+ ck_assert(!s_addr || out_select_route->addr);
+ ck_assert(!s_addr_pattern || out_select_route->addr_pattern);
+ _nltst_assert_select_route(out_select_route);
+}
+
+bool _nltst_select_route_match(struct nl_object *route,
+ const NLTstSelectRoute *select_route,
+ bool do_assert)
+{
+ struct nl_addr *addr;
+ struct rtnl_route *route_;
+ int i;
+ char sbuf1[200];
+
+ ck_assert_ptr_nonnull(route);
+ ck_assert_str_eq(nl_object_get_type(route), "route/route");
+
+ if (!select_route)
+ return true;
+
+ route_ = (struct rtnl_route *)route;
+
+ _nltst_assert_select_route(select_route);
+
+#define _check(cond, msg, ...) \
+ do { \
+ if (do_assert) { \
+ _nl_auto_free char *s1 = NULL; \
+ _nl_auto_free char *s2 = NULL; \
+ \
+ ck_assert_msg( \
+ (cond), \
+ "Checking condition \"%s\" for route \"%s\" (expected \"%s\") failed (msg: " msg \
+ ")", \
+ #cond, (s1 = _nltst_object_to_string(route)), \
+ (s2 = _nltst_select_route_to_string( \
+ select_route)), \
+ ##__VA_ARGS__); \
+ } else if (cond) { \
+ } else { \
+ return false; \
+ } \
+ } while (0)
+
+ if (select_route->addr_family != AF_UNSPEC) {
+ _check(rtnl_route_get_family(route_) ==
+ select_route->addr_family,
+ "mismatching address family");
+ }
+
+ if (select_route->ifindex != 0) {
+ struct nl_list_head *list;
+ struct rtnl_nexthop *nh;
+ size_t n;
+ struct rtnl_nexthop *nh2;
+
+ list = rtnl_route_get_nexthops(route_);
+ _check(list, "no nexthops for ifindex");
+
+ n = 0;
+ nl_list_for_each_entry(nh, list, rtnh_list) {
+ nh2 = nh;
+ n++;
+ }
+ _check(n == 1, "expects one nexthop for ifindex but got %zu",
+ n);
+ ck_assert_ptr_nonnull(nh2);
+
+ i = rtnl_route_nh_get_ifindex(nh2);
+ _check(i == select_route->ifindex,
+ "route has unexpected ifindex %d for next hop", i);
+ }
+
+ addr = rtnl_route_get_dst(route_);
+
+ if (addr) {
+ if (select_route->addr_family != AF_UNSPEC) {
+ _check(nl_addr_get_family(addr) ==
+ select_route->addr_family,
+ "unexecpted address family of dst");
+ }
+ }
+
+ if (select_route->plen != -1) {
+ _check(addr, "missing address");
+ _check(nl_addr_get_prefixlen(addr) ==
+ (unsigned)select_route->plen,
+ "unexpected prefix length");
+ }
+ if (select_route->addr || select_route->addr_pattern) {
+ _check(addr, "missing address");
+
+ _nl_inet_ntop(nl_addr_get_family(addr),
+ nl_addr_get_binary_addr(addr), sbuf1);
+
+ ck_assert(strlen(sbuf1) > 0);
+ ck_assert(strlen(sbuf1) < sizeof(sbuf1));
+
+ if (select_route->addr) {
+ _check(_nl_streq(sbuf1, select_route->addr),
+ "unexpected address, \"%s\" does not match \"%s\"",
+ sbuf1, select_route->addr);
+ }
+ if (select_route->addr_pattern) {
+ _check(fnmatch(select_route->addr_pattern, sbuf1, 0) ==
+ 0,
+ "unexpected address, \"%s\" does not match pattern \"%s\"",
+ sbuf1, select_route->addr_pattern);
+ }
+ }
+
+#undef _check
+
+ return false;
+}
+
+/*****************************************************************************/
+
+void _nltst_assert_route_list(struct nl_object *const *objs, ssize_t len,
+ const char *const *expected_routes)
+{
+ size_t l;
+ size_t i;
+
+ if (len < 0) {
+ l = 0;
+ if (objs) {
+ while (objs[l])
+ l++;
+ }
+ } else
+ l = len;
+
+ for (i = 0; i < l; i++) {
+ struct nl_object *route = objs[i];
+ _nltst_auto_clear_select_route NLTstSelectRoute select_route = {
+ 0
+ };
+ _nl_auto_free char *s = _nltst_object_to_string(route);
+
+ if (!expected_routes[i]) {
+ ck_abort_msg(
+ "No more expected route, but have route %zu (of %zu) as %s",
+ i + 1, l, s);
+ }
+
+ _nltst_select_route_parse(expected_routes[i], &select_route);
+
+ _nltst_select_route_match(route, &select_route, true);
+ }
+}
+
+void _nltst_assert_route_cache_v(struct nl_cache *cache,
+ const char *const *expected_routes)
+{
+ _nl_auto_free struct nl_object **objs = NULL;
+ size_t len;
+
+ ck_assert(cache);
+ ck_assert(expected_routes);
+
+ objs = _nltst_cache_get_all(cache, &len);
+
+ _nltst_assert_route_list(objs, len, expected_routes);
+}
diff --git a/tests/nl-test-util.h b/tests/nl-test-util.h
index ee4bd96..b751cc5 100644
--- a/tests/nl-test-util.h
+++ b/tests/nl-test-util.h
@@ -36,12 +36,12 @@
#endif
#ifndef ck_assert_pstr_ne
-#define ck_assert_pstr_ne(a, b) \
- do { \
- const char *_a = (a); \
- const char *_b = (b); \
- \
- ck_assert(!(_a == _b || (_a && _b && strcmp(_a, _b) == 0))); \
+#define ck_assert_pstr_ne(a, b) \
+ do { \
+ const char *_a = (a); \
+ const char *_b = (b); \
+ \
+ ck_assert(!(_a == _b || (_a && _b && strcmp(_a, _b) == 0))); \
} while (0)
#endif
@@ -51,6 +51,46 @@
/*****************************************************************************/
+#define __nltst_assert_nonnull(uniq, x) \
+ ({ \
+ typeof(x) _NL_UNIQ_T(_x, uniq) = (x); \
+ \
+ ck_assert_ptr_nonnull(_NL_UNIQ_T(_x, uniq)); \
+ \
+ _NL_UNIQ_T(_x, uniq); \
+ })
+
+#define _nltst_assert_nonnull(x) __nltst_assert_nonnull(_NL_UNIQ, x)
+
+static inline char *_nltst_strdup(const char *str)
+{
+ return str ? _nltst_assert_nonnull(strdup(str)) : NULL;
+}
+
+/*****************************************************************************/
+
+#define __nltst_sprintf_arr(uniq, arr, fmt, ...) \
+ ({ \
+ char *const _NL_UNIQ_T(arr, uniq) = (arr); \
+ int _NL_UNIQ_T(c, uniq); \
+ \
+ _NL_STATIC_ASSERT(sizeof(arr) > \
+ sizeof(_NL_UNIQ_T(arr, uniq))); \
+ \
+ _NL_UNIQ_T(c, uniq) = snprintf(_NL_UNIQ_T(arr, uniq), \
+ sizeof(arr), fmt, \
+ ##__VA_ARGS__); \
+ \
+ ck_assert_int_lt(_NL_UNIQ_T(c, uniq), sizeof(arr)); \
+ \
+ _NL_UNIQ_T(arr, uniq); \
+ })
+
+#define _nltst_sprintf_arr(arr, fmt, ...) \
+ __nltst_sprintf_arr(_NL_UNIQ, arr, fmt, ##__VA_ARGS__)
+
+/*****************************************************************************/
+
void _nltst_get_urandom(void *ptr, size_t len);
uint32_t _nltst_rand_u32(void);
@@ -78,34 +118,34 @@
return _nltst_rand_u32() % 2 == 0;
}
-#define _nltst_rand_select(a, ...) \
- ({ \
- const typeof(a) _lst[] = { (a), ##__VA_ARGS__ }; \
- \
- _lst[_nltst_rand_u32_range(_NL_N_ELEMENTS(_lst))]; \
+#define _nltst_rand_select(a, ...) \
+ ({ \
+ const typeof(a) _lst[] = { (a), ##__VA_ARGS__ }; \
+ \
+ _lst[_nltst_rand_u32_range(_NL_N_ELEMENTS(_lst))]; \
})
/*****************************************************************************/
-#define _nltst_assert(expr) \
- ({ \
- typeof(expr) _expr = (expr); \
- \
- if (!_expr) { \
- ck_assert_msg(0, "assert(%s) failed", #expr); \
- } \
- _expr; \
+#define _nltst_assert(expr) \
+ ({ \
+ typeof(expr) _expr = (expr); \
+ \
+ if (!_expr) { \
+ ck_assert_msg(0, "assert(%s) failed", #expr); \
+ } \
+ _expr; \
})
-#define _nltst_assert_errno(expr) \
- do { \
- if (expr) { \
- } else { \
- const int _errno = (errno); \
- \
- ck_assert_msg(0, "assert(%s) failed (errno=%d, %s)", \
- #expr, _errno, strerror(_errno)); \
- } \
+#define _nltst_assert_errno(expr) \
+ do { \
+ if (expr) { \
+ } else { \
+ const int _errno = (errno); \
+ \
+ ck_assert_msg(0, "assert(%s) failed (errno=%d, %s)", \
+ #expr, _errno, strerror(_errno)); \
+ } \
} while (0)
#define _nltst_assert_retcode(expr) \
@@ -125,28 +165,28 @@
} \
} while (0)
-#define _nltst_close(fd) \
- do { \
- int _r; \
- \
- _r = _nl_close((fd)); \
- _nltst_assert_errno(_r == 0); \
+#define _nltst_close(fd) \
+ do { \
+ int _r; \
+ \
+ _r = _nl_close((fd)); \
+ _nltst_assert_errno(_r == 0); \
} while (0)
-#define _nltst_fclose(f) \
- do { \
- int _r; \
- \
- _r = fclose((f)); \
- _nltst_assert_errno(_r == 0); \
+#define _nltst_fclose(f) \
+ do { \
+ int _r; \
+ \
+ _r = fclose((f)); \
+ _nltst_assert_errno(_r == 0); \
} while (0)
void _nltst_assert_link_exists_full(const char *ifname, bool exists);
-#define _nltst_assert_link_exists(ifname) \
+#define _nltst_assert_link_exists(ifname) \
_nltst_assert_link_exists_full((ifname), true)
-#define _nltst_assert_link_not_exists(ifname) \
+#define _nltst_assert_link_not_exists(ifname) \
_nltst_assert_link_exists_full((ifname), false)
/*****************************************************************************/
@@ -167,11 +207,11 @@
r = (char *)inet_ntop(addr_family, addr, buf,
(addr_family == AF_INET) ? INET_ADDRSTRLEN :
- INET6_ADDRSTRLEN);
+ INET6_ADDRSTRLEN);
ck_assert_ptr_eq(r, buf);
ck_assert_int_lt(strlen(r), (addr_family == AF_INET) ?
INET_ADDRSTRLEN :
- INET6_ADDRSTRLEN);
+ INET6_ADDRSTRLEN);
return r;
}
@@ -180,7 +220,7 @@
return (char *)_nltst_inet_ntop(addr_family, addr,
malloc((addr_family == AF_INET) ?
INET_ADDRSTRLEN :
- INET6_ADDRSTRLEN));
+ INET6_ADDRSTRLEN));
}
static inline bool _nltst_inet_pton(int addr_family, const char *str,
@@ -209,7 +249,7 @@
if (out_addr) {
memcpy(out_addr, &a,
addr_family == AF_INET ? sizeof(in_addr_t) :
- sizeof(struct in6_addr));
+ sizeof(struct in6_addr));
}
if (out_addr_family)
*out_addr_family = addr_family;
@@ -270,24 +310,24 @@
char **_nltst_strtokv(const char *str);
-#define _nltst_assert_strv_equal(strv1, strv2) \
- do { \
- typeof(strv1) _strv1 = (strv1); \
- typeof(strv2) _strv2 = (strv2); \
- _nl_unused const void *_strv1_typecheck1 = _strv1; \
- _nl_unused const void *_strv2_typecheck1 = _strv2; \
- _nl_unused const char *_strv1_typecheck2 = \
- _strv1 ? _strv1[0] : NULL; \
- _nl_unused const char *_strv2_typecheck2 = \
- _strv2 ? _strv2[0] : NULL; \
- size_t _i; \
- \
- ck_assert_int_eq(!!_strv1, !!_strv2); \
- if (_strv1) { \
- for (_i = 0; _strv1[_i] || _strv2[_i]; _i++) { \
- ck_assert_str_eq(_strv1[_i], _strv2[_i]); \
- } \
- } \
+#define _nltst_assert_strv_equal(strv1, strv2) \
+ do { \
+ typeof(strv1) _strv1 = (strv1); \
+ typeof(strv2) _strv2 = (strv2); \
+ _nl_unused const void *_strv1_typecheck1 = _strv1; \
+ _nl_unused const void *_strv2_typecheck1 = _strv2; \
+ _nl_unused const char *_strv1_typecheck2 = \
+ _strv1 ? _strv1[0] : NULL; \
+ _nl_unused const char *_strv2_typecheck2 = \
+ _strv2 ? _strv2[0] : NULL; \
+ size_t _i; \
+ \
+ ck_assert_int_eq(!!_strv1, !!_strv2); \
+ if (_strv1) { \
+ for (_i = 0; _strv1[_i] || _strv2[_i]; _i++) { \
+ ck_assert_str_eq(_strv1[_i], _strv2[_i]); \
+ } \
+ } \
} while (0)
#define _NLTST_CHARSET_SPACE " \n\r\t"
@@ -296,64 +336,64 @@
#define _nltst_char_is_space(ch) _nltst_char_is(ch, _NLTST_CHARSET_SPACE)
-#define _nltst_str_skip_predicate(s, ch, predicate) \
- ({ \
- typeof(s) _s1 = (s); \
- _nl_unused const char *_s1_typecheck = (_s1); \
- \
- if (_s1) { \
- while (({ \
- const char ch = _s1[0]; \
- \
- (ch != '\0') && (predicate); \
- })) \
- _s1++; \
- } \
- _s1; \
+#define _nltst_str_skip_predicate(s, ch, predicate) \
+ ({ \
+ typeof(s) _s1 = (s); \
+ _nl_unused const char *_s1_typecheck = (_s1); \
+ \
+ if (_s1) { \
+ while (({ \
+ const char ch = _s1[0]; \
+ \
+ (ch != '\0') && (predicate); \
+ })) \
+ _s1++; \
+ } \
+ _s1; \
})
-#define _nltst_str_skip_charset(s, charset) \
+#define _nltst_str_skip_charset(s, charset) \
_nltst_str_skip_predicate(s, _ch, _nltst_char_is(_ch, "" charset ""))
-#define _nltst_str_skip_space(s) \
+#define _nltst_str_skip_space(s) \
_nltst_str_skip_charset(s, _NLTST_CHARSET_SPACE)
-#define _nltst_str_has_prefix_and_space(s, prefix) \
- ({ \
- typeof(s) _s2 = (s); \
- _nl_unused const char *_s2_typecheck = (_s2); \
- const size_t _l = strlen("" prefix ""); \
- \
- if (_s2) { \
- if ((strncmp(_s2, "" prefix "", _l)) == 0 && \
- _nltst_char_is_space(_s2[_l])) \
- _s2 = _nltst_str_skip_space(&_s2[_l + 1]); \
- else \
- _s2 = NULL; \
- } \
- _s2; \
+#define _nltst_str_has_prefix_and_space(s, prefix) \
+ ({ \
+ typeof(s) _s2 = (s); \
+ _nl_unused const char *_s2_typecheck = (_s2); \
+ const size_t _l = strlen("" prefix ""); \
+ \
+ if (_s2) { \
+ if ((strncmp(_s2, "" prefix "", _l)) == 0 && \
+ _nltst_char_is_space(_s2[_l])) \
+ _s2 = _nltst_str_skip_space(&_s2[_l + 1]); \
+ else \
+ _s2 = NULL; \
+ } \
+ _s2; \
})
-#define _nltst_str_find_first_not_from_charset(s, charset) \
- ({ \
- typeof(s) _s3 = (s); \
- _nl_unused const char *_s3_typecheck = (_s3); \
- size_t _l3; \
- \
- _l3 = strspn(_s3, "" charset ""); \
- \
- &_s3[_l3]; \
+#define _nltst_str_find_first_not_from_charset(s, charset) \
+ ({ \
+ typeof(s) _s3 = (s); \
+ _nl_unused const char *_s3_typecheck = (_s3); \
+ size_t _l3; \
+ \
+ _l3 = strspn(_s3, "" charset ""); \
+ \
+ &_s3[_l3]; \
})
-#define _nltst_str_find_first_from_charset(s, charset) \
- ({ \
- typeof(s) _s3 = (s); \
- _nl_unused const char *_s3_typecheck = (_s3); \
- size_t _l3; \
- \
- _l3 = strcspn(_s3, "" charset ""); \
- \
- &_s3[_l3]; \
+#define _nltst_str_find_first_from_charset(s, charset) \
+ ({ \
+ typeof(s) _s3 = (s); \
+ _nl_unused const char *_s3_typecheck = (_s3); \
+ size_t _l3; \
+ \
+ _l3 = strcspn(_s3, "" charset ""); \
+ \
+ &_s3[_l3]; \
})
/*****************************************************************************/
@@ -368,9 +408,82 @@
/*****************************************************************************/
+#define _nltst_system(command) _nltst_assert_retcode(system(command))
+
+bool _nltst_in_ci(void);
+
+bool _nltst_has_iproute2(void);
+bool _nltst_skip_no_iproute2(const char *msg);
+
+/*****************************************************************************/
+
+typedef struct {
+ int addr_family;
+ int ifindex;
+ int plen;
+ char *addr;
+ char *addr_pattern;
+} NLTstSelectRoute;
+
+#define _nltst_assert_select_route(select_route) \
+ do { \
+ const NLTstSelectRoute *_select_route_5 = (select_route); \
+ \
+ ck_assert_ptr_nonnull(_select_route_5); \
+ _nl_assert_addr_family_or_unspec( \
+ _select_route_5->addr_family); \
+ ck_assert_int_ge(_select_route_5->ifindex, 0); \
+ ck_assert_int_ge(_select_route_5->plen, -1); \
+ ck_assert_int_le( \
+ _select_route_5->plen, \
+ _select_route_5->addr_family == AF_INET ? 32 : 128); \
+ ck_assert(!_select_route_5->addr || ({ \
+ char _buf[INET6_ADDRSTRLEN]; \
+ const char *_s2; \
+ \
+ _s2 = _nltst_inet_normalize( \
+ _select_route_5->addr_family, \
+ _select_route_5->addr, _buf); \
+ (_select_route_5->addr_family != AF_UNSPEC && _s2 && \
+ _nl_streq(_s2, _select_route_5->addr)); \
+ })); \
+ ck_assert(!_select_route_5->addr_pattern || \
+ !_select_route_5->addr); \
+ ck_assert(!_select_route_5->addr_pattern || \
+ _select_route_5->addr_family != AF_UNSPEC); \
+ } while (0)
+
+void _nltst_select_route_clear(NLTstSelectRoute *select_route);
+
+#define _nltst_auto_clear_select_route \
+ _nl_auto(_nltst_auto_clear_select_route_fcn)
+_NL_AUTO_DEFINE_FCN_STRUCT(NLTstSelectRoute, _nltst_auto_clear_select_route_fcn,
+ _nltst_select_route_clear);
+
+int _nltst_select_route_cmp(const NLTstSelectRoute *select_route1,
+ const NLTstSelectRoute *select_route2);
+
+static inline bool
+_nltst_select_route_equal(const NLTstSelectRoute *select_route1,
+ const NLTstSelectRoute *select_route2)
+{
+ return _nltst_select_route_cmp(select_route1, select_route2) == 0;
+}
+
+char *_nltst_select_route_to_string(const NLTstSelectRoute *select_route);
+
+void _nltst_select_route_parse(const char *str,
+ NLTstSelectRoute *out_select_route);
+
+bool _nltst_select_route_match(struct nl_object *route,
+ const NLTstSelectRoute *select_route,
+ bool do_assert);
+
+/*****************************************************************************/
+
void _nltst_object_identical(const void *a, const void *b);
-char *_nltst_object_to_string(struct nl_object *obj);
+char *_nltst_object_to_string(const struct nl_object *obj);
struct nl_object **_nltst_cache_get_all(struct nl_cache *cache,
size_t *out_len);
@@ -394,4 +507,14 @@
void _nltst_get_link(struct nl_sock *sk, const char *ifname, int *out_ifindex,
struct rtnl_link **out_link);
+void _nltst_assert_route_list(struct nl_object *const *objs, ssize_t len,
+ const char *const *expected_routes);
+
+void _nltst_assert_route_cache_v(struct nl_cache *cache,
+ const char *const *expected_routes);
+
+#define _nltst_assert_route_cache(cache, ...) \
+ _nltst_assert_route_cache_v(cache, \
+ ((const char *const[200]){ __VA_ARGS__ }))
+
#endif /* __NL_TEST_UTIL_H__ */
diff --git a/tools/clang-format.sh b/tools/clang-format.sh
index 6a0db2a..40c3f7a 100755
--- a/tools/clang-format.sh
+++ b/tools/clang-format.sh
@@ -334,7 +334,6 @@
"src/nl-rule-list.c"
"src/nl-tctree-list.c"
"src/nl-util-addr.c"
- "tests/nl-test-util.h"
"tests/test-cache-mngr.c"
"tests/test-complex-HTB-with-hash-filters.c"
"tests/test-create-bridge.c"