libnl 3.0
|
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_ops *ops; 00071 struct nl_object *obj; 00072 int nitems = 0; 00073 00074 if (cache->c_ops == NULL) 00075 BUG(); 00076 00077 ops = cache->c_ops->co_obj_ops; 00078 00079 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 00080 if (filter && !nl_object_match_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 00169 * @arg ops cache operations to base the cache on 00170 * 00171 * @return A newly allocated and initialized cache. 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 int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, 00190 struct nl_cache **result) 00191 { 00192 struct nl_cache *cache; 00193 int err; 00194 00195 if (!(cache = nl_cache_alloc(ops))) 00196 return -NLE_NOMEM; 00197 00198 if (sock && (err = nl_cache_refill(sock, cache)) < 0) { 00199 nl_cache_free(cache); 00200 return err; 00201 } 00202 00203 *result = cache; 00204 return 0; 00205 } 00206 00207 /** 00208 * Allocate an empty cache based on type name 00209 * @arg kind Name of cache type 00210 * @return A newly allocated and initialized cache. 00211 */ 00212 int nl_cache_alloc_name(const char *kind, struct nl_cache **result) 00213 { 00214 struct nl_cache_ops *ops; 00215 struct nl_cache *cache; 00216 00217 ops = nl_cache_ops_lookup(kind); 00218 if (!ops) 00219 return -NLE_NOCACHE; 00220 00221 if (!(cache = nl_cache_alloc(ops))) 00222 return -NLE_NOMEM; 00223 00224 *result = cache; 00225 return 0; 00226 } 00227 00228 /** 00229 * Allocate a new cache containing a subset of a cache 00230 * @arg orig Original cache to be based on 00231 * @arg filter Filter defining the subset to be filled into new cache 00232 * @return A newly allocated cache or NULL. 00233 */ 00234 struct nl_cache *nl_cache_subset(struct nl_cache *orig, 00235 struct nl_object *filter) 00236 { 00237 struct nl_cache *cache; 00238 struct nl_object_ops *ops; 00239 struct nl_object *obj; 00240 00241 if (!filter) 00242 BUG(); 00243 00244 cache = nl_cache_alloc(orig->c_ops); 00245 if (!cache) 00246 return NULL; 00247 00248 ops = orig->c_ops->co_obj_ops; 00249 00250 nl_list_for_each_entry(obj, &orig->c_items, ce_list) { 00251 if (!nl_object_match_filter(obj, filter)) 00252 continue; 00253 00254 nl_cache_add(cache, obj); 00255 } 00256 00257 return cache; 00258 } 00259 00260 /** 00261 * Clear a cache. 00262 * @arg cache cache to clear 00263 * 00264 * Removes all elements of a cache. 00265 */ 00266 void nl_cache_clear(struct nl_cache *cache) 00267 { 00268 struct nl_object *obj, *tmp; 00269 00270 NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache)); 00271 00272 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) 00273 nl_cache_remove(obj); 00274 } 00275 00276 /** 00277 * Free a cache. 00278 * @arg cache Cache to free. 00279 * 00280 * Removes all elements of a cache and frees all memory. 00281 * 00282 * @note Use this function if you are working with allocated caches. 00283 */ 00284 void nl_cache_free(struct nl_cache *cache) 00285 { 00286 if (!cache) 00287 return; 00288 00289 nl_cache_clear(cache); 00290 NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache)); 00291 free(cache); 00292 } 00293 00294 /** @} */ 00295 00296 /** 00297 * @name Cache Modifications 00298 * @{ 00299 */ 00300 00301 static int __cache_add(struct nl_cache *cache, struct nl_object *obj) 00302 { 00303 obj->ce_cache = cache; 00304 00305 nl_list_add_tail(&obj->ce_list, &cache->c_items); 00306 cache->c_nitems++; 00307 00308 NL_DBG(1, "Added %p to cache %p <%s>.\n", 00309 obj, cache, nl_cache_name(cache)); 00310 00311 return 0; 00312 } 00313 00314 /** 00315 * Add object to a cache. 00316 * @arg cache Cache to add object to 00317 * @arg obj Object to be added to the cache 00318 * 00319 * Adds the given object to the specified cache. The object is cloned 00320 * if it has been added to another cache already. 00321 * 00322 * @return 0 or a negative error code. 00323 */ 00324 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) 00325 { 00326 struct nl_object *new; 00327 00328 if (cache->c_ops->co_obj_ops != obj->ce_ops) 00329 return -NLE_OBJ_MISMATCH; 00330 00331 if (!nl_list_empty(&obj->ce_list)) { 00332 new = nl_object_clone(obj); 00333 if (!new) 00334 return -NLE_NOMEM; 00335 } else { 00336 nl_object_get(obj); 00337 new = obj; 00338 } 00339 00340 return __cache_add(cache, new); 00341 } 00342 00343 /** 00344 * Move object from one cache to another 00345 * @arg cache Cache to move object to. 00346 * @arg obj Object subject to be moved 00347 * 00348 * Removes the given object from its associated cache if needed 00349 * and adds it to the new cache. 00350 * 00351 * @return 0 on success or a negative error code. 00352 */ 00353 int nl_cache_move(struct nl_cache *cache, struct nl_object *obj) 00354 { 00355 if (cache->c_ops->co_obj_ops != obj->ce_ops) 00356 return -NLE_OBJ_MISMATCH; 00357 00358 NL_DBG(3, "Moving object %p to cache %p\n", obj, cache); 00359 00360 /* Acquire reference, if already in a cache this will be 00361 * reverted during removal */ 00362 nl_object_get(obj); 00363 00364 if (!nl_list_empty(&obj->ce_list)) 00365 nl_cache_remove(obj); 00366 00367 return __cache_add(cache, obj); 00368 } 00369 00370 /** 00371 * Removes an object from a cache. 00372 * @arg obj Object to remove from its cache 00373 * 00374 * Removes the object \c obj from the cache it is assigned to, since 00375 * an object can only be assigned to one cache at a time, the cache 00376 * must ne be passed along with it. 00377 */ 00378 void nl_cache_remove(struct nl_object *obj) 00379 { 00380 struct nl_cache *cache = obj->ce_cache; 00381 00382 if (cache == NULL) 00383 return; 00384 00385 nl_list_del(&obj->ce_list); 00386 obj->ce_cache = NULL; 00387 nl_object_put(obj); 00388 cache->c_nitems--; 00389 00390 NL_DBG(1, "Deleted %p from cache %p <%s>.\n", 00391 obj, cache, nl_cache_name(cache)); 00392 } 00393 00394 /** 00395 * Search for an object in a cache 00396 * @arg cache Cache to search in. 00397 * @arg needle Object to look for. 00398 * 00399 * Iterates over the cache and looks for an object with identical 00400 * identifiers as the needle. 00401 * 00402 * @return Reference to object or NULL if not found. 00403 * @note The returned object must be returned via nl_object_put(). 00404 */ 00405 struct nl_object *nl_cache_search(struct nl_cache *cache, 00406 struct nl_object *needle) 00407 { 00408 struct nl_object *obj; 00409 00410 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 00411 if (nl_object_identical(obj, needle)) { 00412 nl_object_get(obj); 00413 return obj; 00414 } 00415 } 00416 00417 return NULL; 00418 } 00419 00420 00421 /** @} */ 00422 00423 /** 00424 * @name Synchronization 00425 * @{ 00426 */ 00427 00428 /** 00429 * Request a full dump from the kernel to fill a cache 00430 * @arg sk Netlink socket. 00431 * @arg cache Cache subjected to be filled. 00432 * 00433 * Send a dumping request to the kernel causing it to dump all objects 00434 * related to the specified cache to the netlink socket. 00435 * 00436 * Use nl_cache_pickup() to read the objects from the socket and fill them 00437 * into a cache. 00438 */ 00439 int nl_cache_request_full_dump(struct nl_sock *sk, struct nl_cache *cache) 00440 { 00441 NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n", 00442 cache, nl_cache_name(cache)); 00443 00444 if (cache->c_ops->co_request_update == NULL) 00445 return -NLE_OPNOTSUPP; 00446 00447 return cache->c_ops->co_request_update(cache, sk); 00448 } 00449 00450 /** @cond SKIP */ 00451 struct update_xdata { 00452 struct nl_cache_ops *ops; 00453 struct nl_parser_param *params; 00454 }; 00455 00456 static int update_msg_parser(struct nl_msg *msg, void *arg) 00457 { 00458 struct update_xdata *x = arg; 00459 00460 return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params); 00461 } 00462 /** @endcond */ 00463 00464 int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache, 00465 struct nl_parser_param *param) 00466 { 00467 int err; 00468 struct nl_cb *cb; 00469 struct update_xdata x = { 00470 .ops = cache->c_ops, 00471 .params = param, 00472 }; 00473 00474 NL_DBG(1, "Picking up answer for cache %p <%s>...\n", 00475 cache, nl_cache_name(cache)); 00476 00477 cb = nl_cb_clone(sk->s_cb); 00478 if (cb == NULL) 00479 return -NLE_NOMEM; 00480 00481 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x); 00482 00483 err = nl_recvmsgs(sk, cb); 00484 if (err < 0) 00485 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \ 00486 "%d: %s", cache, nl_cache_name(cache), 00487 err, nl_geterror(err)); 00488 00489 nl_cb_put(cb); 00490 00491 return err; 00492 } 00493 00494 static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) 00495 { 00496 return nl_cache_add((struct nl_cache *) p->pp_arg, c); 00497 } 00498 00499 /** 00500 * Pickup a netlink dump response and put it into a cache. 00501 * @arg sk Netlink socket. 00502 * @arg cache Cache to put items into. 00503 * 00504 * Waits for netlink messages to arrive, parses them and puts them into 00505 * the specified cache. 00506 * 00507 * @return 0 on success or a negative error code. 00508 */ 00509 int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) 00510 { 00511 struct nl_parser_param p = { 00512 .pp_cb = pickup_cb, 00513 .pp_arg = cache, 00514 }; 00515 00516 return __cache_pickup(sk, cache, &p); 00517 } 00518 00519 static int cache_include(struct nl_cache *cache, struct nl_object *obj, 00520 struct nl_msgtype *type, change_func_t cb, void *data) 00521 { 00522 struct nl_object *old; 00523 00524 switch (type->mt_act) { 00525 case NL_ACT_NEW: 00526 case NL_ACT_DEL: 00527 old = nl_cache_search(cache, obj); 00528 if (old) { 00529 nl_cache_remove(old); 00530 if (type->mt_act == NL_ACT_DEL) { 00531 if (cb) 00532 cb(cache, old, NL_ACT_DEL, data); 00533 nl_object_put(old); 00534 } 00535 } 00536 00537 if (type->mt_act == NL_ACT_NEW) { 00538 nl_cache_move(cache, obj); 00539 if (old == NULL && cb) 00540 cb(cache, obj, NL_ACT_NEW, data); 00541 else if (old) { 00542 if (nl_object_diff(old, obj) && cb) 00543 cb(cache, obj, NL_ACT_CHANGE, data); 00544 00545 nl_object_put(old); 00546 } 00547 } 00548 break; 00549 default: 00550 NL_DBG(2, "Unknown action associated to object %p\n", obj); 00551 return 0; 00552 } 00553 00554 return 0; 00555 } 00556 00557 int nl_cache_include(struct nl_cache *cache, struct nl_object *obj, 00558 change_func_t change_cb, void *data) 00559 { 00560 struct nl_cache_ops *ops = cache->c_ops; 00561 int i; 00562 00563 if (ops->co_obj_ops != obj->ce_ops) 00564 return -NLE_OBJ_MISMATCH; 00565 00566 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) 00567 if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype) 00568 return cache_include(cache, obj, &ops->co_msgtypes[i], 00569 change_cb, data); 00570 00571 return -NLE_MSGTYPE_NOSUPPORT; 00572 } 00573 00574 static int resync_cb(struct nl_object *c, struct nl_parser_param *p) 00575 { 00576 struct nl_cache_assoc *ca = p->pp_arg; 00577 00578 return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data); 00579 } 00580 00581 int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache, 00582 change_func_t change_cb, void *data) 00583 { 00584 struct nl_object *obj, *next; 00585 struct nl_cache_assoc ca = { 00586 .ca_cache = cache, 00587 .ca_change = change_cb, 00588 .ca_change_data = data, 00589 }; 00590 struct nl_parser_param p = { 00591 .pp_cb = resync_cb, 00592 .pp_arg = &ca, 00593 }; 00594 int err; 00595 00596 NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache)); 00597 00598 /* Mark all objects so we can see if some of them are obsolete */ 00599 nl_cache_mark_all(cache); 00600 00601 err = nl_cache_request_full_dump(sk, cache); 00602 if (err < 0) 00603 goto errout; 00604 00605 err = __cache_pickup(sk, cache, &p); 00606 if (err < 0) 00607 goto errout; 00608 00609 nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) { 00610 if (nl_object_is_marked(obj)) { 00611 nl_object_get(obj); 00612 nl_cache_remove(obj); 00613 if (change_cb) 00614 change_cb(cache, obj, NL_ACT_DEL, data); 00615 nl_object_put(obj); 00616 } 00617 } 00618 00619 NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache)); 00620 00621 err = 0; 00622 errout: 00623 return err; 00624 } 00625 00626 /** @} */ 00627 00628 /** 00629 * @name Parsing 00630 * @{ 00631 */ 00632 00633 /** @cond SKIP */ 00634 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00635 struct nlmsghdr *nlh, struct nl_parser_param *params) 00636 { 00637 int i, err; 00638 00639 if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) 00640 return -NLE_MSG_TOOSHORT; 00641 00642 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) { 00643 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) { 00644 err = ops->co_msg_parser(ops, who, nlh, params); 00645 if (err != -NLE_OPNOTSUPP) 00646 goto errout; 00647 } 00648 } 00649 00650 00651 err = -NLE_MSGTYPE_NOSUPPORT; 00652 errout: 00653 return err; 00654 } 00655 /** @endcond */ 00656 00657 /** 00658 * Parse a netlink message and add it to the cache. 00659 * @arg cache cache to add element to 00660 * @arg msg netlink message 00661 * 00662 * Parses a netlink message by calling the cache specific message parser 00663 * and adds the new element to the cache. 00664 * 00665 * @return 0 or a negative error code. 00666 */ 00667 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) 00668 { 00669 struct nl_parser_param p = { 00670 .pp_cb = pickup_cb, 00671 .pp_arg = cache, 00672 }; 00673 00674 return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p); 00675 } 00676 00677 /** 00678 * (Re)fill a cache with the contents in the kernel. 00679 * @arg sk Netlink socket. 00680 * @arg cache cache to update 00681 * 00682 * Clears the specified cache and fills it with the current state in 00683 * the kernel. 00684 * 00685 * @return 0 or a negative error code. 00686 */ 00687 int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) 00688 { 00689 int err; 00690 00691 err = nl_cache_request_full_dump(sk, cache); 00692 if (err < 0) 00693 return err; 00694 00695 NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n", 00696 cache, nl_cache_name(cache)); 00697 nl_cache_clear(cache); 00698 00699 return nl_cache_pickup(sk, cache); 00700 } 00701 00702 /** @} */ 00703 00704 /** 00705 * @name Utillities 00706 * @{ 00707 */ 00708 00709 /** 00710 * Mark all objects in a cache 00711 * @arg cache Cache to mark all objects in 00712 */ 00713 void nl_cache_mark_all(struct nl_cache *cache) 00714 { 00715 struct nl_object *obj; 00716 00717 NL_DBG(2, "Marking all objects in cache %p <%s>...\n", 00718 cache, nl_cache_name(cache)); 00719 00720 nl_list_for_each_entry(obj, &cache->c_items, ce_list) 00721 nl_object_mark(obj); 00722 } 00723 00724 /** @} */ 00725 00726 /** 00727 * @name Dumping 00728 * @{ 00729 */ 00730 00731 /** 00732 * Dump all elements of a cache. 00733 * @arg cache cache to dump 00734 * @arg params dumping parameters 00735 * 00736 * Dumps all elements of the \a cache to the file descriptor \a fd. 00737 */ 00738 void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params) 00739 { 00740 nl_cache_dump_filter(cache, params, NULL); 00741 } 00742 00743 /** 00744 * Dump all elements of a cache (filtered). 00745 * @arg cache cache to dump 00746 * @arg params dumping parameters (optional) 00747 * @arg filter filter object 00748 * 00749 * Dumps all elements of the \a cache to the file descriptor \a fd 00750 * given they match the given filter \a filter. 00751 */ 00752 void nl_cache_dump_filter(struct nl_cache *cache, 00753 struct nl_dump_params *params, 00754 struct nl_object *filter) 00755 { 00756 int type = params ? params->dp_type : NL_DUMP_DETAILS; 00757 struct nl_object_ops *ops; 00758 struct nl_object *obj; 00759 00760 NL_DBG(2, "Dumping cache %p <%s> filter %p\n", 00761 cache, nl_cache_name(cache), filter); 00762 00763 if (type > NL_DUMP_MAX || type < 0) 00764 BUG(); 00765 00766 if (cache->c_ops == NULL) 00767 BUG(); 00768 00769 ops = cache->c_ops->co_obj_ops; 00770 if (!ops->oo_dump[type]) 00771 return; 00772 00773 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 00774 if (filter && !nl_object_match_filter(obj, filter)) 00775 continue; 00776 00777 NL_DBG(4, "Dumping object %p...\n", obj); 00778 dump_from_ops(obj, params); 00779 } 00780 } 00781 00782 /** @} */ 00783 00784 /** 00785 * @name Iterators 00786 * @{ 00787 */ 00788 00789 /** 00790 * Call a callback on each element of the cache. 00791 * @arg cache cache to iterate on 00792 * @arg cb callback function 00793 * @arg arg argument passed to callback function 00794 * 00795 * Calls a callback function \a cb on each element of the \a cache. 00796 * The argument \a arg is passed on the callback function. 00797 */ 00798 void nl_cache_foreach(struct nl_cache *cache, 00799 void (*cb)(struct nl_object *, void *), void *arg) 00800 { 00801 nl_cache_foreach_filter(cache, NULL, cb, arg); 00802 } 00803 00804 /** 00805 * Call a callback on each element of the cache (filtered). 00806 * @arg cache cache to iterate on 00807 * @arg filter filter object 00808 * @arg cb callback function 00809 * @arg arg argument passed to callback function 00810 * 00811 * Calls a callback function \a cb on each element of the \a cache 00812 * that matches the \a filter. The argument \a arg is passed on 00813 * to the callback function. 00814 */ 00815 void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, 00816 void (*cb)(struct nl_object *, void *), void *arg) 00817 { 00818 struct nl_object *obj, *tmp; 00819 struct nl_object_ops *ops; 00820 00821 if (cache->c_ops == NULL) 00822 BUG(); 00823 00824 ops = cache->c_ops->co_obj_ops; 00825 00826 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) { 00827 if (filter) { 00828 int diff = nl_object_match_filter(obj, filter); 00829 00830 NL_DBG(3, "%p<->%p object difference: %x\n", 00831 obj, filter, diff); 00832 00833 if (!diff) 00834 continue; 00835 } 00836 00837 /* Caller may hold obj for a long time */ 00838 nl_object_get(obj); 00839 00840 cb(obj, arg); 00841 00842 nl_object_put(obj); 00843 } 00844 } 00845 00846 /** @} */ 00847 00848 /** @} */