libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/cache.c
00001 /*
00002  * lib/cache.c          Caching Module
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup cache_mngt
00014  * @defgroup cache Cache
00015  *
00016  * @code
00017  *   Cache Management             |    | Type Specific Cache Operations
00018  *                                      
00019  *                                |    | +----------------+ +------------+
00020  *                                       | request update | | msg_parser |
00021  *                                |    | +----------------+ +------------+
00022  *                                     +- - - - -^- - - - - - - -^- -|- - - -
00023  *    nl_cache_update:            |              |               |   |
00024  *          1) --------- co_request_update ------+               |   |
00025  *                                |                              |   |
00026  *          2) destroy old cache     +----------- pp_cb ---------|---+
00027  *                                |  |                           |
00028  *          3) ---------- nl_recvmsgs ----------+   +- cb_valid -+
00029  *             +--------------+   |  |          |   |
00030  *             | nl_cache_add |<-----+   + - - -v- -|- - - - - - - - - - -
00031  *             +--------------+   |      | +-------------+
00032  *                                         | nl_recvmsgs |
00033  *                                |      | +-----|-^-----+
00034  *                                           +---v-|---+
00035  *                                |      |   | nl_recv |
00036  *                                           +---------+
00037  *                                |      |                 Core Netlink
00038  * @endcode
00039  * 
00040  * @{
00041  */
00042 
00043 #include <netlink-local.h>
00044 #include <netlink/netlink.h>
00045 #include <netlink/cache.h>
00046 #include <netlink/object.h>
00047 #include <netlink/utils.h>
00048 
00049 /**
00050  * @name Access Functions
00051  * @{
00052  */
00053 
00054 /**
00055  * Return the number of items in the cache
00056  * @arg cache           cache handle
00057  */
00058 int nl_cache_nitems(struct nl_cache *cache)
00059 {
00060         return cache->c_nitems;
00061 }
00062 
00063 /**
00064  * Return the number of items matching a filter in the cache
00065  * @arg cache           Cache object.
00066  * @arg filter          Filter object.
00067  */
00068 int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
00069 {
00070         struct nl_object *obj;
00071         int nitems = 0;
00072 
00073         if (cache->c_ops == NULL)
00074                 BUG();
00075 
00076         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00077                 if (filter && !nl_object_match_filter(obj, filter))
00078                         continue;
00079 
00080                 nitems++;
00081         }
00082 
00083         return nitems;
00084 }
00085 
00086 /**
00087  * Returns \b true if the cache is empty.
00088  * @arg cache           Cache to check
00089  * @return \a true if the cache is empty, otherwise \b false is returned.
00090  */
00091 int nl_cache_is_empty(struct nl_cache *cache)
00092 {
00093         return nl_list_empty(&cache->c_items);
00094 }
00095 
00096 /**
00097  * Return the operations set of the cache
00098  * @arg cache           cache handle
00099  */
00100 struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache)
00101 {
00102         return cache->c_ops;
00103 }
00104 
00105 /**
00106  * Return the first element in the cache
00107  * @arg cache           cache handle
00108  */
00109 struct nl_object *nl_cache_get_first(struct nl_cache *cache)
00110 {
00111         if (nl_list_empty(&cache->c_items))
00112                 return NULL;
00113 
00114         return nl_list_entry(cache->c_items.next,
00115                              struct nl_object, ce_list);
00116 }
00117 
00118 /**
00119  * Return the last element in the cache
00120  * @arg cache           cache handle
00121  */
00122 struct nl_object *nl_cache_get_last(struct nl_cache *cache)
00123 {
00124         if (nl_list_empty(&cache->c_items))
00125                 return NULL;
00126 
00127         return nl_list_entry(cache->c_items.prev,
00128                              struct nl_object, ce_list);
00129 }
00130 
00131 /**
00132  * Return the next element in the cache
00133  * @arg obj             current object
00134  */
00135 struct nl_object *nl_cache_get_next(struct nl_object *obj)
00136 {
00137         if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list))
00138                 return NULL;
00139         else
00140                 return nl_list_entry(obj->ce_list.next,
00141                                      struct nl_object, ce_list);
00142 }
00143 
00144 /**
00145  * Return the previous element in the cache
00146  * @arg obj             current object
00147  */
00148 struct nl_object *nl_cache_get_prev(struct nl_object *obj)
00149 {
00150         if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list))
00151                 return NULL;
00152         else
00153                 return nl_list_entry(obj->ce_list.prev,
00154                                      struct nl_object, ce_list);
00155 }
00156 
00157 /** @} */
00158 
00159 /**
00160  * @name Cache Allocation/Deletion
00161  * @{
00162  */
00163 
00164 /**
00165  * Allocate new cache
00166  * @arg ops             Cache operations
00167  *
00168  * Allocate and initialize a new cache based on the cache operations
00169  * provided.
00170  *
00171  * @return Allocated cache or NULL if allocation failed.
00172  */
00173 struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops)
00174 {
00175         struct nl_cache *cache;
00176 
00177         cache = calloc(1, sizeof(*cache));
00178         if (!cache)
00179                 return NULL;
00180 
00181         nl_init_list_head(&cache->c_items);
00182         cache->c_ops = ops;
00183 
00184         NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
00185 
00186         return cache;
00187 }
00188 
00189 /**
00190  * Allocate new cache and fill it
00191  * @arg ops             Cache operations
00192  * @arg sock            Netlink socket
00193  * @arg result          Result pointer
00194  *
00195  * Allocate new cache and fill it. Equivalent to calling:
00196  * @code
00197  * cache = nl_cache_alloc(ops);
00198  * nl_cache_refill(sock, cache);
00199  * @endcode
00200  *
00201  * @see nl_cache_alloc
00202  *
00203  * @return 0 on success or a negative error code.
00204  */
00205 int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock,
00206                             struct nl_cache **result)
00207 {
00208         struct nl_cache *cache;
00209         int err;
00210         
00211         if (!(cache = nl_cache_alloc(ops)))
00212                 return -NLE_NOMEM;
00213 
00214         if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
00215                 nl_cache_free(cache);
00216                 return err;
00217         }
00218 
00219         *result = cache;
00220         return 0;
00221 }
00222 
00223 /**
00224  * Allocate new cache based on type name
00225  * @arg kind            Name of cache type
00226  * @arg result          Result pointer
00227  *
00228  * Lookup cache ops via nl_cache_ops_lookup() and allocate the cache
00229  * by calling nl_cache_alloc(). Stores the allocated cache in the
00230  * result pointer provided.
00231  *
00232  * @see nl_cache_alloc
00233  *
00234  * @return 0 on success or a negative error code.
00235  */
00236 int nl_cache_alloc_name(const char *kind, struct nl_cache **result)
00237 {
00238         struct nl_cache_ops *ops;
00239         struct nl_cache *cache;
00240 
00241         ops = nl_cache_ops_lookup(kind);
00242         if (!ops)
00243                 return -NLE_NOCACHE;
00244 
00245         if (!(cache = nl_cache_alloc(ops)))
00246                 return -NLE_NOMEM;
00247 
00248         *result = cache;
00249         return 0;
00250 }
00251 
00252 /**
00253  * Allocate new cache containing a subset of an existing cache
00254  * @arg orig            Original cache to base new cache on
00255  * @arg filter          Filter defining the subset to be filled into the new cache
00256  *
00257  * Allocates a new cache matching the type of the cache specified by
00258  * \p orig. Iterates over the \p orig cache applying the specified
00259  * \p filter and copies all objects that match to the new cache.
00260  *
00261  * The copied objects are clones but do not contain a reference to each
00262  * other. Later modifications to objects in the original cache will
00263  * not affect objects in the new cache.
00264  *
00265  * @return A newly allocated cache or NULL.
00266  */
00267 struct nl_cache *nl_cache_subset(struct nl_cache *orig,
00268                                  struct nl_object *filter)
00269 {
00270         struct nl_cache *cache;
00271         struct nl_object *obj;
00272 
00273         if (!filter)
00274                 BUG();
00275 
00276         cache = nl_cache_alloc(orig->c_ops);
00277         if (!cache)
00278                 return NULL;
00279 
00280         nl_list_for_each_entry(obj, &orig->c_items, ce_list) {
00281                 if (!nl_object_match_filter(obj, filter))
00282                         continue;
00283 
00284                 nl_cache_add(cache, obj);
00285         }
00286 
00287         return cache;
00288 }
00289 
00290 /**
00291  * Remove all objects of a cache.
00292  * @arg cache           Cache to clear
00293  *
00294  * The objects are unliked/removed from the cache by calling
00295  * nl_cache_remove() on each object in the cache. If any of the objects
00296  * to not contain any further references to them, those objects will
00297  * be freed.
00298  *
00299  * Unlike with nl_cache_free(), the cache is not freed just emptied.
00300  */
00301 void nl_cache_clear(struct nl_cache *cache)
00302 {
00303         struct nl_object *obj, *tmp;
00304 
00305         NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
00306 
00307         nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
00308                 nl_cache_remove(obj);
00309 }
00310 
00311 /**
00312  * Free a cache.
00313  * @arg cache           Cache to free.
00314  *
00315  * Calls nl_cache_clear() to remove all objects associated with the
00316  * cache and frees the cache afterwards.
00317  *
00318  * @see nl_cache_clear()
00319  */
00320 void nl_cache_free(struct nl_cache *cache)
00321 {
00322         if (!cache)
00323                 return;
00324 
00325         nl_cache_clear(cache);
00326         NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
00327         free(cache);
00328 }
00329 
00330 /** @} */
00331 
00332 /**
00333  * @name Cache Modifications
00334  * @{
00335  */
00336 
00337 static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
00338 {
00339         obj->ce_cache = cache;
00340 
00341         nl_list_add_tail(&obj->ce_list, &cache->c_items);
00342         cache->c_nitems++;
00343 
00344         NL_DBG(1, "Added %p to cache %p <%s>.\n",
00345                obj, cache, nl_cache_name(cache));
00346 
00347         return 0;
00348 }
00349 
00350 /**
00351  * Add object to cache.
00352  * @arg cache           Cache
00353  * @arg obj             Object to be added to the cache
00354  *
00355  * Adds the object \p obj to the specified \p cache. In case the object
00356  * is already associated with another cache, the object is cloned before
00357  * adding it to the cache. In this case, the sole reference to the object
00358  * will be the one of the cache. Therefore clearing/freeing the cache
00359  * will result in the object being freed again.
00360  *
00361  * If the object has not been associated with a cache yet, the reference
00362  * counter of the object is incremented to account for the additional
00363  * reference.
00364  *
00365  * The type of the object and cache must match, otherwise an error is
00366  * returned (-NLE_OBJ_MISMATCH).
00367  *
00368  * @see nl_cache_move()
00369  *
00370  * @return 0 or a negative error code.
00371  */
00372 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
00373 {
00374         struct nl_object *new;
00375 
00376         if (cache->c_ops->co_obj_ops != obj->ce_ops)
00377                 return -NLE_OBJ_MISMATCH;
00378 
00379         if (!nl_list_empty(&obj->ce_list)) {
00380                 new = nl_object_clone(obj);
00381                 if (!new)
00382                         return -NLE_NOMEM;
00383         } else {
00384                 nl_object_get(obj);
00385                 new = obj;
00386         }
00387 
00388         return __cache_add(cache, new);
00389 }
00390 
00391 /**
00392  * Move object from one cache to another
00393  * @arg cache           Cache to move object to.
00394  * @arg obj             Object subject to be moved
00395  *
00396  * Removes the the specified object \p obj from its associated cache
00397  * and moves it to another cache.
00398  *
00399  * If the object is not associated with a cache, the function behaves
00400  * just like nl_cache_add().
00401  *
00402  * The type of the object and cache must match, otherwise an error is
00403  * returned (-NLE_OBJ_MISMATCH).
00404  *
00405  * @see nl_cache_add()
00406  *
00407  * @return 0 on success or a negative error code.
00408  */
00409 int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
00410 {
00411         if (cache->c_ops->co_obj_ops != obj->ce_ops)
00412                 return -NLE_OBJ_MISMATCH;
00413 
00414         NL_DBG(3, "Moving object %p to cache %p\n", obj, cache);
00415         
00416         /* Acquire reference, if already in a cache this will be
00417          * reverted during removal */
00418         nl_object_get(obj);
00419 
00420         if (!nl_list_empty(&obj->ce_list))
00421                 nl_cache_remove(obj);
00422 
00423         return __cache_add(cache, obj);
00424 }
00425 
00426 /**
00427  * Remove object from cache.
00428  * @arg obj             Object to remove from cache
00429  *
00430  * Removes the object \c obj from the cache it is associated with. The
00431  * reference counter of the object will be decremented. If the reference
00432  * to the object was the only one remaining, the object will be freed.
00433  *
00434  * If no cache is associated with the object, this function is a NOP.
00435  */
00436 void nl_cache_remove(struct nl_object *obj)
00437 {
00438         struct nl_cache *cache = obj->ce_cache;
00439 
00440         if (cache == NULL)
00441                 return;
00442 
00443         nl_list_del(&obj->ce_list);
00444         obj->ce_cache = NULL;
00445         nl_object_put(obj);
00446         cache->c_nitems--;
00447 
00448         NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
00449                obj, cache, nl_cache_name(cache));
00450 }
00451 
00452 /** @} */
00453 
00454 /**
00455  * @name Synchronization
00456  * @{
00457  */
00458 
00459 /**
00460  * Set synchronization arg1 of cache
00461  * @arg cache           Cache
00462  * @arg arg             argument
00463  *
00464  * Synchronization arguments are used to specify filters when
00465  * requesting dumps from the kernel.
00466  */
00467 void nl_cache_set_arg1(struct nl_cache *cache, int arg)
00468 {
00469         cache->c_iarg1 = arg;
00470 }
00471 
00472 /**
00473  * Set synchronization arg2 of cache
00474  * @arg cache           Cache
00475  * @arg arg             argument
00476  *
00477  * Synchronization arguments are used to specify filters when
00478  * requesting dumps from the kernel.
00479  */
00480 void nl_cache_set_arg2(struct nl_cache *cache, int arg)
00481 {
00482         cache->c_iarg2 = arg;
00483 }
00484 
00485 /**
00486  * Invoke the request-update operation
00487  * @arg sk              Netlink socket.
00488  * @arg cache           Cache
00489  *
00490  * This function causes the \e request-update function of the cache
00491  * operations to be invoked. This usually causes a dump request to
00492  * be sent over the netlink socket which triggers the kernel to dump
00493  * all objects of a specific type to be dumped onto the netlink
00494  * socket for pickup.
00495  *
00496  * The behaviour of this function depends on the implemenation of
00497  * the \e request_update function of each individual type of cache.
00498  *
00499  * This function will not have any effects on the cache (unless the
00500  * request_update implementation of the cache operations does so).
00501  *
00502  * Use nl_cache_pickup() to pick-up (read) the objects from the socket
00503  * and fill them into the cache.
00504  *
00505  * @see nl_cache_pickup(), nl_cache_resync()
00506  *
00507  * @return 0 on success or a negative error code.
00508  */
00509 static int nl_cache_request_full_dump(struct nl_sock *sk,
00510                                       struct nl_cache *cache)
00511 {
00512         NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n",
00513                   cache, nl_cache_name(cache));
00514 
00515         if (cache->c_ops->co_request_update == NULL)
00516                 return -NLE_OPNOTSUPP;
00517 
00518         return cache->c_ops->co_request_update(cache, sk);
00519 }
00520 
00521 /** @cond SKIP */
00522 struct update_xdata {
00523         struct nl_cache_ops *ops;
00524         struct nl_parser_param *params;
00525 };
00526 
00527 static int update_msg_parser(struct nl_msg *msg, void *arg)
00528 {
00529         struct update_xdata *x = arg;
00530         
00531         return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
00532 }
00533 /** @endcond */
00534 
00535 /**
00536  * Pick-up a netlink request-update with your own parser
00537  * @arg sk              Netlink socket
00538  * @arg cache           Cache
00539  * @arg param           Parser parameters
00540  */
00541 static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
00542                           struct nl_parser_param *param)
00543 {
00544         int err;
00545         struct nl_cb *cb;
00546         struct update_xdata x = {
00547                 .ops = cache->c_ops,
00548                 .params = param,
00549         };
00550 
00551         NL_DBG(1, "Picking up answer for cache %p <%s>...\n",
00552                   cache, nl_cache_name(cache));
00553 
00554         cb = nl_cb_clone(sk->s_cb);
00555         if (cb == NULL)
00556                 return -NLE_NOMEM;
00557 
00558         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
00559 
00560         err = nl_recvmsgs(sk, cb);
00561         if (err < 0)
00562                 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
00563                        "%d: %s", cache, nl_cache_name(cache),
00564                        err, nl_geterror(err));
00565 
00566         nl_cb_put(cb);
00567 
00568         return err;
00569 }
00570 
00571 static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
00572 {
00573         return nl_cache_add((struct nl_cache *) p->pp_arg, c);
00574 }
00575 
00576 /**
00577  * Pickup a netlink dump response and put it into a cache.
00578  * @arg sk              Netlink socket.
00579  * @arg cache           Cache to put items into.
00580  *
00581  * Waits for netlink messages to arrive, parses them and puts them into
00582  * the specified cache.
00583  *
00584  * @return 0 on success or a negative error code.
00585  */
00586 int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
00587 {
00588         struct nl_parser_param p = {
00589                 .pp_cb = pickup_cb,
00590                 .pp_arg = cache,
00591         };
00592 
00593         return __cache_pickup(sk, cache, &p);
00594 }
00595 
00596 static int cache_include(struct nl_cache *cache, struct nl_object *obj,
00597                          struct nl_msgtype *type, change_func_t cb, void *data)
00598 {
00599         struct nl_object *old;
00600 
00601         switch (type->mt_act) {
00602         case NL_ACT_NEW:
00603         case NL_ACT_DEL:
00604                 old = nl_cache_search(cache, obj);
00605                 if (old) {
00606                         nl_cache_remove(old);
00607                         if (type->mt_act == NL_ACT_DEL) {
00608                                 if (cb)
00609                                         cb(cache, old, NL_ACT_DEL, data);
00610                                 nl_object_put(old);
00611                         }
00612                 }
00613 
00614                 if (type->mt_act == NL_ACT_NEW) {
00615                         nl_cache_move(cache, obj);
00616                         if (old == NULL && cb)
00617                                 cb(cache, obj, NL_ACT_NEW, data);
00618                         else if (old) {
00619                                 if (nl_object_diff(old, obj) && cb)
00620                                         cb(cache, obj, NL_ACT_CHANGE, data);
00621 
00622                                 nl_object_put(old);
00623                         }
00624                 }
00625                 break;
00626         default:
00627                 NL_DBG(2, "Unknown action associated to object %p\n", obj);
00628                 return 0;
00629         }
00630 
00631         return 0;
00632 }
00633 
00634 int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
00635                      change_func_t change_cb, void *data)
00636 {
00637         struct nl_cache_ops *ops = cache->c_ops;
00638         int i;
00639 
00640         if (ops->co_obj_ops != obj->ce_ops)
00641                 return -NLE_OBJ_MISMATCH;
00642 
00643         for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
00644                 if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
00645                         return cache_include(cache, obj, &ops->co_msgtypes[i],
00646                                              change_cb, data);
00647 
00648         return -NLE_MSGTYPE_NOSUPPORT;
00649 }
00650 
00651 static int resync_cb(struct nl_object *c, struct nl_parser_param *p)
00652 {
00653         struct nl_cache_assoc *ca = p->pp_arg;
00654 
00655         return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data);
00656 }
00657 
00658 int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
00659                     change_func_t change_cb, void *data)
00660 {
00661         struct nl_object *obj, *next;
00662         struct nl_cache_assoc ca = {
00663                 .ca_cache = cache,
00664                 .ca_change = change_cb,
00665                 .ca_change_data = data,
00666         };
00667         struct nl_parser_param p = {
00668                 .pp_cb = resync_cb,
00669                 .pp_arg = &ca,
00670         };
00671         int err;
00672 
00673         NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache));
00674 
00675 restart:
00676         /* Mark all objects so we can see if some of them are obsolete */
00677         nl_cache_mark_all(cache);
00678 
00679         err = nl_cache_request_full_dump(sk, cache);
00680         if (err < 0)
00681                 goto errout;
00682 
00683         err = __cache_pickup(sk, cache, &p);
00684         if (err == -NLE_DUMP_INTR)
00685                 goto restart;
00686         else if (err < 0)
00687                 goto errout;
00688 
00689         nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) {
00690                 if (nl_object_is_marked(obj)) {
00691                         nl_object_get(obj);
00692                         nl_cache_remove(obj);
00693                         if (change_cb)
00694                                 change_cb(cache, obj, NL_ACT_DEL, data);
00695                         nl_object_put(obj);
00696                 }
00697         }
00698 
00699         NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache));
00700 
00701         err = 0;
00702 errout:
00703         return err;
00704 }
00705 
00706 /** @} */
00707 
00708 /**
00709  * @name Parsing
00710  * @{
00711  */
00712 
00713 /** @cond SKIP */
00714 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00715                    struct nlmsghdr *nlh, struct nl_parser_param *params)
00716 {
00717         int i, err;
00718 
00719         if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize))
00720                 return -NLE_MSG_TOOSHORT;
00721 
00722         for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) {
00723                 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) {
00724                         err = ops->co_msg_parser(ops, who, nlh, params);
00725                         if (err != -NLE_OPNOTSUPP)
00726                                 goto errout;
00727                 }
00728         }
00729 
00730 
00731         err = -NLE_MSGTYPE_NOSUPPORT;
00732 errout:
00733         return err;
00734 }
00735 /** @endcond */
00736 
00737 /**
00738  * Parse a netlink message and add it to the cache.
00739  * @arg cache           cache to add element to
00740  * @arg msg             netlink message
00741  *
00742  * Parses a netlink message by calling the cache specific message parser
00743  * and adds the new element to the cache.
00744  *
00745  * @return 0 or a negative error code.
00746  */
00747 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
00748 {
00749         struct nl_parser_param p = {
00750                 .pp_cb = pickup_cb,
00751                 .pp_arg = cache,
00752         };
00753 
00754         return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
00755 }
00756 
00757 /**
00758  * (Re)fill a cache with the contents in the kernel.
00759  * @arg sk              Netlink socket.
00760  * @arg cache           cache to update
00761  *
00762  * Clears the specified cache and fills it with the current state in
00763  * the kernel.
00764  *
00765  * @return 0 or a negative error code.
00766  */
00767 int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
00768 {
00769         int err;
00770 
00771 restart:
00772         err = nl_cache_request_full_dump(sk, cache);
00773         if (err < 0)
00774                 return err;
00775 
00776         NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
00777                cache, nl_cache_name(cache));
00778         nl_cache_clear(cache);
00779 
00780         err = nl_cache_pickup(sk, cache);
00781         if (err == -NLE_DUMP_INTR) {
00782                 fprintf(stderr, "dump interrupted, restarting!\n");
00783                 goto restart;
00784         }
00785         
00786         return err;
00787 }
00788 
00789 /** @} */
00790 
00791 /**
00792  * @name Utillities
00793  * @{
00794  */
00795 
00796 /**
00797  * Search object in cache
00798  * @arg cache           Cache
00799  * @arg needle          Object to look for.
00800  *
00801  * Searches the cache for an object which matches the object \p needle.
00802  * The function nl_object_identical() is used to determine if the
00803  * objects match. If a matching object is found, the reference counter
00804  * is incremented and the object is returned.
00805  * 
00806  * Therefore, if an object is returned, the reference to the object
00807  * must be returned by calling nl_object_put() after usage.
00808  *
00809  * @return Reference to object or NULL if not found.
00810  */
00811 struct nl_object *nl_cache_search(struct nl_cache *cache,
00812                                   struct nl_object *needle)
00813 {
00814         struct nl_object *obj;
00815 
00816         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00817                 if (nl_object_identical(obj, needle)) {
00818                         nl_object_get(obj);
00819                         return obj;
00820                 }
00821         }
00822 
00823         return NULL;
00824 }
00825 
00826 /**
00827  * Mark all objects of a cache
00828  * @arg cache           Cache
00829  *
00830  * Marks all objects of a cache by calling nl_object_mark() on each
00831  * object associated with the cache.
00832  */
00833 void nl_cache_mark_all(struct nl_cache *cache)
00834 {
00835         struct nl_object *obj;
00836 
00837         NL_DBG(2, "Marking all objects in cache %p <%s>...\n",
00838                   cache, nl_cache_name(cache));
00839 
00840         nl_list_for_each_entry(obj, &cache->c_items, ce_list)
00841                 nl_object_mark(obj);
00842 }
00843 
00844 /** @} */
00845 
00846 /**
00847  * @name Dumping
00848  * @{
00849  */
00850 
00851 /**
00852  * Dump all elements of a cache.
00853  * @arg cache           cache to dump
00854  * @arg params          dumping parameters
00855  *
00856  * Dumps all elements of the \a cache to the file descriptor \a fd.
00857  */
00858 void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
00859 {
00860         nl_cache_dump_filter(cache, params, NULL);
00861 }
00862 
00863 /**
00864  * Dump all elements of a cache (filtered).
00865  * @arg cache           cache to dump
00866  * @arg params          dumping parameters (optional)
00867  * @arg filter          filter object
00868  *
00869  * Dumps all elements of the \a cache to the file descriptor \a fd
00870  * given they match the given filter \a filter.
00871  */
00872 void nl_cache_dump_filter(struct nl_cache *cache,
00873                           struct nl_dump_params *params,
00874                           struct nl_object *filter)
00875 {
00876         int type = params ? params->dp_type : NL_DUMP_DETAILS;
00877         struct nl_object_ops *ops;
00878         struct nl_object *obj;
00879 
00880         NL_DBG(2, "Dumping cache %p <%s> filter %p\n",
00881                cache, nl_cache_name(cache), filter);
00882 
00883         if (type > NL_DUMP_MAX || type < 0)
00884                 BUG();
00885 
00886         if (cache->c_ops == NULL)
00887                 BUG();
00888 
00889         ops = cache->c_ops->co_obj_ops;
00890         if (!ops->oo_dump[type])
00891                 return;
00892 
00893         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00894                 if (filter && !nl_object_match_filter(obj, filter))
00895                         continue;
00896 
00897                 NL_DBG(4, "Dumping object %p...\n", obj);
00898                 dump_from_ops(obj, params);
00899         }
00900 }
00901 
00902 /** @} */
00903 
00904 /**
00905  * @name Iterators
00906  * @{
00907  */
00908 
00909 /**
00910  * Call a callback on each element of the cache.
00911  * @arg cache           cache to iterate on
00912  * @arg cb              callback function
00913  * @arg arg             argument passed to callback function
00914  *
00915  * Calls a callback function \a cb on each element of the \a cache.
00916  * The argument \a arg is passed on the callback function.
00917  */
00918 void nl_cache_foreach(struct nl_cache *cache,
00919                       void (*cb)(struct nl_object *, void *), void *arg)
00920 {
00921         nl_cache_foreach_filter(cache, NULL, cb, arg);
00922 }
00923 
00924 /**
00925  * Call a callback on each element of the cache (filtered).
00926  * @arg cache           cache to iterate on
00927  * @arg filter          filter object
00928  * @arg cb              callback function
00929  * @arg arg             argument passed to callback function
00930  *
00931  * Calls a callback function \a cb on each element of the \a cache
00932  * that matches the \a filter. The argument \a arg is passed on
00933  * to the callback function.
00934  */
00935 void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
00936                              void (*cb)(struct nl_object *, void *), void *arg)
00937 {
00938         struct nl_object *obj, *tmp;
00939 
00940         if (cache->c_ops == NULL)
00941                 BUG();
00942 
00943         nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
00944                 if (filter) {
00945                         int diff = nl_object_match_filter(obj, filter);
00946 
00947                         NL_DBG(3, "%p<->%p object difference: %x\n",
00948                                 obj, filter, diff);
00949 
00950                         if (!diff)
00951                                 continue;
00952                 }
00953 
00954                 /* Caller may hold obj for a long time */
00955                 nl_object_get(obj);
00956 
00957                 cb(obj, arg);
00958 
00959                 nl_object_put(obj);
00960         }
00961 }
00962 
00963 /** @} */
00964 
00965 /** @} */