libnl
3.2.3
|
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 /** @} */