/build/buildd/libnl-1.0~pre6/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-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup utils
00014  * @defgroup cache Caching
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 static inline char *nl_cache_name(struct nl_cache *cache)
00050 {
00051         return cache->c_ops ? cache->c_ops->co_name : "unknown";
00052 }
00053 
00054 /**
00055  * @name Access Functions
00056  * @{
00057  */
00058 
00059 /**
00060  * Return the number of items in the cache
00061  * @arg cache           cache handle
00062  */
00063 int nl_cache_nitems(struct nl_cache *cache)
00064 {
00065         return cache->c_nitems;
00066 }
00067 
00068 /**
00069  * Return the number of items matching a filter in the cache
00070  * @arg cache           Cache object.
00071  * @arg filter          Filter object.
00072  */
00073 int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
00074 {
00075         struct nl_cache_ops *ops = cache->c_ops;
00076         struct nl_object *obj;
00077         int nitems = 0;
00078         
00079         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00080                 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
00081                         continue;
00082 
00083                 nitems++;
00084         }
00085 
00086         return nitems;
00087 }
00088 
00089 /**
00090  * Returns \b true if the cache is empty.
00091  * @arg cache           Cache to check
00092  * @return \a true if the cache is empty, otherwise \b false is returned.
00093  */
00094 int nl_cache_is_empty(struct nl_cache *cache)
00095 {
00096         return nl_list_empty(&cache->c_items);
00097 }
00098 
00099 /**
00100  * Return the operations set of the cache
00101  * @arg cache           cache handle
00102  */
00103 struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache)
00104 {
00105         return cache->c_ops;
00106 }
00107 
00108 /**
00109  * Return the first element in the cache
00110  * @arg cache           cache handle
00111  */
00112 struct nl_object *nl_cache_get_first(struct nl_cache *cache)
00113 {
00114         if (nl_list_empty(&cache->c_items))
00115                 return NULL;
00116 
00117         return nl_list_entry(cache->c_items.next,
00118                              struct nl_object, ce_list);
00119 }
00120 
00121 /**
00122  * Return the last element in the cache
00123  * @arg cache           cache handle
00124  */
00125 struct nl_object *nl_cache_get_last(struct nl_cache *cache)
00126 {
00127         if (nl_list_empty(&cache->c_items))
00128                 return NULL;
00129 
00130         return nl_list_entry(cache->c_items.prev,
00131                              struct nl_object, ce_list);
00132 }
00133 
00134 /**
00135  * Return the next element in the cache
00136  * @arg obj             current object
00137  */
00138 struct nl_object *nl_cache_get_next(struct nl_object *obj)
00139 {
00140         if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list))
00141                 return NULL;
00142         else
00143                 return nl_list_entry(obj->ce_list.next,
00144                                      struct nl_object, ce_list);
00145 }
00146 
00147 /**
00148  * Return the previous element in the cache
00149  * @arg obj             current object
00150  */
00151 struct nl_object *nl_cache_get_prev(struct nl_object *obj)
00152 {
00153         if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list))
00154                 return NULL;
00155         else
00156                 return nl_list_entry(obj->ce_list.prev,
00157                                      struct nl_object, ce_list);
00158 }
00159 
00160 /** @} */
00161 
00162 /**
00163  * @name Cache Creation/Deletion
00164  * @{
00165  */
00166 
00167 /**
00168  * Allocate an empty cache of no certain type
00169  * 
00170  * @return A newly allocated and initialized cache.
00171  */
00172 struct nl_cache *nl_cache_alloc(void)
00173 {
00174         struct nl_cache *cache;
00175 
00176         cache = calloc(1, sizeof(*cache));
00177         if (!cache) {
00178                 nl_errno(ENOMEM);
00179                 return NULL;
00180         }
00181 
00182         nl_init_list_head(&cache->c_items);
00183         NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
00184 
00185         return cache;
00186 }
00187 
00188 /**
00189  * Allocate an empty cache based on cache operations
00190  * @arg ops             cache operations to base the cache on
00191  * @return A newly allocated and initialized cache.
00192  */
00193 struct nl_cache *nl_cache_alloc_from_ops(struct nl_cache_ops *ops)
00194 {
00195         struct nl_cache *new;
00196 
00197         new = nl_cache_alloc();
00198         if (!new)
00199                 return NULL;
00200 
00201         new->c_ops = ops;
00202 
00203         return new;
00204 }
00205 
00206 /**
00207  * Allocate an empty cache based on type name
00208  * @arg kind            Name of cache type
00209  * @return A newly allocated and initialized cache.
00210  */
00211 struct nl_cache *nl_cache_alloc_name(const char *kind)
00212 {
00213         struct nl_cache_ops *ops;
00214 
00215         ops = nl_cache_mngt_lookup(kind);
00216         if (!ops) {
00217                 nl_error(ENOENT, "Unable to lookup cache \"%s\"", kind);
00218                 return NULL;
00219         }
00220 
00221         return nl_cache_alloc_from_ops(ops);
00222 }
00223 
00224 /**
00225  * Clear a cache.
00226  * @arg cache           cache to clear
00227  *
00228  * Removes all elements of a cache.
00229  */
00230 void nl_cache_clear(struct nl_cache *cache)
00231 {
00232         struct nl_object *obj, *tmp;
00233 
00234         NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
00235 
00236         nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
00237                 nl_cache_delete(cache, obj);
00238 }
00239 
00240 /**
00241  * Free a cache.
00242  * @arg cache           Cache to free.
00243  *
00244  * Removes all elements of a cache and frees all memory.
00245  *
00246  * @note Use this function if you are working with allocated caches.
00247  */
00248 void nl_cache_free(struct nl_cache *cache)
00249 {
00250         nl_cache_clear(cache);
00251         NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
00252         free(cache);
00253 }
00254 
00255 /** @} */
00256 
00257 /**
00258  * @name Cache Modifications
00259  * @{
00260  */
00261 
00262 /**
00263  * Add an element to the cache.
00264  * @arg cache           cache to add a element to
00265  * @arg obj             Common obj to be added to the cache
00266  *
00267  * Adds the object \c obj to the tail of the cache \c cache and. The
00268  * cache is enlarged as needed.
00269  *
00270  * @return 0 or a negative error code.
00271  */
00272 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
00273 {
00274         struct nl_object *new;
00275 
00276         if (nl_object_shared(obj)) {
00277                 new = nl_object_clone(obj);
00278                 if (!new)
00279                         return nl_errno(ENOMEM);
00280 
00281                 nl_object_put(obj);
00282         } else
00283                 new = obj;
00284 
00285         new->ce_cache = cache;
00286 
00287         nl_list_add_tail(&new->ce_list, &cache->c_items);
00288         cache->c_nitems++;
00289 
00290         NL_DBG(1, "Added %p to cache %p <%s>.\n",
00291                new, cache, nl_cache_name(cache));
00292 
00293         return 0;
00294 }
00295 
00296 static int subsys_parse_cb(struct nl_object *c, struct nl_parser_param *p)
00297 {
00298         return nl_cache_add((struct nl_cache *) p->pp_arg, c);
00299 }
00300 
00301 /** @cond SKIP */
00302 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00303                    struct nlmsghdr *nlh, struct nl_parser_param *params)
00304 {
00305         int i, len, err, hdrsize;
00306 
00307         hdrsize = ops->co_hdrsize;
00308         len = nlh->nlmsg_len - nlmsg_msg_size(hdrsize);
00309         if (len < 0) {
00310                 err = nl_error(EINVAL, "netlink message too short to "
00311                                        "of kind %s", ops->co_name);
00312                 goto errout;
00313         }
00314 
00315         for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
00316                 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type)
00317                         return ops->co_msg_parser(who, nlh, params);
00318 
00319         err = nl_error(EINVAL, "Unsupported netlink message type %d",
00320                        nlh->nlmsg_type);
00321 errout:
00322         return err;
00323 }
00324 /** @endcond */
00325 
00326 /**
00327  * Parse a netlink message and add it to the cache.
00328  * @arg cache           cache to add element to
00329  * @arg msg             netlink message
00330  *
00331  * Parses a netlink message by calling the cache specific message parser
00332  * and adds the new element to the cache.
00333  *
00334  * @return 0 or a negative error code.
00335  */
00336 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
00337 {
00338         struct nl_parser_param p = {
00339                 .pp_cb = subsys_parse_cb,
00340                 .pp_arg = cache,
00341         };
00342 
00343         return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
00344 }
00345 
00346 /**
00347  * Delete an element from a cache.
00348  * @arg cache           cache to delete the element from
00349  * @arg obj             Object to delete
00350  *
00351  * Deletes the object \c obj from the cache \c cache.
00352  */
00353 void nl_cache_delete(struct nl_cache *cache, struct nl_object *obj)
00354 {
00355         if (obj->ce_cache != cache)
00356                 BUG();
00357 
00358         nl_list_del(&obj->ce_list);
00359         obj->ce_cache = NULL;
00360         nl_object_put(obj);
00361         cache->c_nitems--;
00362 
00363         NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
00364                obj, cache, nl_cache_name(cache));
00365 }
00366 
00367 /** @cond SKIP */
00368 struct update_xdata {
00369         struct nl_cache_ops *ops;
00370         struct nl_parser_param *params;
00371 };
00372 /** @endcond */
00373 
00374 static int update_msg_parser(struct nl_msg *msg, void *arg)
00375 {
00376         struct update_xdata *x = arg;
00377         
00378         return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
00379 }
00380 
00381 /**
00382  * Pickup a netlink dump response and put it into a cache.
00383  * @arg handle          Netlink handle.
00384  * @arg cache           Cache to put items into.
00385  *
00386  * Waits for netlink messages to arrive, parses them and puts them into
00387  * the specified cache.
00388  *
00389  * @return 0 on success or a negative error code.
00390  */
00391 int nl_cache_pickup(struct nl_handle *handle, struct nl_cache *cache)
00392 {
00393         int err;
00394         struct nl_cache_ops *ops = cache->c_ops;
00395         struct nl_cb *cb;
00396         struct nl_parser_param p = {
00397                 .pp_cb = subsys_parse_cb,
00398                 .pp_arg = cache,
00399         };
00400         struct update_xdata x = {
00401                 .ops = ops,
00402                 .params = &p,
00403         };
00404 
00405         NL_DBG(1, "Filling cache %p <%s>...\n", cache, nl_cache_name(cache));
00406 
00407         cb = nl_cb_clone(nl_handle_get_cb(handle));
00408         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
00409 
00410         err = nl_recvmsgs(handle, cb);
00411         if (err < 0)
00412                 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
00413                        "%d: %s", cache, nl_cache_name(cache),
00414                        err, nl_geterror());
00415 
00416         nl_cb_destroy(cb);
00417 
00418         return err;
00419 }
00420 
00421 /**
00422  * Update (synchronize) a local cache with the kernel.
00423  * @arg handle          netlink handle
00424  * @arg cache           cache to update
00425  *
00426  * Updates the local cache \c cache with the state in the kernel. During
00427  * this process the cache gets emptied and refilled with the new content
00428  * received from the kernel.
00429  *
00430  * @return 0 or a negative error code.
00431  */
00432 int nl_cache_update(struct nl_handle *handle, struct nl_cache *cache)
00433 {
00434         int err;
00435         struct nl_cache_ops *ops = cache->c_ops;
00436 
00437         err = ops->co_request_update(cache, handle);
00438         if (err < 0)
00439                 return err;
00440 
00441         NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
00442                cache, nl_cache_name(cache));
00443         nl_cache_clear(cache);
00444 
00445         return nl_cache_pickup(handle, cache);
00446 }
00447 
00448 /** @} */
00449 
00450 /**
00451  * @name Dumping
00452  * @{
00453  */
00454 
00455 /**
00456  * Dump all elements of a cache.
00457  * @arg cache           cache to dump
00458  * @arg params          dumping parameters
00459  *
00460  * Dumps all elements of the \a cache to the file descriptor \a fd.
00461  */
00462 void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
00463 {
00464         NL_DBG(1, "Dumping cache %p <%s>\n", cache, nl_cache_name(cache));
00465         nl_cache_dump_filter(cache, params, NULL);
00466 }
00467 
00468 /**
00469  * Dump all elements of a cache (filtered).
00470  * @arg cache           cache to dump
00471  * @arg params          dumping parameters (optional)
00472  * @arg filter          filter object
00473  *
00474  * Dumps all elements of the \a cache to the file descriptor \a fd
00475  * given they match the given filter \a filter.
00476  */
00477 void nl_cache_dump_filter(struct nl_cache *cache,
00478                           struct nl_dump_params *params,
00479                           struct nl_object *filter)
00480 {
00481         int type = params ? params->dp_type : NL_DUMP_FULL;
00482         struct nl_cache_ops *ops = cache->c_ops;
00483         struct nl_object *obj;
00484 
00485         if (type > NL_DUMP_MAX || type < 0)
00486                 BUG();
00487 
00488         if (!ops->co_dump[type])
00489                 return;
00490 
00491         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00492                 if (filter && obj->ce_ops != filter->ce_ops)
00493                         continue;
00494                 
00495                 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
00496                         continue;
00497 
00498                 dump_from_ops(obj, params);
00499         }
00500 }
00501 
00502 /** @} */
00503 
00504 /**
00505  * @name Iterators
00506  * @{
00507  */
00508 
00509 /**
00510  * Call a callback on each element of the cache.
00511  * @arg cache           cache to iterate on
00512  * @arg cb              callback function
00513  * @arg arg             argument passed to callback function
00514  *
00515  * Calls a callback function \a cb on each element of the \a cache.
00516  * The argument \a arg is passed on the callback function.
00517  */
00518 void nl_cache_foreach(struct nl_cache *cache,
00519                       void (*cb)(struct nl_object *, void *), void *arg)
00520 {
00521         nl_cache_foreach_filter(cache, NULL, cb, arg);
00522 }
00523 
00524 /**
00525  * Call a callback on each element of the cache (filtered).
00526  * @arg cache           cache to iterate on
00527  * @arg filter          filter object
00528  * @arg cb              callback function
00529  * @arg arg             argument passed to callback function
00530  *
00531  * Calls a callback function \a cb on each element of the \a cache
00532  * that matches the \a filter. The argument \a arg is passed on
00533  * to the callback function.
00534  */
00535 void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
00536                              void (*cb)(struct nl_object *, void *), void *arg)
00537 {
00538         struct nl_object *obj, *tmp;
00539         struct nl_cache_ops *ops = cache->c_ops;
00540 
00541         nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
00542                 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
00543                         continue;
00544 
00545                 cb(obj, arg);
00546         }
00547 }
00548 
00549 /** @} */
00550 
00551 /** @} */

Generated on Fri Apr 27 14:14:07 2007 for libnl by  doxygen 1.5.1