diff options
-rw-r--r-- | include/netlink-private/cache-api.h | 15 | ||||
-rw-r--r-- | include/netlink/cache.h | 3 | ||||
-rw-r--r-- | include/netlink/hashtable.h | 2 | ||||
-rw-r--r-- | include/netlink/object.h | 3 | ||||
-rw-r--r-- | lib/cache.c | 56 | ||||
-rw-r--r-- | lib/hashtable.c | 34 | ||||
-rw-r--r-- | lib/object.c | 11 |
7 files changed, 124 insertions, 0 deletions
diff --git a/include/netlink-private/cache-api.h b/include/netlink-private/cache-api.h index f3d9f01..0b39bfa 100644 --- a/include/netlink-private/cache-api.h +++ b/include/netlink-private/cache-api.h @@ -239,6 +239,21 @@ struct nl_cache_ops int (*co_include_event)(struct nl_cache *cache, struct nl_object *obj, change_func_t change_cb, void *data); + /** + * The function registered under this callback is called when an + * a nl_cache_search is to performed on the cache. + * + * The callback if implemented by a cache must return an attribute + * mask to be used for the cache search + * + * If no function is registered, nl_cache_search will internally use + * oo_id_attrs_get to get its attributes for matching objects + * + * @see nl_cache_search() + */ + uint32_t (*co_cache_search_attrs_get)(struct nl_cache *cache, + struct nl_object *needle); + void (*reserved_1)(void); void (*reserved_2)(void); void (*reserved_3)(void); diff --git a/include/netlink/cache.h b/include/netlink/cache.h index 71eaceb..7077f2e 100644 --- a/include/netlink/cache.h +++ b/include/netlink/cache.h @@ -96,6 +96,9 @@ extern void nl_cache_set_flags(struct nl_cache *, unsigned int); extern int nl_cache_is_empty(struct nl_cache *); extern struct nl_object * nl_cache_search(struct nl_cache *, struct nl_object *); +extern struct nl_object * nl_cache_search_mask(struct nl_cache *, + struct nl_object *, + uint32_t); extern struct nl_object *nl_cache_find(struct nl_cache *, struct nl_object *); extern void nl_cache_mark_all(struct nl_cache *); diff --git a/include/netlink/hashtable.h b/include/netlink/hashtable.h index 70d8c0f..c52f6e1 100644 --- a/include/netlink/hashtable.h +++ b/include/netlink/hashtable.h @@ -42,6 +42,8 @@ extern int nl_hash_table_del(nl_hash_table_t *ht, extern struct nl_object * nl_hash_table_lookup(nl_hash_table_t *ht, struct nl_object *obj); +extern struct nl_object * nl_hash_table_lookup_mask(nl_hash_table_t *ht, + struct nl_object *obj, uint32_t); extern uint32_t nl_hash(void *k, size_t length, uint32_t initval); diff --git a/include/netlink/object.h b/include/netlink/object.h index b0c32c9..e442f0f 100644 --- a/include/netlink/object.h +++ b/include/netlink/object.h @@ -45,6 +45,9 @@ extern uint32_t nl_object_diff(struct nl_object *, struct nl_object *); extern uint64_t nl_object_diff64(struct nl_object *, struct nl_object *); +extern uint32_t nl_object_diff_mask(struct nl_object *, + struct nl_object *, + uint32_t); extern int nl_object_match_filter(struct nl_object *, struct nl_object *); extern char * nl_object_attrs2str(struct nl_object *, diff --git a/lib/cache.c b/lib/cache.c index ba5fa72..960459d 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -1043,6 +1043,21 @@ restart: * @name Utillities * @{ */ +static struct nl_object *__cache_fast_lookup_mask(struct nl_cache *cache, + struct nl_object *needle, + uint32_t mask) +{ + struct nl_object *obj; + + obj = nl_hash_table_lookup_mask(cache->hashtable, needle, mask); + if (obj) { + nl_object_get(obj); + return obj; + } + + return NULL; +} + static struct nl_object *__cache_fast_lookup(struct nl_cache *cache, struct nl_object *needle) { @@ -1061,6 +1076,40 @@ static struct nl_object *__cache_fast_lookup(struct nl_cache *cache, * Search object in cache * @arg cache Cache * @arg needle Object to look for. + * @arg mask Attribute mask to use during object comparision + * + * Searches the cache for an object which matches the object \p needle. + * The function nl_object_diff_mask() is used to determine if the + * objects match. If a matching object is found, the reference counter + * is incremented and the object is returned. + * + * Therefore, if an object is returned, the reference to the object + * must be returned by calling nl_object_put() after usage. + * + * @return Reference to object or NULL if not found. + */ +struct nl_object *nl_cache_search_mask(struct nl_cache *cache, + struct nl_object *needle, uint32_t mask) +{ + struct nl_object *obj; + + if (cache->hashtable) + return __cache_fast_lookup_mask(cache, needle, mask); + + nl_list_for_each_entry(obj, &cache->c_items, ce_list) { + if (!nl_object_diff_mask(obj, needle, mask)) { + nl_object_get(obj); + return obj; + } + } + + return NULL; +} + +/** + * Search object in cache + * @arg cache Cache + * @arg needle Object to look for. * * Searches the cache for an object which matches the object \p needle. * The function nl_object_identical() is used to determine if the @@ -1076,6 +1125,13 @@ struct nl_object *nl_cache_search(struct nl_cache *cache, struct nl_object *needle) { struct nl_object *obj; + uint32_t mask; + + if (cache->c_ops->co_cache_search_attrs_get) { + mask = cache->c_ops->co_cache_search_attrs_get(cache, needle); + if (mask) + return nl_cache_search_mask(cache, needle, mask); + } if (cache->hashtable) return __cache_fast_lookup(cache, needle); diff --git a/lib/hashtable.c b/lib/hashtable.c index 75e9fda..7652e6b 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -116,6 +116,40 @@ struct nl_object* nl_hash_table_lookup(nl_hash_table_t *ht, } /** + * Lookup identical object in hashtable + * @arg ht Hashtable + * @arg obj Object to lookup + * @arg mask Attribute mask to use during lookup + * + * Generates hashkey for `obj` and traverses the corresponding chain calling + * `nl_object_diff_mask()` on each trying to find a match. similar to + * nl_hash_table_lookup but uses an user provided attribute mask. + * + * @return Pointer to object if match was found or NULL. + */ + +struct nl_object* nl_hash_table_lookup_mask(nl_hash_table_t *ht, + struct nl_object *obj, + uint32_t mask) +{ + nl_hash_node_t *node, *head; + uint32_t key_hash; + + nl_object_keygen(obj, &key_hash, ht->size); + head = ht->nodes[key_hash]; + + if (!head) + return NULL; + + nl_list_for_each_entry(node, &head->list, list) { + if (!nl_object_diff_mask(node->obj, obj, mask)) + return node->obj; + } + + return NULL; +} + +/** * Add object to hashtable * @arg ht Hashtable * @arg obj Object to add diff --git a/lib/object.c b/lib/object.c index 06c2a95..dcf2a36 100644 --- a/lib/object.c +++ b/lib/object.c @@ -393,6 +393,17 @@ uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b) : (uint32_t) diff; } +uint32_t nl_object_diff_mask(struct nl_object *a, struct nl_object *b, + uint32_t mask) +{ + struct nl_object_ops *ops = obj_ops(a); + + if (ops != obj_ops(b) || ops->oo_compare == NULL) + return UINT_MAX; + + return ops->oo_compare(a, b, mask, 0); +} + /** * Match a filter against an object * @arg obj object to check |