]> granicus.if.org Git - libnl/commitdiff
cache_mngr: add include callback v2
authorTobias Jungel <tobias.jungel@bisdn.de>
Sun, 13 Nov 2016 14:21:46 +0000 (15:21 +0100)
committerThomas Haller <thaller@redhat.com>
Thu, 1 Dec 2016 15:49:43 +0000 (16:49 +0100)
This patch adds change_func_v2_t to add a more detailed callback in
case of a cache change. The change function is registered using the new
nl_cache_mngr_add_cache_v2. In case the new change function is set,
nl_cache_include_v2 and thus cache_include_v2 will be used to perform the cache
inclusion.

The parameter of change_func_v2_t are the following:
* struct nl_cache * => cache
* struct nl_object * => the old/deleted nl_object
* struct nl_object * => the new nl_object
* uint64_t => the result of nl_object_diff64 in case of a change
* int => NL_ACT_*
* void * => data

https://github.com/thom311/libnl/issues/71
http://lists.infradead.org/pipermail/libnl/2016-September/002214.html
http://lists.infradead.org/pipermail/libnl/2016-October/002229.html
http://lists.infradead.org/pipermail/libnl/2016-November/002250.html

include/netlink-private/cache-api.h
include/netlink-private/types.h
include/netlink/cache.h
lib/cache.c
lib/cache_mngr.c
lib/xfrm/sa.c
libnl-3.sym

index f3d9f01a20c9a1485c07689d70df764fcd90c31c..c684e79735b247873c4e316e36831f9ff6f6cfa7 100644 (file)
@@ -237,7 +237,8 @@ struct nl_cache_ops
         * @see nl_cache_include()
         */
        int   (*co_include_event)(struct nl_cache *cache, struct nl_object *obj,
-                                 change_func_t change_cb, void *data);
+                                 change_func_t change_cb, change_func_v2_t change_cb_v2,
+                                 void *data);
 
        void (*reserved_1)(void);
        void (*reserved_2)(void);
index 1b19b5841f098aa26e8a5750888926f4f8ad55a0..d8a9269030b374b2421a9540517f99b28fe90ca5 100644 (file)
@@ -99,6 +99,7 @@ struct nl_cache_assoc
 {
        struct nl_cache *       ca_cache;
        change_func_t           ca_change;
+       change_func_v2_t        ca_change_v2;
        void *                  ca_change_data;
 };
 
index 71eaceb271c24f36b298dd46264a3a842e56f7e1..c0797d0130cb50a485dcae5881b6d82d41bec8f1 100644 (file)
@@ -35,6 +35,8 @@ enum {
 
 struct nl_cache;
 typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *);
+typedef void (*change_func_v2_t)(struct nl_cache *, struct nl_object *old_obj,
+             struct nl_object *new_obj, uint64_t, int, void *);
 
 /**
  * @ingroup cache
@@ -88,6 +90,10 @@ extern int                   nl_cache_include(struct nl_cache *,
                                                 struct nl_object *,
                                                 change_func_t,
                                                 void *);
+extern int                     nl_cache_include_v2(struct nl_cache *,
+                                                   struct nl_object *,
+                                                   change_func_v2_t,
+                                                   void *);
 extern void                    nl_cache_set_arg1(struct nl_cache *, int);
 extern void                    nl_cache_set_arg2(struct nl_cache *, int);
 extern void                    nl_cache_set_flags(struct nl_cache *, unsigned int);
@@ -154,6 +160,9 @@ extern int                  nl_cache_mngr_add(struct nl_cache_mngr *,
 extern int                     nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr,
                                                        struct nl_cache *cache,
                                                        change_func_t cb, void *data);
+extern int                     nl_cache_mngr_add_cache_v2(struct nl_cache_mngr *mngr,
+                                                          struct nl_cache *cache,
+                                                          change_func_v2_t cb, void *data);
 extern int                     nl_cache_mngr_get_fd(struct nl_cache_mngr *);
 extern int                     nl_cache_mngr_poll(struct nl_cache_mngr *,
                                                   int);
index d8592b6c6825119865c40be5f5eeb574c5e4e020..d9742b6ddacd7f275a8e0ca474a94a6ad2f6e91e 100644 (file)
@@ -784,30 +784,45 @@ int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
 }
 
 static int cache_include(struct nl_cache *cache, struct nl_object *obj,
-                        struct nl_msgtype *type, change_func_t cb, void *data)
+                        struct nl_msgtype *type, change_func_t cb,
+                        change_func_v2_t cb_v2, void *data)
 {
        struct nl_object *old;
+       struct nl_object *clone = NULL;
+       uint64_t diff;
 
        switch (type->mt_act) {
        case NL_ACT_NEW:
        case NL_ACT_DEL:
                old = nl_cache_search(cache, obj);
                if (old) {
+                       if (cb_v2 && old->ce_ops->oo_update) {
+                               clone = nl_object_clone(old);
+                               diff = nl_object_diff64(old, obj);
+                       }
                        /*
                         * Some objects types might support merging the new
                         * object with the old existing cache object.
                         * Handle them first.
                         */
                        if (nl_object_update(old, obj) == 0) {
-                               if (cb)
+                               if (cb_v2) {
+                                       cb_v2(cache, clone, obj, diff,
+                                             NL_ACT_CHANGE, data);
+                                       nl_object_put(clone);
+                               } else if (cb)
                                        cb(cache, old, NL_ACT_CHANGE, data);
                                nl_object_put(old);
                                return 0;
                        }
+                       nl_object_put(clone);
 
                        nl_cache_remove(old);
                        if (type->mt_act == NL_ACT_DEL) {
-                               if (cb)
+                               if (cb_v2)
+                                       cb_v2(cache, old, NULL, 0, NL_ACT_DEL,
+                                             data);
+                               else if (cb)
                                        cb(cache, old, NL_ACT_DEL, data);
                                nl_object_put(old);
                        }
@@ -815,10 +830,20 @@ static int cache_include(struct nl_cache *cache, struct nl_object *obj,
 
                if (type->mt_act == NL_ACT_NEW) {
                        nl_cache_move(cache, obj);
-                       if (old == NULL && cb)
-                               cb(cache, obj, NL_ACT_NEW, data);
-                       else if (old) {
-                               if (nl_object_diff(old, obj) && cb)
+                       if (old == NULL) {
+                               if (cb_v2) {
+                                       cb_v2(cache, NULL, obj, 0, NL_ACT_NEW,
+                                             data);
+                               } else if (cb)
+                                       cb(cache, obj, NL_ACT_NEW, data);
+                       } else if (old) {
+                               uint64_t diff = 0;
+                               if (cb || cb_v2)
+                                       diff = nl_object_diff64(old, obj);
+                               if (diff && cb_v2) {
+                                       cb_v2(cache, old, obj, diff, NL_ACT_CHANGE,
+                                             data);
+                               } else if (diff && cb)
                                        cb(cache, obj, NL_ACT_CHANGE, data);
 
                                nl_object_put(old);
@@ -845,7 +870,27 @@ int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
        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, data);
+                                            change_cb, NULL, 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;
+}
+
+int nl_cache_include_v2(struct nl_cache *cache, struct nl_object *obj,
+                       change_func_v2_t change_cb, void *data)
+{
+       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],
+                                               NULL, change_cb, data);
 
        NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
               obj, cache, nl_cache_name(cache));
@@ -857,7 +902,12 @@ 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, ca->ca_change_data);
+       if (ca->ca_change_v2)
+               return nl_cache_include_v2(ca->ca_cache, c, ca->ca_change_v2,
+                                          ca->ca_change_data);
+       else
+               return nl_cache_include(ca->ca_cache, c, ca->ca_change,
+                                       ca->ca_change_data);
 }
 
 int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
index 1f23eb1384e9dfa49be0bcc7a7ab10511235ea52..3d51b2a75872918cea24e53135b369374df508b8 100644 (file)
@@ -60,9 +60,15 @@ static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
 
        if (ops->co_include_event)
                return ops->co_include_event(ca->ca_cache, obj, ca->ca_change,
+                                            ca->ca_change_v2,
                                             ca->ca_change_data);
-       else
-               return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
+       else {
+               if (ca->ca_change_v2)
+                       return nl_cache_include_v2(ca->ca_cache, obj, ca->ca_change_v2, ca->ca_change_data);
+               else
+                       return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
+       }
+
 }
 
 static int event_input(struct nl_msg *msg, void *arg)
@@ -194,6 +200,70 @@ errout:
        return err;
 }
 
+/**
+ * Set change_func_v2 for cache manager
+ * @arg mngr           Cache manager.
+ * @arg cache          Cache associated with the callback
+ * @arg cb             Function to be called upon changes.
+ * @arg data           Argument passed on to change callback
+ *
+ * Adds callback change_func_v2 to a registered cache. This callback provides
+ * in like the standard change_func the added or remove netlink object. In case
+ * of a change the old and the new object is provided as well as the according
+ * diff. If this callback is registered this has a higher priority then the
+ * change_func registered during cache registration. Hence only one callback is
+ * executed.
+ *
+ * The first netlink object in the callback is refering to the old object and
+ * the second to the new. This means on NL_ACT_CHANGE the first is the previous
+ * object in the cache and the second the updated version. On NL_ACT_DEL the
+ * first is the deleted object the second is NULL. On NL_ACT_NEW the first is
+ * NULL and the second the new netlink object.
+ *
+ * The user is responsible for calling nl_cache_mngr_poll() or monitor
+ * the socket and call nl_cache_mngr_data_ready() to allow the library
+ * to process netlink notification events.
+ *
+ * @see nl_cache_mngr_poll()
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
+ *                            cache type
+ * @return -NLE_OPNOTSUPP Cache type does not support updates
+ * @return -NLE_RANGE Cache of this type is not registered
+ */
+static int nl_cache_mngr_set_change_func_v2(struct nl_cache_mngr *mngr,
+                                           struct nl_cache *cache,
+                                           change_func_v2_t cb, void *data)
+{
+       struct nl_cache_ops *ops;
+       int i;
+
+       ops = cache->c_ops;
+       if (!ops)
+               return -NLE_INVAL;
+
+       if (ops->co_protocol != mngr->cm_protocol)
+               return -NLE_PROTO_MISMATCH;
+
+       if (ops->co_groups == NULL)
+               return -NLE_OPNOTSUPP;
+
+       for (i = 0; i < mngr->cm_nassocs; i++)
+               if (mngr->cm_assocs[i].ca_cache == cache)
+                       break;
+
+       if (i >= mngr->cm_nassocs) {
+               return -NLE_RANGE;
+       }
+
+       mngr->cm_assocs[i].ca_change_v2 = cb;
+       mngr->cm_assocs[i].ca_change_data = data;
+
+       return 0;
+}
+
 /**
  * Add cache to cache manager
  * @arg mngr           Cache manager.
@@ -291,6 +361,41 @@ errout_drop_membership:
        return err;
 }
 
+/**
+ * Add cache to cache manager
+ * @arg mngr           Cache manager.
+ * @arg cache          Cache to be added to cache manager
+ * @arg cb             V2 function to be called upon changes.
+ * @arg data           Argument passed on to change callback
+ *
+ * Adds cache to the manager. The operation will trigger a full
+ * dump request from the kernel to initially fill the contents
+ * of the cache. The manager will subscribe to the notification group
+ * of the cache and keep track of any further changes.
+ *
+ * The user is responsible for calling nl_cache_mngr_poll() or monitor
+ * the socket and call nl_cache_mngr_data_ready() to allow the library
+ * to process netlink notification events.
+ *
+ * @see nl_cache_mngr_poll()
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
+ *                            cache type
+ * @return -NLE_OPNOTSUPP Cache type does not support updates
+ * @return -NLE_EXIST Cache of this type already being managed
+ */
+int nl_cache_mngr_add_cache_v2(struct nl_cache_mngr *mngr, struct nl_cache *cache,
+                     change_func_v2_t cb, void *data) {
+       int err;
+       err = nl_cache_mngr_add_cache(mngr, cache, NULL, NULL);
+       if (err < 0)
+               return err;
+
+       return nl_cache_mngr_set_change_func_v2(mngr, cache, cb, data);
+}
+
 /**
  * Add cache to cache manager
  * @arg mngr           Cache manager.
index f25c7eb032b6a3587eaa9c1fc1c01a08b2063311..5bd99522945c328c8d9d17beed2155d1d26121e7 100644 (file)
@@ -918,7 +918,8 @@ errout:
 }
 
 static int xfrm_sa_update_cache (struct nl_cache *cache, struct nl_object *obj,
-                                 change_func_t change_cb, void *data)
+                                 change_func_t change_cb, change_func_v2_t change_cb_v2,
+                                void *data)
 {
        struct nl_object*       old_sa;
        struct xfrmnl_sa*       sa = (struct xfrmnl_sa*)obj;
@@ -947,18 +948,29 @@ static int xfrm_sa_update_cache (struct nl_cache *cache, struct nl_object *obj,
                         * cache and notify application of the expiry event. */
                        nl_cache_move (cache, obj);
 
-                       if (old_sa == NULL && change_cb)
+                       if (old_sa == NULL)
                        {
                                /* Application CB present, no previous instance of SA object present.
                                 * Notify application CB as a NEW event */
-                               change_cb (cache, obj, NL_ACT_NEW, data);
+                               if (change_cb_v2)
+                                       change_cb_v2(cache, NULL, obj, 0, NL_ACT_NEW, data);
+                               else if (change_cb)
+                                       change_cb(cache, obj, NL_ACT_NEW, data);
                        }
                        else if (old_sa)
                        {
+                               uint64_t diff = 0;
+                               if (change_cb || change_cb_v2)
+                                       diff = nl_object_diff64(old_sa, obj);
+
                                /* Application CB present, a previous instance of SA object present.
                                 * Notify application CB as a CHANGE1 event */
-                               if (nl_object_diff (old_sa, obj) && change_cb)
-                                       change_cb (cache, obj, NL_ACT_CHANGE, data);
+                               if (diff) {
+                                       if (change_cb_v2) {
+                                               change_cb_v2(cache, old_sa, obj, diff, NL_ACT_CHANGE, data);
+                                       } else if (change_cb)
+                                               change_cb(cache, obj, NL_ACT_CHANGE, data);
+                               }
                                nl_object_put (old_sa);
                        }
                }
@@ -966,7 +978,9 @@ static int xfrm_sa_update_cache (struct nl_cache *cache, struct nl_object *obj,
                {
                        /* Hard expiry event: Delete the object from the
                         * cache and notify application of the expiry event. */
-                       if (change_cb)
+                       if (change_cb_v2)
+                               change_cb_v2(cache, obj, NULL, 0, NL_ACT_DEL, data);
+                       else if (change_cb)
                                change_cb (cache, obj, NL_ACT_DEL, data);
                        nl_object_put (old_sa);
                }
@@ -978,7 +992,10 @@ static int xfrm_sa_update_cache (struct nl_cache *cache, struct nl_object *obj,
        {
                /* All other messages other than Expire, let the standard Libnl cache
                 * module handle it. */
-               return nl_cache_include (cache, obj, change_cb, data);
+               if (change_cb_v2)
+                       return nl_cache_include_v2(cache, obj, change_cb_v2, data);
+               else
+                       return nl_cache_include (cache, obj, change_cb, data);
        }
 }
 
index 9119e66e3984e4c50259b2394acb4a388fe965a4..4546a40c1f857373a681e101a6bc0d663b00cd01 100644 (file)
@@ -354,5 +354,7 @@ global:
 
 libnl_3_2_29 {
 global:
+       nl_cache_include_v2;
+       nl_cache_mngr_add_cache_v2;
        nl_strerror_l;
 } libnl_3_2_28;