dect
/
libnl
Archived
13
0
Fork 0

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

This commit is contained in:
Patrick McHardy 2013-06-28 18:11:40 +02:00
commit 6ae22c1b39
32 changed files with 981 additions and 123 deletions

View File

@ -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([

View File

@ -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])

View File

@ -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

View File

@ -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 \

View File

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

View File

@ -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)

View File

@ -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 );

View File

@ -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

View File

@ -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 \

View File

@ -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)

View File

@ -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);
}
/** @} */

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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 */
/**

144
lib/msg.c
View File

@ -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,14 +815,62 @@ 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,
int prefix)
{
@ -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");
}
/** @} */

View File

@ -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 (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_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 (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);

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

367
lib/route/link/macvlan.c Normal file
View File

@ -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;
}
/**
* Set MACVLAN flags
* @arg link Link object
* @arg flags MACVLAN flags
*
* @return 0 on success or a negative error code.
*/
int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
{
struct macvlan_info *mvi = link->l_info;
IS_MACVLAN_LINK_ASSERT(link);
mvi->mvi_flags |= flags;
mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
return 0;
}
/**
* Unset MACVLAN flags
* @arg link Link object
* @arg flags MACVLAN flags
*
* Note: kernel currently only has a single flag and lacks flags_mask to
* indicate which flags shall be changed (it always all).
*
* @return 0 on success or a negative error code.
*/
int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
{
struct macvlan_info *mvi = link->l_info;
IS_MACVLAN_LINK_ASSERT(link);
mvi->mvi_flags &= ~flags;
mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
return 0;
}
/**
* Get MACVLAN flags
* @arg link Link object
*
* @return MACVLAN flags, 0 if none set, or a negative error code.
*/
uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
{
struct macvlan_info *mvi = link->l_info;
IS_MACVLAN_LINK_ASSERT(link);
return mvi->mvi_flags;
}
/** @} */
static const struct trans_tbl macvlan_flags[] = {
__ADD(MACVLAN_FLAG_NOPROMISC, nopromisc)
};
static const struct trans_tbl macvlan_modes[] = {
__ADD(MACVLAN_MODE_PRIVATE, private)
__ADD(MACVLAN_MODE_VEPA, vepa)
__ADD(MACVLAN_MODE_BRIDGE, bridge)
__ADD(MACVLAN_MODE_PASSTHRU, passthru)
};
/**
* @name Flag Translation
* @{
*/
char *rtnl_link_macvlan_flags2str(int flags, char *buf, size_t len)
{
return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
}
int rtnl_link_macvlan_str2flags(const char *name)
{
return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
}
/** @} */
/**
* @name Mode Translation
* @{
*/
char *rtnl_link_macvlan_mode2str(int mode, char *buf, size_t len)
{
return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
}
int rtnl_link_macvlan_str2mode(const char *name)
{
return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
}
/** @} */
static void __init macvlan_init(void)
{
rtnl_link_register_info(&macvlan_info_ops);
}
static void __exit macvlan_exit(void)
{
rtnl_link_unregister_info(&macvlan_info_ops);
}
/** @} */

View File

@ -211,7 +211,9 @@ static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey,
uint32_t n_ifindex;
char n_addr[0];
} __attribute__((packed)) *nkey;
#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
#endif
if (neigh->n_family == AF_BRIDGE) {
if (neigh->n_lladdr)

View File

@ -307,7 +307,9 @@ static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
uint32_t rt_prio;
char rt_addr[0];
} __attribute__((packed)) *rkey;
#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
#endif
if (route->rt_dst)
addr = route->rt_dst;
@ -449,8 +451,10 @@ static int route_update(struct nl_object *old_obj, struct nl_object *new_obj)
struct rtnl_route *new_route = (struct rtnl_route *) new_obj;
struct rtnl_route *old_route = (struct rtnl_route *) old_obj;
struct rtnl_nexthop *new_nh;
char buf[INET6_ADDRSTRLEN+5];
int action = new_obj->ce_msgtype;
#ifdef NL_DEBUG
char buf[INET6_ADDRSTRLEN+5];
#endif
/*
* ipv6 ECMP route notifications from the kernel come as

View File

@ -120,7 +120,7 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
return NULL;
sk->s_fd = -1;
sk->s_cb = cb;
sk->s_cb = nl_cb_get(cb);
sk->s_local.nl_family = AF_NETLINK;
sk->s_peer.nl_family = AF_NETLINK;
sk->s_seq_expect = sk->s_seq_next = time(0);
@ -141,12 +141,18 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
struct nl_sock *nl_socket_alloc(void)
{
struct nl_cb *cb;
struct nl_sock *sk;
cb = nl_cb_alloc(default_cb);
if (!cb)
return NULL;
return __alloc_socket(cb);
/* will increment cb reference count on success */
sk = __alloc_socket(cb);
nl_cb_put(cb);
return sk;
}
/**
@ -163,7 +169,7 @@ struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
if (cb == NULL)
BUG();
return __alloc_socket(nl_cb_get(cb));
return __alloc_socket(cb);
}
/**
@ -519,6 +525,9 @@ struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk)
void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
{
if (cb == NULL)
BUG();
nl_cb_put(sk->s_cb);
sk->s_cb = nl_cb_get(cb);
}

View File

@ -49,6 +49,7 @@
int nl_debug = 0;
/** @cond SKIP */
#ifdef NL_DEBUG
struct nl_dump_params nl_debug_dp = {
.dp_type = NL_DUMP_DETAILS,
};
@ -65,6 +66,7 @@ static void __init nl_debug_init(void)
nl_debug_dp.dp_fd = stderr;
}
#endif
int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
{
@ -683,7 +685,9 @@ static const struct trans_tbl llprotos[] = {
__ADD(ARPHRD_IEEE802_TR,tr)
__ADD(ARPHRD_IEEE80211,ieee802.11)
__ADD(ARPHRD_PHONET,phonet)
#ifdef ARPHRD_CAIF
__ADD(ARPHRD_CAIF, caif)
#endif
#ifdef ARPHRD_IEEE80211_PRISM
__ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
#endif

View File

@ -3,6 +3,7 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
#include <netlink/route/link/macvlan.h>
#include <netlink/route/link/inet.h>
#include <netlink/route/tc.h>
@ -169,6 +170,21 @@ extern uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *);
extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, uint32_t, int);
extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, int *);
/* <netlink/route/link/macvlan.h> */
%cstring_output_maxsize(char *buf, size_t len)
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 *);
/* <netlink/route/link/inet.h> */
%cstring_output_maxsize(char *buf, size_t len)
extern const char *rtnl_link_inet_devconf2str(int, char *buf, size_t len);

View File

@ -1,5 +1,10 @@
# -*- Makefile -*-
EXTRA_DIST = \
util.h
if ENABLE_UNIT_TESTS
AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
LDADD = \
@ -44,4 +49,6 @@ test_complex_HTB_with_hash_filters_SOURCES = test-complex-HTB-with-hash-filters.
# Unit tests
check_all_SOURCES = \
check-all.c \
check-addr.c
check-addr.c \
check-attr.c
endif

View File

@ -12,6 +12,7 @@
#include <check.h>
extern Suite *make_nl_addr_suite(void);
extern Suite *make_nl_attr_suite(void);
static Suite *main_suite(void)
{
@ -30,6 +31,7 @@ int main(int argc, char *argv[])
/* Add testsuites below */
srunner_add_suite(runner, make_nl_addr_suite());
srunner_add_suite(runner, make_nl_attr_suite());
/* Do not add testsuites below this line */

88
tests/check-attr.c Normal file
View File

@ -0,0 +1,88 @@
/*
* tests/check-attr.c nla_attr unit tests
*
* 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 Thomas Graf <tgraf@suug.ch>
*/
#include "util.h"
#include <netlink/attr.h>
#include <netlink/msg.h>
START_TEST(attr_size)
{
fail_if(nla_attr_size(0) != NLA_HDRLEN,
"Length of empty attribute should match header size");
fail_if(nla_attr_size(1) != NLA_HDRLEN + 1,
"Length of 1 bytes payload should be NLA_HDRLEN + 1");
fail_if(nla_attr_size(2) != NLA_HDRLEN + 2,
"Length of 2 bytes payload should be NLA_HDRLEN + 2");
fail_if(nla_attr_size(3) != NLA_HDRLEN + 3,
"Length of 3 bytes payload should be NLA_HDRLEN + 3");
fail_if(nla_attr_size(4) != NLA_HDRLEN + 4,
"Length of 4 bytes payload should be NLA_HDRLEN + 4");
fail_if(nla_total_size(1) != NLA_HDRLEN + 4,
"Total size of 1 bytes payload should result in 8 bytes");
fail_if(nla_total_size(2) != NLA_HDRLEN + 4,
"Total size of 2 bytes payload should result in 8 bytes");
fail_if(nla_total_size(3) != NLA_HDRLEN + 4,
"Total size of 3 bytes payload should result in 8 bytes");
fail_if(nla_total_size(4) != NLA_HDRLEN + 4,
"Total size of 4 bytes payload should result in 8 bytes");
fail_if(nla_padlen(1) != 3,
"2 bytes of payload should result in 3 padding bytes");
fail_if(nla_padlen(2) != 2,
"2 bytes of payload should result in 2 padding bytes");
fail_if(nla_padlen(3) != 1,
"3 bytes of payload should result in 1 padding bytes");
fail_if(nla_padlen(4) != 0,
"4 bytes of payload should result in 0 padding bytes");
fail_if(nla_padlen(5) != 3,
"5 bytes of payload should result in 3 padding bytes");
}
END_TEST
START_TEST(msg_construct)
{
struct nl_msg *msg;
struct nlmsghdr *nlh;
struct nlattr *a;
int i, rem;
msg = nlmsg_alloc();
fail_if(!msg, "Unable to allocate netlink message");
for (i = 1; i < 256; i++) {
fail_if(nla_put_u32(msg, i, i+1) != 0,
"Unable to add attribute %d", i);
}
nlh = nlmsg_hdr(msg);
i = 1;
nlmsg_for_each_attr(a, nlh, 0, rem) {
fail_if(nla_type(a) != i, "Expected attribute %d", i);
i++;
fail_if(nla_get_u32(a) != i, "Expected attribute value %d", i);
}
nlmsg_free(msg);
}
END_TEST
Suite *make_nl_attr_suite(void)
{
Suite *suite = suite_create("Netlink attributes");
TCase *nl_attr = tcase_create("Core");
tcase_add_test(nl_attr, attr_size);
tcase_add_test(nl_attr, msg_construct);
suite_add_tcase(suite, nl_attr);
return suite;
}

View File

@ -0,0 +1,48 @@
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/route/link/macvlan.h>
int main(int argc, char *argv[])
{
struct rtnl_link *link;
struct nl_cache *link_cache;
struct nl_sock *sk;
struct nl_addr* addr;
int err, master_index;
sk = nl_socket_alloc();
if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
nl_perror(err, "Unable to connect socket");
return err;
}
if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
nl_perror(err, "Unable to allocate cache");
return err;
}
if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) {
fprintf(stderr, "Unable to lookup eth0");
return -1;
}
link = rtnl_link_macvlan_alloc();
rtnl_link_set_link(link, master_index);
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);
rtnl_link_macvlan_set_mode(link, rtnl_link_macvlan_str2mode("bridge"));
if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
nl_perror(err, "Unable to add link");
return err;
}
rtnl_link_put(link);
nl_close(sk);
return 0;
}

5
tests/util.h Normal file
View File

@ -0,0 +1,5 @@
#include <check.h>
#define nl_fail_if(condition, error, message) \
fail_if((condition), "nlerr=%d (%s): %s", \
(error), nl_geterror(error), (message))