Merge /home/kaber/src/repos/libnl.git
commit
6ae22c1b39
24
configure.ac
24
configure.ac
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
62
lib/cache.c
62
lib/cache.c
|
@ -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 */
|
||||
|
||||
/**
|
||||
|
|
144
lib/msg.c
144
lib/msg.c
|
@ -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");
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
7
lib/nl.c
7
lib/nl.c
|
@ -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;
|
||||
}
|
||||
|
|
11
lib/object.c
11
lib/object.c
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||