summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/netlink-private/cache-api.h15
-rw-r--r--include/netlink/cache.h3
-rw-r--r--include/netlink/hashtable.h2
-rw-r--r--include/netlink/object.h3
-rw-r--r--lib/cache.c56
-rw-r--r--lib/hashtable.c34
-rw-r--r--lib/object.c11
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