|
|
|
@ -46,121 +46,6 @@ |
|
|
|
|
#include <netlink/object.h> |
|
|
|
|
#include <netlink/utils.h> |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name Access Functions |
|
|
|
|
* @{ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#ifdef disabled |
|
|
|
|
/**
|
|
|
|
|
* Return the number of items in the cache |
|
|
|
|
* @arg cache cache handle |
|
|
|
|
*/ |
|
|
|
|
int nl_cache_nitems(struct nl_cache *cache) |
|
|
|
|
{ |
|
|
|
|
return cache->c_nitems; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the number of items matching a filter in the cache |
|
|
|
|
* @arg cache Cache object. |
|
|
|
|
* @arg filter Filter object. |
|
|
|
|
*/ |
|
|
|
|
int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter) |
|
|
|
|
{ |
|
|
|
|
struct nl_object_ops *ops; |
|
|
|
|
struct nl_object *obj; |
|
|
|
|
int nitems = 0; |
|
|
|
|
|
|
|
|
|
if (cache->c_ops == NULL) |
|
|
|
|
BUG(); |
|
|
|
|
|
|
|
|
|
ops = cache->c_ops->co_obj_ops; |
|
|
|
|
|
|
|
|
|
nl_list_for_each_entry(obj, &cache->c_items, ce_list) { |
|
|
|
|
if (filter && !nl_object_match_filter(obj, filter)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
nitems++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nitems; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns \b true if the cache is empty. |
|
|
|
|
* @arg cache Cache to check |
|
|
|
|
* @return \a true if the cache is empty, otherwise \b false is returned. |
|
|
|
|
*/ |
|
|
|
|
int nl_cache_is_empty(struct nl_cache *cache) |
|
|
|
|
{ |
|
|
|
|
return nl_list_empty(&cache->c_items); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the operations set of the cache |
|
|
|
|
* @arg cache cache handle |
|
|
|
|
*/ |
|
|
|
|
struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache) |
|
|
|
|
{ |
|
|
|
|
return cache->c_ops; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the first element in the cache |
|
|
|
|
* @arg cache cache handle |
|
|
|
|
*/ |
|
|
|
|
struct nl_object *nl_cache_get_first(struct nl_cache *cache) |
|
|
|
|
{ |
|
|
|
|
if (nl_list_empty(&cache->c_items)) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
return nl_list_entry(cache->c_items.next, |
|
|
|
|
struct nl_object, ce_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the last element in the cache |
|
|
|
|
* @arg cache cache handle |
|
|
|
|
*/ |
|
|
|
|
struct nl_object *nl_cache_get_last(struct nl_cache *cache) |
|
|
|
|
{ |
|
|
|
|
if (nl_list_empty(&cache->c_items)) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
return nl_list_entry(cache->c_items.prev, |
|
|
|
|
struct nl_object, ce_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the next element in the cache |
|
|
|
|
* @arg obj current object |
|
|
|
|
*/ |
|
|
|
|
struct nl_object *nl_cache_get_next(struct nl_object *obj) |
|
|
|
|
{ |
|
|
|
|
if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list)) |
|
|
|
|
return NULL; |
|
|
|
|
else |
|
|
|
|
return nl_list_entry(obj->ce_list.next, |
|
|
|
|
struct nl_object, ce_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the previous element in the cache |
|
|
|
|
* @arg obj current object |
|
|
|
|
*/ |
|
|
|
|
struct nl_object *nl_cache_get_prev(struct nl_object *obj) |
|
|
|
|
{ |
|
|
|
|
if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list)) |
|
|
|
|
return NULL; |
|
|
|
|
else |
|
|
|
|
return nl_list_entry(obj->ce_list.prev, |
|
|
|
|
struct nl_object, ce_list); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name Cache Creation/Deletion |
|
|
|
|
* @{ |
|
|
|
@ -206,61 +91,6 @@ int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef disabled |
|
|
|
|
/**
|
|
|
|
|
* Allocate an empty cache based on type name |
|
|
|
|
* @arg kind Name of cache type |
|
|
|
|
* @return A newly allocated and initialized cache. |
|
|
|
|
*/ |
|
|
|
|
int nl_cache_alloc_name(const char *kind, struct nl_cache **result) |
|
|
|
|
{ |
|
|
|
|
struct nl_cache_ops *ops; |
|
|
|
|
struct nl_cache *cache; |
|
|
|
|
|
|
|
|
|
ops = nl_cache_ops_lookup(kind); |
|
|
|
|
if (!ops) |
|
|
|
|
return -NLE_NOCACHE; |
|
|
|
|
|
|
|
|
|
if (!(cache = nl_cache_alloc(ops))) |
|
|
|
|
return -NLE_NOMEM; |
|
|
|
|
|
|
|
|
|
*result = cache; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Allocate a new cache containing a subset of a cache |
|
|
|
|
* @arg orig Original cache to be based on |
|
|
|
|
* @arg filter Filter defining the subset to be filled into new cache |
|
|
|
|
* @return A newly allocated cache or NULL. |
|
|
|
|
*/ |
|
|
|
|
struct nl_cache *nl_cache_subset(struct nl_cache *orig, |
|
|
|
|
struct nl_object *filter) |
|
|
|
|
{ |
|
|
|
|
struct nl_cache *cache; |
|
|
|
|
struct nl_object_ops *ops; |
|
|
|
|
struct nl_object *obj; |
|
|
|
|
|
|
|
|
|
if (!filter) |
|
|
|
|
BUG(); |
|
|
|
|
|
|
|
|
|
cache = nl_cache_alloc(orig->c_ops); |
|
|
|
|
if (!cache) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
ops = orig->c_ops->co_obj_ops; |
|
|
|
|
|
|
|
|
|
nl_list_for_each_entry(obj, &orig->c_items, ce_list) { |
|
|
|
|
if (!nl_object_match_filter(obj, filter)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
nl_cache_add(cache, obj); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return cache; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clear a cache. |
|
|
|
|
* @arg cache cache to clear |
|
|
|
@ -344,35 +174,6 @@ int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) |
|
|
|
|
return __cache_add(cache, new); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef disabled |
|
|
|
|
/**
|
|
|
|
|
* Move object from one cache to another |
|
|
|
|
* @arg cache Cache to move object to. |
|
|
|
|
* @arg obj Object subject to be moved |
|
|
|
|
* |
|
|
|
|
* Removes the given object from its associated cache if needed |
|
|
|
|
* and adds it to the new cache. |
|
|
|
|
* |
|
|
|
|
* @return 0 on success or a negative error code. |
|
|
|
|
*/ |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
/* Acquire reference, if already in a cache this will be
|
|
|
|
|
* reverted during removal */ |
|
|
|
|
nl_object_get(obj); |
|
|
|
|
|
|
|
|
|
if (!nl_list_empty(&obj->ce_list)) |
|
|
|
|
nl_cache_remove(obj); |
|
|
|
|
|
|
|
|
|
return __cache_add(cache, obj); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Removes an object from a cache. |
|
|
|
|
* @arg obj Object to remove from its cache |
|
|
|
@ -397,34 +198,6 @@ void nl_cache_remove(struct nl_object *obj) |
|
|
|
|
obj, cache, nl_cache_name(cache)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef disabled |
|
|
|
|
/**
|
|
|
|
|
* Search for an object in a cache |
|
|
|
|
* @arg cache Cache to search in. |
|
|
|
|
* @arg needle Object to look for. |
|
|
|
|
* |
|
|
|
|
* Iterates over the cache and looks for an object with identical |
|
|
|
|
* identifiers as the needle. |
|
|
|
|
* |
|
|
|
|
* @return Reference to object or NULL if not found. |
|
|
|
|
* @note The returned object must be returned via nl_object_put(). |
|
|
|
|
*/ |
|
|
|
|
struct nl_object *nl_cache_search(struct nl_cache *cache, |
|
|
|
|
struct nl_object *needle) |
|
|
|
|
{ |
|
|
|
|
struct nl_object *obj; |
|
|
|
|
|
|
|
|
|
nl_list_for_each_entry(obj, &cache->c_items, ce_list) { |
|
|
|
|
if (nl_object_identical(obj, needle)) { |
|
|
|
|
nl_object_get(obj); |
|
|
|
|
return obj; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -523,107 +296,6 @@ int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) |
|
|
|
|
return __cache_pickup(sk, cache, &p); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef disabled |
|
|
|
|
static int cache_include(struct nl_cache *cache, struct nl_object *obj, |
|
|
|
|
struct nl_msgtype *type, change_func_t cb) |
|
|
|
|
{ |
|
|
|
|
struct nl_object *old; |
|
|
|
|
|
|
|
|
|
switch (type->mt_act) { |
|
|
|
|
case NL_ACT_NEW: |
|
|
|
|
case NL_ACT_DEL: |
|
|
|
|
old = nl_cache_search(cache, obj); |
|
|
|
|
if (old) { |
|
|
|
|
nl_cache_remove(old); |
|
|
|
|
if (type->mt_act == NL_ACT_DEL) { |
|
|
|
|
if (cb) |
|
|
|
|
cb(cache, old, NL_ACT_DEL); |
|
|
|
|
nl_object_put(old); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (type->mt_act == NL_ACT_NEW) { |
|
|
|
|
nl_cache_move(cache, obj); |
|
|
|
|
if (old == NULL && cb) |
|
|
|
|
cb(cache, obj, NL_ACT_NEW); |
|
|
|
|
else if (old) { |
|
|
|
|
if (nl_object_diff(old, obj) && cb) |
|
|
|
|
cb(cache, obj, NL_ACT_CHANGE); |
|
|
|
|
|
|
|
|
|
nl_object_put(old); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
NL_DBG(2, "Unknown action associated to object %p\n", obj); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int nl_cache_include(struct nl_cache *cache, struct nl_object *obj, |
|
|
|
|
change_func_t change_cb) |
|
|
|
|
{ |
|
|
|
|
struct nl_cache_ops *ops = cache->c_ops; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
if (ops->co_obj_ops != obj->ce_ops) |
|
|
|
|
return -NLE_OBJ_MISMATCH; |
|
|
|
|
|
|
|
|
|
for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) |
|
|
|
|
if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype) |
|
|
|
|
return cache_include(cache, obj, &ops->co_msgtypes[i], |
|
|
|
|
change_cb); |
|
|
|
|
|
|
|
|
|
return -NLE_MSGTYPE_NOSUPPORT; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int resync_cb(struct nl_object *c, struct nl_parser_param *p) |
|
|
|
|
{ |
|
|
|
|
struct nl_cache_assoc *ca = p->pp_arg; |
|
|
|
|
|
|
|
|
|
return nl_cache_include(ca->ca_cache, c, ca->ca_change); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache, |
|
|
|
|
change_func_t change_cb) |
|
|
|
|
{ |
|
|
|
|
struct nl_object *obj, *next; |
|
|
|
|
struct nl_cache_assoc ca = { |
|
|
|
|
.ca_cache = cache, |
|
|
|
|
.ca_change = change_cb, |
|
|
|
|
}; |
|
|
|
|
struct nl_parser_param p = { |
|
|
|
|
.pp_cb = resync_cb, |
|
|
|
|
.pp_arg = &ca, |
|
|
|
|
}; |
|
|
|
|
int err; |
|
|
|
|
|
|
|
|
|
NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache)); |
|
|
|
|
|
|
|
|
|
/* Mark all objects so we can see if some of them are obsolete */ |
|
|
|
|
nl_cache_mark_all(cache); |
|
|
|
|
|
|
|
|
|
err = nl_cache_request_full_dump(sk, cache); |
|
|
|
|
if (err < 0) |
|
|
|
|
goto errout; |
|
|
|
|
|
|
|
|
|
err = __cache_pickup(sk, cache, &p); |
|
|
|
|
if (err < 0) |
|
|
|
|
goto errout; |
|
|
|
|
|
|
|
|
|
nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) |
|
|
|
|
if (nl_object_is_marked(obj)) |
|
|
|
|
nl_cache_remove(obj); |
|
|
|
|
|
|
|
|
|
NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache)); |
|
|
|
|
|
|
|
|
|
err = 0; |
|
|
|
|
errout: |
|
|
|
|
return err; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
|
|
|
|
@ -702,138 +374,3 @@ int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
#ifdef disabled |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name Utillities |
|
|
|
|
* @{ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Mark all objects in a cache |
|
|
|
|
* @arg cache Cache to mark all objects in |
|
|
|
|
*/ |
|
|
|
|
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_list_for_each_entry(obj, &cache->c_items, ce_list) |
|
|
|
|
nl_object_mark(obj); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name Dumping |
|
|
|
|
* @{ |
|
|
|
|
*/ |
|
|
|
|
/**
|
|
|
|
|
* Dump all elements of a cache. |
|
|
|
|
* @arg cache cache to dump |
|
|
|
|
* @arg params dumping parameters |
|
|
|
|
* |
|
|
|
|
* Dumps all elements of the \a cache to the file descriptor \a fd. |
|
|
|
|
*/ |
|
|
|
|
void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params) |
|
|
|
|
{ |
|
|
|
|
nl_cache_dump_filter(cache, params, NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dump all elements of a cache (filtered). |
|
|
|
|
* @arg cache cache to dump |
|
|
|
|
* @arg params dumping parameters (optional) |
|
|
|
|
* @arg filter filter object |
|
|
|
|
* |
|
|
|
|
* Dumps all elements of the \a cache to the file descriptor \a fd |
|
|
|
|
* given they match the given filter \a filter. |
|
|
|
|
*/ |
|
|
|
|
void nl_cache_dump_filter(struct nl_cache *cache, |
|
|
|
|
struct nl_dump_params *params, |
|
|
|
|
struct nl_object *filter) |
|
|
|
|
{ |
|
|
|
|
int type = params ? params->dp_type : NL_DUMP_DETAILS; |
|
|
|
|
struct nl_object_ops *ops; |
|
|
|
|
struct nl_object *obj; |
|
|
|
|
|
|
|
|
|
NL_DBG(2, "Dumping cache %p <%s> filter %p\n", |
|
|
|
|
cache, nl_cache_name(cache), filter); |
|
|
|
|
|
|
|
|
|
if (type > NL_DUMP_MAX || type < 0) |
|
|
|
|
BUG(); |
|
|
|
|
|
|
|
|
|
if (cache->c_ops == NULL) |
|
|
|
|
BUG(); |
|
|
|
|
|
|
|
|
|
ops = cache->c_ops->co_obj_ops; |
|
|
|
|
if (!ops->oo_dump[type]) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
nl_list_for_each_entry(obj, &cache->c_items, ce_list) { |
|
|
|
|
if (filter && !nl_object_match_filter(obj, filter)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
NL_DBG(4, "Dumping object %p...\n", obj); |
|
|
|
|
dump_from_ops(obj, params); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name Iterators |
|
|
|
|
* @{ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Call a callback on each element of the cache. |
|
|
|
|
* @arg cache cache to iterate on |
|
|
|
|
* @arg cb callback function |
|
|
|
|
* @arg arg argument passed to callback function |
|
|
|
|
* |
|
|
|
|
* Calls a callback function \a cb on each element of the \a cache. |
|
|
|
|
* The argument \a arg is passed on the callback function. |
|
|
|
|
*/ |
|
|
|
|
void nl_cache_foreach(struct nl_cache *cache, |
|
|
|
|
void (*cb)(struct nl_object *, void *), void *arg) |
|
|
|
|
{ |
|
|
|
|
nl_cache_foreach_filter(cache, NULL, cb, arg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Call a callback on each element of the cache (filtered). |
|
|
|
|
* @arg cache cache to iterate on |
|
|
|
|
* @arg filter filter object |
|
|
|
|
* @arg cb callback function |
|
|
|
|
* @arg arg argument passed to callback function |
|
|
|
|
* |
|
|
|
|
* Calls a callback function \a cb on each element of the \a cache |
|
|
|
|
* that matches the \a filter. The argument \a arg is passed on |
|
|
|
|
* to the callback function. |
|
|
|
|
*/ |
|
|
|
|
void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, |
|
|
|
|
void (*cb)(struct nl_object *, void *), void *arg) |
|
|
|
|
{ |
|
|
|
|
struct nl_object *obj, *tmp; |
|
|
|
|
struct nl_object_ops *ops; |
|
|
|
|
|
|
|
|
|
if (cache->c_ops == NULL) |
|
|
|
|
BUG(); |
|
|
|
|
|
|
|
|
|
ops = cache->c_ops->co_obj_ops; |
|
|
|
|
|
|
|
|
|
nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) { |
|
|
|
|
if (filter && !nl_object_match_filter(obj, filter)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
cb(obj, arg); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/** @} */ |
|
|
|
|