dect
/
libnl
Archived
1
0
Fork 0

Merge /home/kaber/src/repos/libnl.git

master
Patrick McHardy 10 years ago
commit 6ae22c1b39
  1. 24
      configure.ac
  2. 2
      doc/configure.ac
  3. 57
      doc/route.txt
  4. 1
      include/Makefile.am
  5. 2
      include/netlink-private/genl.h
  6. 23
      include/netlink-private/netlink.h
  7. 2
      include/netlink/netfilter/queue_msg.h
  8. 46
      include/netlink/route/link/macvlan.h
  9. 2
      lib/Makefile.am
  10. 8
      lib/addr.c
  11. 4
      lib/attr.c
  12. 62
      lib/cache.c
  13. 2
      lib/cache_mngr.c
  14. 9
      lib/genl/ctrl.c
  15. 30
      lib/genl/mngt.c
  16. 144
      lib/msg.c
  17. 63
      lib/netfilter/ct.c
  18. 41
      lib/netfilter/queue_msg.c
  19. 7
      lib/nl.c
  20. 11
      lib/object.c
  21. 4
      lib/route/link/api.c
  22. 367
      lib/route/link/macvlan.c
  23. 2
      lib/route/neigh.c
  24. 6
      lib/route/route_obj.c
  25. 17
      lib/socket.c
  26. 4
      lib/utils.c
  27. 16
      python/netlink/route/capi.i
  28. 9
      tests/Makefile.am
  29. 2
      tests/check-all.c
  30. 88
      tests/check-attr.c
  31. 48
      tests/test-create-macvlan.c
  32. 5
      tests/util.h

@ -13,7 +13,7 @@
# copied from glib
m4_define([libnl_major_version], [3])
m4_define([libnl_minor_version], [2])
m4_define([libnl_micro_version], [21])
m4_define([libnl_micro_version], [22])
# The following explanation may help to understand the above rules a bit
@ -34,9 +34,9 @@ m4_define([libnl_micro_version], [21])
# 3. Programs may need to be changed, recompiled, relinked in order to use
# the new version. Bump current, set revision and age to 0.
m4_define([libnl_lt_current], [216])
m4_define([libnl_lt_revision], [1])
m4_define([libnl_lt_age], [16])
m4_define([libnl_lt_current], [217])
m4_define([libnl_lt_revision], [0])
m4_define([libnl_lt_age], [17])
m4_define([libnl_version],
[libnl_major_version.libnl_minor_version.libnl_micro_version])
@ -75,7 +75,12 @@ AC_CHECK_PROGS(YACC, 'bison -y')
AC_C_CONST
AC_C_INLINE
AM_PATH_CHECK()
PKG_CHECK_MODULES([CHECK], [check >= 0.9.0],
[enable_unit_tests="yes"],
[AC_MSG_WARN([*** Disabling building of unit tests])
enable_unit_tests="no"])
AM_CONDITIONAL([ENABLE_UNIT_TESTS], [test "$enable_unit_tests" = "yes"])
AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
[Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),
@ -92,6 +97,11 @@ AC_ARG_ENABLE([pthreads],
[enable_pthreads="$enableval"], [enable_pthreads="yes"])
AM_CONDITIONAL([DISABLE_PTHREADS], [test "$enable_pthreads" = "no"])
AC_ARG_ENABLE([debug],
AS_HELP_STRING([--disable-debug], [Do not include debugging statements]),
[enable_debug="$enableval"], [enable_debug="yes"])
AM_CONDITIONAL([ENABLE_DEBUG], [test "$enable_debug" = "no" ])
AC_CHECK_LIB([m], [pow], [], AC_MSG_ERROR([libm is required]))
if test "x$enable_pthreads" = "xno"; then
@ -100,6 +110,10 @@ else
AC_CHECK_LIB([pthread], [pthread_mutex_lock], [], AC_MSG_ERROR([libpthread is required]))
fi
if test "x$enable_debug" = "xyes"; then
AC_DEFINE([NL_DEBUG], [1], [Define to 1 to enable debugging])
fi
AC_CONFIG_SUBDIRS([doc])
AC_CONFIG_FILES([

@ -9,7 +9,7 @@
# Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
#
AC_INIT(libnl-doc, [3.2.21], [http://www.infradead.org/~tgr/libnl/])
AC_INIT(libnl-doc, [3.2.22], [http://www.infradead.org/~tgr/libnl/])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([foreign])

@ -706,6 +706,63 @@ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0)
rtnl_link_put(link);
-----
[[link_macvlan]]
==== MACVLAN
[source,c]
-----
extern struct rtnl_link *rtnl_link_macvlan_alloc(void);
extern int rtnl_link_is_macvlan(struct rtnl_link *);
extern char * rtnl_link_macvlan_mode2str(int, char *, size_t);
extern int rtnl_link_macvlan_str2mode(const char *);
extern char * rtnl_link_macvlan_flags2str(int, char *, size_t);
extern int rtnl_link_macvlan_str2flags(const char *);
extern int rtnl_link_macvlan_set_mode(struct rtnl_link *,
uint32_t);
extern uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *);
extern int rtnl_link_macvlan_set_flags(struct rtnl_link *,
uint16_t);
extern int rtnl_link_macvlan_unset_flags(struct rtnl_link *,
uint16_t);
extern uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *);
-----
.Example: Add a MACVLAN device
[source,c]
-----
struct rtnl_link *link;
int master_index;
struct nl_addr* addr;
/* lookup interface index of eth0 */
if (!(master_index = rtnl_link_name2i(link_cache, "eth0")))
/* error */
/* allocate new link object of type macvlan */
link = rtnl_link_macvlan_alloc();
/* set eth0 to be our master device */
rtnl_link_set_link(link, master_index);
/* set address of virtual interface */
addr = nl_addr_build(AF_LLC, ether_aton("00:11:22:33:44:55"), ETH_ALEN);
rtnl_link_set_addr(link, addr);
nl_addr_put(addr);
/* set mode of virtual interface */
rtnl_link_macvlan_set_mode(link, rtnl_link_macvlan_str2mode("bridge"));
if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0)
/* error */
rtnl_link_put(link);
-----
== Neighbouring
== Routing

@ -52,6 +52,7 @@ nobase_libnlinclude_HEADERS = \
netlink/route/link/can.h \
netlink/route/link/inet.h \
netlink/route/link/vlan.h \
netlink/route/link/macvlan.h \
netlink/route/qdisc/cbq.h \
netlink/route/qdisc/dsmark.h \
netlink/route/qdisc/fifo.h \

@ -17,4 +17,6 @@
#define GENL_HDRSIZE(hdrlen) (GENL_HDRLEN + (hdrlen))
extern int genl_resolve_id(struct genl_ops *ops);
#endif

@ -80,24 +80,29 @@ struct trans_list {
struct nl_list_head list;
};
#define NL_DEBUG 1
#define NL_DBG(LVL,FMT,ARG...) \
do { \
if (LVL <= nl_debug) \
fprintf(stderr, "DBG<" #LVL ">: " FMT, ##ARG); \
#ifdef NL_DEBUG
#define NL_DBG(LVL,FMT,ARG...) \
do { \
if (LVL <= nl_debug) \
fprintf(stderr, \
"DBG<" #LVL ">%20s:%-4u %s: " FMT, \
__FILE__, __LINE__, \
__PRETTY_FUNCTION__, ##ARG); \
} while (0)
#else /* NL_DEBUG */
#define NL_DBG(LVL,FMT,ARG...) do { } while(0)
#endif /* NL_DEBUG */
#define BUG() \
do { \
NL_DBG(1, "BUG: %s:%d\n", \
__FILE__, __LINE__); \
fprintf(stderr, "BUG at file position %s:%d:%s\n", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
assert(0); \
} while (0)
#define APPBUG(msg) \
do { \
NL_DBG(1, "APPLICATION BUG: %s:%d:%s: %s\n", \
fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n", \
__FILE__, __LINE__, __PRETTY_FUNCTION__, msg); \
assert(0); \
} while(0)

@ -93,6 +93,8 @@ extern unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *);
extern struct nl_msg * nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *);
extern int nfnl_queue_msg_send_verdict(struct nl_sock *,
const struct nfnl_queue_msg *);
extern int nfnl_queue_msg_send_verdict_batch(struct nl_sock *,
const struct nfnl_queue_msg *);
extern int nfnl_queue_msg_send_verdict_payload(struct nl_sock *,
const struct nfnl_queue_msg *,
const void *, unsigned );

@ -0,0 +1,46 @@
/*
* netlink/route/link/macvlan.h MACVLAN interface
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2013 Michael Braun <michael-dev@fami-braun.de>
*/
#ifndef NETLINK_LINK_MACVLAN_H_
#define NETLINK_LINK_MACVLAN_H_
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#ifdef __cplusplus
extern "C" {
#endif
extern struct rtnl_link *rtnl_link_macvlan_alloc(void);
extern int rtnl_link_is_macvlan(struct rtnl_link *);
extern char * rtnl_link_macvlan_mode2str(int, char *, size_t);
extern int rtnl_link_macvlan_str2mode(const char *);
extern char * rtnl_link_macvlan_flags2str(int, char *, size_t);
extern int rtnl_link_macvlan_str2flags(const char *);
extern int rtnl_link_macvlan_set_mode(struct rtnl_link *,
uint32_t);
extern uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *);
extern int rtnl_link_macvlan_set_flags(struct rtnl_link *,
uint16_t);
extern int rtnl_link_macvlan_unset_flags(struct rtnl_link *,
uint16_t);
extern uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *);
#ifdef __cplusplus
}
#endif
#endif

@ -75,7 +75,7 @@ libnl_route_3_la_SOURCES = \
\
route/link/api.c route/link/vlan.c route/link/dummy.c \
route/link/bridge.c route/link/inet6.c route/link/inet.c \
route/link/bonding.c route/link/can.c \
route/link/bonding.c route/link/can.c route/link/macvlan.c \
\
route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \
route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \

@ -1037,10 +1037,18 @@ static const struct trans_tbl afs[] = {
__ADD(AF_RXRPC,rxrpc)
__ADD(AF_ISDN,isdn)
__ADD(AF_PHONET,phonet)
#ifdef AF_IEEE802154
__ADD(AF_IEEE802154,ieee802154)
#endif
#ifdef AF_CAIF
__ADD(AF_CAIF,caif)
#endif
#ifdef AF_ALG
__ADD(AF_ALG,alg)
#endif
#ifdef AF_NFC
__ADD(AF_NFC,nfc)
#endif
};
char *nl_af2str(int family, char *buf, size_t size)

@ -464,7 +464,7 @@ struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size)
if (tlen > msg->nm_size)
return NULL;
nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
@ -899,7 +899,7 @@ int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
*/
int nla_is_nested(struct nlattr *attr)
{
return !!(nla_type(attr) & NLA_F_NESTED);
return !!(attr->nla_type & NLA_F_NESTED);
}
/** @} */

@ -307,6 +307,9 @@ struct nl_cache *nl_cache_subset(struct nl_cache *orig,
if (!cache)
return NULL;
NL_DBG(2, "Filling subset of cache %p <%s> with filter %p into %p\n",
orig, nl_cache_name(orig), filter, cache);
nl_list_for_each_entry(obj, &orig->c_items, ce_list) {
if (!nl_object_match_filter(obj, filter))
continue;
@ -341,6 +344,8 @@ struct nl_cache *nl_cache_clone(struct nl_cache *cache)
if (!clone)
return NULL;
NL_DBG(2, "Cloning %p into %p\n", cache, clone);
nl_list_for_each_entry(obj, &cache->c_items, ce_list)
nl_cache_add(clone, obj);
@ -362,7 +367,7 @@ void nl_cache_clear(struct nl_cache *cache)
{
struct nl_object *obj, *tmp;
NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
NL_DBG(2, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
nl_cache_remove(obj);
@ -375,7 +380,7 @@ static void __nl_cache_free(struct nl_cache *cache)
if (cache->hashtable)
nl_hash_table_free(cache->hashtable);
NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
NL_DBG(2, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
free(cache);
}
@ -386,6 +391,9 @@ static void __nl_cache_free(struct nl_cache *cache)
void nl_cache_get(struct nl_cache *cache)
{
cache->c_refcnt++;
NL_DBG(3, "Incremented cache %p <%s> reference count to %d\n",
cache, nl_cache_name(cache), cache->c_refcnt);
}
/**
@ -403,8 +411,9 @@ void nl_cache_free(struct nl_cache *cache)
return;
cache->c_refcnt--;
NL_DBG(4, "Returned cache reference %p, %d remaining\n",
cache, cache->c_refcnt);
NL_DBG(3, "Decremented cache %p <%s> reference count, %d remaining\n",
cache, nl_cache_name(cache), cache->c_refcnt);
if (cache->c_refcnt <= 0)
__nl_cache_free(cache);
@ -439,8 +448,8 @@ static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
nl_list_add_tail(&obj->ce_list, &cache->c_items);
cache->c_nitems++;
NL_DBG(1, "Added %p to cache %p <%s>.\n",
obj, cache, nl_cache_name(cache));
NL_DBG(3, "Added object %p to cache %p <%s>, nitems %d\n",
obj, cache, nl_cache_name(cache), cache->c_nitems);
return 0;
}
@ -476,6 +485,8 @@ int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
return -NLE_OBJ_MISMATCH;
if (!nl_list_empty(&obj->ce_list)) {
NL_DBG(3, "Object %p already in cache, cloning new object\n", obj);
new = nl_object_clone(obj);
if (!new)
return -NLE_NOMEM;
@ -514,7 +525,8 @@ int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
if (cache->c_ops->co_obj_ops != obj->ce_ops)
return -NLE_OBJ_MISMATCH;
NL_DBG(3, "Moving object %p to cache %p\n", obj, cache);
NL_DBG(3, "Moving object %p from cache %p to cache %p\n",
obj, obj->ce_cache, cache);
/* Acquire reference, if already in a cache this will be
* reverted during removal */
@ -547,7 +559,7 @@ void nl_cache_remove(struct nl_object *obj)
if (cache->hashtable) {
ret = nl_hash_table_del(cache->hashtable, obj);
if (ret < 0)
NL_DBG(3, "Failed to delete %p from cache %p <%s>.\n",
NL_DBG(2, "Failed to delete %p from cache %p <%s>.\n",
obj, cache, nl_cache_name(cache));
}
@ -556,7 +568,7 @@ void nl_cache_remove(struct nl_object *obj)
nl_object_put(obj);
cache->c_nitems--;
NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
NL_DBG(2, "Deleted object %p from cache %p <%s>.\n",
obj, cache, nl_cache_name(cache));
}
@ -630,12 +642,12 @@ void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
static int nl_cache_request_full_dump(struct nl_sock *sk,
struct nl_cache *cache)
{
NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n",
cache, nl_cache_name(cache));
if (cache->c_ops->co_request_update == NULL)
return -NLE_OPNOTSUPP;
NL_DBG(2, "Requesting update from kernel for cache %p <%s>\n",
cache, nl_cache_name(cache));
return cache->c_ops->co_request_update(cache, sk);
}
@ -674,8 +686,8 @@ static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
.params = param,
};
NL_DBG(1, "Picking up answer for cache %p <%s>...\n",
cache, nl_cache_name(cache));
NL_DBG(2, "Picking up answer for cache %p <%s>\n",
cache, nl_cache_name(cache));
cb = nl_cb_clone(sk->s_cb);
if (cb == NULL)
@ -685,9 +697,8 @@ static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
err = nl_recvmsgs(sk, cb);
if (err < 0)
NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
"%d: %s", cache, nl_cache_name(cache),
err, nl_geterror(err));
NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned %d: %s\n",
cache, nl_cache_name(cache), err, nl_geterror(err));
nl_cb_put(cb);
@ -800,6 +811,9 @@ int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
return cache_include(cache, obj, &ops->co_msgtypes[i],
change_cb, data);
NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
obj, cache, nl_cache_name(cache));
return -NLE_MSGTYPE_NOSUPPORT;
}
@ -951,9 +965,12 @@ restart:
if (err < 0)
return err;
NL_DBG(2, "Updating cache %p <%s> for family %u, request sent, waiting for reply\n",
cache, nl_cache_name(cache), grp ? grp->ag_family : AF_UNSPEC);
err = nl_cache_pickup(sk, cache);
if (err == -NLE_DUMP_INTR) {
NL_DBG(1, "dump interrupted, restarting!\n");
NL_DBG(2, "Dump interrupted, restarting!\n");
goto restart;
} else if (err < 0)
break;
@ -963,9 +980,6 @@ restart:
} while (grp && grp->ag_group &&
(cache->c_flags & NL_CACHE_AF_ITER));
NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
cache, nl_cache_name(cache));
return err;
}
@ -1072,8 +1086,8 @@ void nl_cache_mark_all(struct nl_cache *cache)
{
struct nl_object *obj;
NL_DBG(2, "Marking all objects in cache %p <%s>...\n",
cache, nl_cache_name(cache));
NL_DBG(2, "Marking all objects in cache %p <%s>\n",
cache, nl_cache_name(cache));
nl_list_for_each_entry(obj, &cache->c_items, ce_list)
nl_object_mark(obj);
@ -1115,7 +1129,7 @@ void nl_cache_dump_filter(struct nl_cache *cache,
struct nl_object_ops *ops;
struct nl_object *obj;
NL_DBG(2, "Dumping cache %p <%s> filter %p\n",
NL_DBG(2, "Dumping cache %p <%s> with filter %p\n",
cache, nl_cache_name(cache), filter);
if (type > NL_DUMP_MAX || type < 0)

@ -435,7 +435,7 @@ int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
}
nl_cb_put(cb);
if (err < 0)
if (err < 0 && err != -NLE_AGAIN)
return err;
return nread;

@ -239,7 +239,7 @@ static struct genl_family *genl_ctrl_probe_by_name(struct nl_sock *sk,
{
struct nl_msg *msg;
struct genl_family *ret;
struct nl_cb *cb;
struct nl_cb *cb, *orig;
int rc;
ret = genl_family_alloc();
@ -252,7 +252,12 @@ static struct genl_family *genl_ctrl_probe_by_name(struct nl_sock *sk,
if (!msg)
goto out_fam_free;
if (!(cb = nl_cb_clone(nl_socket_get_cb(sk))))
if (!(orig = nl_socket_get_cb(sk)))
goto out_msg_free;
cb = nl_cb_clone(orig);
nl_cb_put(orig);
if (!cb)
goto out_msg_free;
if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,

@ -295,6 +295,10 @@ static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
family = genl_ctrl_search_by_name(ctrl, ops->o_name);
if (family != NULL) {
ops->o_id = genl_family_get_id(family);
if (ops->o_cache_ops)
ops->o_cache_ops->co_msgtypes[0].mt_id = ops->o_id;
genl_family_put(family);
return 0;
@ -302,6 +306,32 @@ static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
return -NLE_OBJ_NOTFOUND;
}
int genl_resolve_id(struct genl_ops *ops)
{
struct nl_sock *sk;
int err = 0;
/* Check if resolved already */
if (ops->o_id != GENL_ID_GENERATE)
return 0;
if (!ops->o_name)
return -NLE_INVAL;
if (!(sk = nl_socket_alloc()))
return -NLE_NOMEM;
if ((err = genl_connect(sk)) < 0)
goto errout_free;
err = genl_ops_resolve(sk, ops);
errout_free:
nl_socket_free(sk);
return err;
}
/** @endcond */
/**

@ -153,7 +153,7 @@ struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
*/
int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
{
return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
return max_t(int, nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen), 0);
}
/** @} */
@ -767,7 +767,7 @@ static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
int i, a, c, limit;
char ascii[21] = {0};
limit = 18 - (prefix * 2);
limit = 16 - (prefix * 2);
prefix_line(ofd, prefix);
fprintf(ofd, " ");
@ -777,7 +777,7 @@ static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
fprintf(ofd, "%02x ", v);
ascii[a++] = isprint(v) ? v : '.';
if (c == limit-1) {
if (++c >= limit) {
fprintf(ofd, "%s\n", ascii);
if (i < (len - 1)) {
prefix_line(ofd, prefix);
@ -785,8 +785,7 @@ static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
}
a = c = 0;
memset(ascii, 0, sizeof(ascii));
} else
c++;
}
}
if (c != 0) {
@ -816,12 +815,60 @@ static void print_hdr(FILE *ofd, struct nl_msg *msg)
} else
nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf));
fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf);
fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
fprintf(ofd, " .type = %d <%s>\n", nlh->nlmsg_type, buf);
fprintf(ofd, " .flags = %d <%s>\n", nlh->nlmsg_flags,
nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq);
fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid);
fprintf(ofd, " .seq = %d\n", nlh->nlmsg_seq);
fprintf(ofd, " .port = %d\n", nlh->nlmsg_pid);
}
static void print_genl_hdr(FILE *ofd, void *start)
{
struct genlmsghdr *ghdr = start;
fprintf(ofd, " [GENERIC NETLINK HEADER] %zu octets\n", GENL_HDRLEN);
fprintf(ofd, " .cmd = %u\n", ghdr->cmd);
fprintf(ofd, " .version = %u\n", ghdr->version);
fprintf(ofd, " .unused = %#x\n", ghdr->reserved);
}
static void *print_genl_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr,
struct nl_cache_ops *ops, int *payloadlen)
{
void *data = nlmsg_data(hdr);
if (*payloadlen < GENL_HDRLEN)
return data;
print_genl_hdr(ofd, data);
*payloadlen -= GENL_HDRLEN;
data += GENL_HDRLEN;
if (ops) {
int hdrsize = ops->co_hdrsize - GENL_HDRLEN;
if (hdrsize > 0) {
if (*payloadlen < hdrsize)
return data;
fprintf(ofd, " [HEADER] %d octets\n", hdrsize);
dump_hex(ofd, data, hdrsize, 0);
*payloadlen -= hdrsize;
data += hdrsize;
}
}
return data;
}
static void dump_attr(FILE *ofd, struct nlattr *attr, int prefix)
{
int len = nla_len(attr);
dump_hex(ofd, nla_data(attr), len, prefix);
}
static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
@ -839,13 +886,13 @@ static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
fprintf(ofd, " [ATTR PADDING] %d octets\n", alen);
else
fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla),
nla->nla_type & NLA_F_NESTED ? " NESTED" : "",
nla_is_nested(nla) ? " NESTED" : "",
alen);
if (nla->nla_type & NLA_F_NESTED)
if (nla_is_nested(nla))
dump_attrs(ofd, nla_data(nla), alen, prefix+1);
else
dump_hex(ofd, nla_data(nla), alen, prefix);
dump_attr(ofd, nla, prefix);
padlen = nla_padlen(alen);
if (padlen > 0) {
@ -884,6 +931,42 @@ static void dump_error_msg(struct nl_msg *msg, FILE *ofd)
}
}
static void print_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr)
{
struct nl_cache_ops *ops;
int payloadlen = nlmsg_len(hdr);
int attrlen = 0;
void *data;
data = nlmsg_data(hdr);
ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg),
hdr->nlmsg_type);
if (ops) {
attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
payloadlen -= attrlen;
}
if (msg->nm_protocol == NETLINK_GENERIC)
data = print_genl_msg(msg, ofd, hdr, ops, &payloadlen);
if (payloadlen) {
fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen);
dump_hex(ofd, data, payloadlen, 0);
}
if (attrlen) {
struct nlattr *attrs;
int attrlen;
attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
dump_attrs(ofd, attrs, attrlen, 0);
}
if (ops)
nl_cache_ops_put(ops);
}
/**
* Dump message in human readable format to file descriptor
* @arg msg Message to print
@ -894,45 +977,18 @@ void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
struct nlmsghdr *hdr = nlmsg_hdr(msg);
fprintf(ofd,
"-------------------------- BEGIN NETLINK MESSAGE "
"---------------------------\n");
"-------------------------- BEGIN NETLINK MESSAGE ---------------------------\n");
fprintf(ofd, " [HEADER] %zu octets\n", sizeof(struct nlmsghdr));
fprintf(ofd, " [NETLINK HEADER] %zu octets\n", sizeof(struct nlmsghdr));
print_hdr(ofd, msg);
if (hdr->nlmsg_type == NLMSG_ERROR)
dump_error_msg(msg, ofd);
else if (nlmsg_len(hdr) > 0) {
struct nl_cache_ops *ops;
int payloadlen = nlmsg_len(hdr);
int attrlen = 0;
ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg),
hdr->nlmsg_type);
if (ops) {
attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
payloadlen -= attrlen;
}
fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen);
dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0);
if (attrlen) {
struct nlattr *attrs;
int attrlen;
attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
dump_attrs(ofd, attrs, attrlen, 0);
}
if (ops)
nl_cache_ops_put(ops);
}
else if (nlmsg_len(hdr) > 0)
print_msg(msg, ofd, hdr);
fprintf(ofd,
"--------------------------- END NETLINK MESSAGE "
"---------------------------\n");
"--------------------------- END NETLINK MESSAGE ---------------------------\n");
}
/** @} */

@ -174,15 +174,28 @@ static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
if (tb[CTA_PROTO_DST_PORT])
nfnl_ct_set_dst_port(ct, repl,
ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
if (tb[CTA_PROTO_ICMP_ID])
nfnl_ct_set_icmp_id(ct, repl,
ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
if (tb[CTA_PROTO_ICMP_TYPE])
nfnl_ct_set_icmp_type(ct, repl,
if (ct->ct_family == AF_INET) {
if (tb[CTA_PROTO_ICMP_ID])
nfnl_ct_set_icmp_id(ct, repl,
ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
if (tb[CTA_PROTO_ICMP_TYPE])
nfnl_ct_set_icmp_type(ct, repl,
nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
if (tb[CTA_PROTO_ICMP_CODE])
nfnl_ct_set_icmp_code(ct, repl,
if (tb[CTA_PROTO_ICMP_CODE])
nfnl_ct_set_icmp_code(ct, repl,
nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
} else if (ct->ct_family == AF_INET6) {
if (tb[CTA_PROTO_ICMPV6_ID])
nfnl_ct_set_icmp_id(ct, repl,
ntohs(nla_get_u16(tb[CTA_PROTO_ICMPV6_ID])));
if (tb[CTA_PROTO_ICMPV6_TYPE])
nfnl_ct_set_icmp_type(ct, repl,
nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]));
if (tb[CTA_PROTO_ICMPV6_CODE])
nfnl_ct_set_icmp_code(ct, repl,
nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]));
}
return 0;
}
@ -426,17 +439,31 @@ static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
htons(nfnl_ct_get_dst_port(ct, repl)));
if (nfnl_ct_test_icmp_id(ct, repl))
NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
htons(nfnl_ct_get_icmp_id(ct, repl)));
if (nfnl_ct_test_icmp_type(ct, repl))
NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
nfnl_ct_get_icmp_type(ct, repl));
if (nfnl_ct_test_icmp_code(ct, repl))
NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
nfnl_ct_get_icmp_code(ct, repl));
if (family == AF_INET) {
if (nfnl_ct_test_icmp_id(ct, repl))
NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
htons(nfnl_ct_get_icmp_id(ct, repl)));
if (nfnl_ct_test_icmp_type(ct, repl))
NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
nfnl_ct_get_icmp_type(ct, repl));
if (nfnl_ct_test_icmp_code(ct, repl))
NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
nfnl_ct_get_icmp_code(ct, repl));
} else if (family == AF_INET6) {
if (nfnl_ct_test_icmp_id(ct, repl))
NLA_PUT_U16(msg, CTA_PROTO_ICMPV6_ID,
htons(nfnl_ct_get_icmp_id(ct, repl)));
if (nfnl_ct_test_icmp_type(ct, repl))
NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_TYPE,
nfnl_ct_get_icmp_type(ct, repl));
if (nfnl_ct_test_icmp_code(ct, repl))
NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_CODE,
nfnl_ct_get_icmp_code(ct, repl));
}
nla_nest_end(msg, proto);

@ -163,12 +163,14 @@ errout:
/** @} */
struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
static struct nl_msg *
__nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg,
uint8_t type)
{
struct nl_msg *nlmsg;
struct nfqnl_msg_verdict_hdr verdict;
nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0,
nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, type, 0,
nfnl_queue_msg_get_family(msg),
nfnl_queue_msg_get_group(msg));
if (nlmsg == NULL)
@ -191,6 +193,18 @@ nla_put_failure:
return NULL;
}
struct nl_msg *
nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
{
return __nfnl_queue_msg_build_verdict(msg, NFQNL_MSG_VERDICT);
}
struct nl_msg *
nfnl_queue_msg_build_verdict_batch(const struct nfnl_queue_msg *msg)
{
return __nfnl_queue_msg_build_verdict(msg, NFQNL_MSG_VERDICT_BATCH);
}
/**
* Send a message verdict/mark
* @arg nlh netlink messsage header
@ -214,6 +228,29 @@ int nfnl_queue_msg_send_verdict(struct nl_sock *nlh,
return wait_for_ack(nlh);
}
/**
* Send a message batched verdict/mark
* @arg nlh netlink messsage header
* @arg msg queue msg
* @return 0 on OK or error code
*/
int nfnl_queue_msg_send_verdict_batch(struct nl_sock *nlh,
const struct nfnl_queue_msg *msg)
{
struct nl_msg *nlmsg;
int err;
nlmsg = nfnl_queue_msg_build_verdict_batch(msg);
if (nlmsg == NULL)
return -NLE_NOMEM;
err = nl_send_auto_complete(nlh, nlmsg);
nlmsg_free(nlmsg);
if (err < 0)
return err;
return wait_for_ack(nlh);
}
/**
* Send a message verdict including the payload
* @arg nlh netlink messsage header

@ -597,7 +597,7 @@ int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
flags |= MSG_PEEK | MSG_TRUNC;
if (page_size == 0)
page_size = getpagesize();
page_size = getpagesize() * 4;
iov.iov_len = sk->s_bufsize ? : page_size;
iov.iov_base = malloc(iov.iov_len);
@ -627,11 +627,6 @@ retry:
NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
goto retry;
}
if (errno == EAGAIN || errno == EWOULDBLOCK) {
NL_DBG(3, "recvmsg() returned EAGAIN||EWOULDBLOCK, aborting\n");
retval = 0;
goto abort;
}
retval = -nl_syserr2nlerr(errno);
goto abort;
}

@ -165,7 +165,12 @@ int nl_object_update(struct nl_object *dst, struct nl_object *src)
*/
void nl_object_free(struct nl_object *obj)
{
struct nl_object_ops *ops = obj_ops(obj);
struct nl_object_ops *ops;
if (!obj)
return;
ops = obj_ops(obj);
if (obj->ce_refcnt > 0)
NL_DBG(1, "Warning: Freeing object in use...\n");
@ -316,8 +321,10 @@ int nl_object_identical(struct nl_object *a, struct nl_object *b)
if (req_attrs_a != req_attrs_b)
return 0;
req_attrs = req_attrs_a;
} else {
} else if (ops->oo_id_attrs) {
req_attrs = ops->oo_id_attrs;
} else {
req_attrs = 0xFFFFFFFF;
}
if (req_attrs == 0xFFFFFFFF)
req_attrs = a->ce_mask & b->ce_mask;

@ -326,7 +326,7 @@ int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
int err = -NLE_INVAL;
if (!ops)
goto errout;
return err;
nl_write_lock(&info_lock);
if (!af_ops[ops->ao_family]) {
@ -345,7 +345,7 @@ int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
ops->ao_family);
errout:
nl_write_lock(&info_lock);
nl_write_unlock(&info_lock);
return err;
}

@ -0,0 +1,367 @@
/*
* lib/route/link/macvlan.c MACVLAN Link Info
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2013 Michael Braun <michael-dev@fami-braun.de>
*/
/**
* @ingroup link
* @defgroup macvlan MACVLAN
* MAC-based Virtual LAN link module
*
* @details
* \b Link Type Name: "macvlan"
*
* @route_doc{link_macvlan, MACVLAN Documentation}
*
* @{
*/
#include <netlink-private/netlink.h>
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
#include <netlink-private/route/link/api.h>
#include <netlink/route/link/macvlan.h>
#include <linux/if_link.h>
/** @cond SKIP */
#define MACVLAN_HAS_MODE (1<<0)
#define MACVLAN_HAS_FLAGS (1<<1)
struct macvlan_info
{
uint32_t mvi_mode;
uint16_t mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
uint32_t mvi_mask;
};
/** @endcond */
static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
[IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
};
static int macvlan_alloc(struct rtnl_link *link)
{
struct macvlan_info *mvi;
if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
return -NLE_NOMEM;
link->l_info = mvi;
return 0;
}
static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
struct nlattr *xstats)
{
struct nlattr *tb[IFLA_MACVLAN_MAX+1];
struct macvlan_info *mvi;
int err;
NL_DBG(3, "Parsing MACVLAN link info");
if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
goto errout;
if ((err = macvlan_alloc(link)) < 0)
goto errout;
mvi = link->l_info;
if (tb[IFLA_MACVLAN_MODE]) {
mvi->mvi_mode = nla_get_u32(tb[IFLA_MACVLAN_MODE]);
mvi->mvi_mask |= MACVLAN_HAS_MODE;
}
if (tb[IFLA_MACVLAN_FLAGS]) {
mvi->mvi_mode = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
}
err = 0;
errout:
return err;
}
static void macvlan_free(struct rtnl_link *link)
{
free(link->l_info);
link->l_info = NULL;
}
static void macvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
{
char buf[64];
struct macvlan_info *mvi = link->l_info;
if (mvi->mvi_mask & MACVLAN_HAS_MODE) {
rtnl_link_macvlan_mode2str(mvi->mvi_mode, buf, sizeof(buf));
nl_dump(p, "macvlan-mode %s", buf);
}
if (mvi->mvi_mask & MACVLAN_HAS_FLAGS) {
rtnl_link_macvlan_flags2str(mvi->mvi_flags, buf, sizeof(buf));
nl_dump(p, "macvlan-flags %s", buf);
}
}
static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
{
struct macvlan_info *vdst, *vsrc = src->l_info;
int err;
dst->l_info = NULL;
if ((err = rtnl_link_set_type(dst, "macvlan")) < 0)
return err;
vdst = dst->l_info;
if (!vdst || !vsrc)
return -NLE_NOMEM;
memcpy(vdst, vsrc, sizeof(struct macvlan_info));
return 0;
}
static int macvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
{
struct macvlan_info *mvi = link->l_info;
struct nlattr *data;
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
return -NLE_MSGSIZE;
if (mvi->mvi_mask & MACVLAN_HAS_MODE)
NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, mvi->mvi_mode);
if (mvi->mvi_mask & MACVLAN_HAS_FLAGS)
NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
nla_nest_end(msg, data);
nla_put_failure:
return 0;
}
static struct rtnl_link_info_ops macvlan_info_ops = {
.io_name = "macvlan",
.io_alloc = macvlan_alloc,
.io_parse = macvlan_parse,
.io_dump = {
[NL_DUMP_LINE] = macvlan_dump,
[NL_DUMP_DETAILS] = macvlan_dump,
},
.io_clone = macvlan_clone,
.io_put_attrs = macvlan_put_attrs,
.io_free = macvlan_free,
};
/** @cond SKIP */
#define IS_MACVLAN_LINK_ASSERT(link) \
if ((link)->l_info_ops != &macvlan_info_ops) { \
APPBUG("Link is not a macvlan link. set type \"macvlan\" first."); \
return -NLE_OPNOTSUPP; \
}
/** @endcond */
/**
* @name MACVLAN Object
* @{
*/
/**
* Allocate link object of type MACVLAN
*
* @return Allocated link object or NULL.
*/
struct rtnl_link *rtnl_link_macvlan_alloc(void)
{
struct rtnl_link *link;
int err;
if (!(link = rtnl_link_alloc()))
return NULL;
if ((err = rtnl_link_set_type(link, "macvlan")) < 0) {
rtnl_link_put(link);
return NULL;
}
return link;
}
/**
* Check if link is a MACVLAN link
* @arg link Link object
*
* @return True if link is a MACVLAN link, otherwise false is returned.
*/
int rtnl_link_is_macvlan(struct rtnl_link *link)
{
return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvlan");
}
/**
* Set MACVLAN MODE
* @arg link Link object
* @arg mode MACVLAN mode
*
* @return 0 on success or a negative error code
*/
int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
{
struct macvlan_info *mvi = link->l_info;
IS_MACVLAN_LINK_ASSERT(link);
mvi->mvi_mode = mode;
mvi->mvi_mask |= MACVLAN_HAS_MODE;
return 0;
}
/**
* Get MACVLAN Mode
* @arg link Link object
*
* @return MACVLAN mode, 0 if not set or a negative error code.
*/
uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
{
struct macvlan_info *mvi = link->l_info;
IS_MACVLAN_LINK_ASSERT(link);
if (mvi->mvi_mask & MACVLAN_HAS_MODE)
return mvi->mvi_mode;
else
return 0;
}
/**