1 /* 2 * lib/cache.c Caching Module 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2012 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup cache_mngt 14 * @defgroup cache Cache 15 * 16 * @code 17 * Cache Management | | Type Specific Cache Operations 18 * 19 * | | +----------------+ +------------+ 20 * | request update | | msg_parser | 21 * | | +----------------+ +------------+ 22 * +- - - - -^- - - - - - - -^- -|- - - - 23 * nl_cache_update: | | | | 24 * 1) --------- co_request_update ------+ | | 25 * | | | 26 * 2) destroy old cache +----------- pp_cb ---------|---+ 27 * | | | 28 * 3) ---------- nl_recvmsgs ----------+ +- cb_valid -+ 29 * +--------------+ | | | | 30 * | nl_cache_add |<-----+ + - - -v- -|- - - - - - - - - - - 31 * +--------------+ | | +-------------+ 32 * | nl_recvmsgs | 33 * | | +-----|-^-----+ 34 * +---v-|---+ 35 * | | | nl_recv | 36 * +---------+ 37 * | | Core Netlink 38 * @endcode 39 * 40 * Related sections in the development guide: 41 * - @core_doc{core_cache, Caching System} 42 * 43 * @{ 44 * 45 * Header 46 * ------ 47 * ~~~~{.c} 48 * #include <netlink/cache.h> 49 * ~~~~ 50 */ 51 52 #include <netlink-private/netlink.h> 53 #include <netlink/netlink.h> 54 #include <netlink/cache.h> 55 #include <netlink/object.h> 56 #include <netlink/hashtable.h> 57 #include <netlink/utils.h> 58 59 /** 60 * @name Access Functions 61 * @{ 62 */ 63 64 /** 65 * Return the number of items in the cache 66 * @arg cache cache handle 67 */ 68 int nl_cache_nitems(struct nl_cache *cache) 69 { 70 return cache->c_nitems; 71 } 72 73 /** 74 * Return the number of items matching a filter in the cache 75 * @arg cache Cache object. 76 * @arg filter Filter object. 77 */ 78 int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter) 79 { 80 struct nl_object *obj; 81 int nitems = 0; 82 83 if (cache->c_ops == NULL) 84 BUG(); 85 86 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 87 if (filter && !nl_object_match_filter(obj, filter)) 88 continue; 89 90 nitems++; 91 } 92 93 return nitems; 94 } 95 96 /** 97 * Returns \b true if the cache is empty. 98 * @arg cache Cache to check 99 * @return \a true if the cache is empty, otherwise \b false is returned. 100 */ 101 int nl_cache_is_empty(struct nl_cache *cache) 102 { 103 return nl_list_empty(&cache->c_items); 104 } 105 106 /** 107 * Return the operations set of the cache 108 * @arg cache cache handle 109 */ 110 struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache) 111 { 112 return cache->c_ops; 113 } 114 115 /** 116 * Return the first element in the cache 117 * @arg cache cache handle 118 */ 119 struct nl_object *nl_cache_get_first(struct nl_cache *cache) 120 { 121 if (nl_list_empty(&cache->c_items)) 122 return NULL; 123 124 return nl_list_entry(cache->c_items.next, 125 struct nl_object, ce_list); 126 } 127 128 /** 129 * Return the last element in the cache 130 * @arg cache cache handle 131 */ 132 struct nl_object *nl_cache_get_last(struct nl_cache *cache) 133 { 134 if (nl_list_empty(&cache->c_items)) 135 return NULL; 136 137 return nl_list_entry(cache->c_items.prev, 138 struct nl_object, ce_list); 139 } 140 141 /** 142 * Return the next element in the cache 143 * @arg obj current object 144 */ 145 struct nl_object *nl_cache_get_next(struct nl_object *obj) 146 { 147 if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list)) 148 return NULL; 149 else 150 return nl_list_entry(obj->ce_list.next, 151 struct nl_object, ce_list); 152 } 153 154 /** 155 * Return the previous element in the cache 156 * @arg obj current object 157 */ 158 struct nl_object *nl_cache_get_prev(struct nl_object *obj) 159 { 160 if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list)) 161 return NULL; 162 else 163 return nl_list_entry(obj->ce_list.prev, 164 struct nl_object, ce_list); 165 } 166 167 /** @} */ 168 169 /** 170 * @name Cache Allocation/Deletion 171 * @{ 172 */ 173 174 /** 175 * Allocate new cache 176 * @arg ops Cache operations 177 * 178 * Allocate and initialize a new cache based on the cache operations 179 * provided. 180 * 181 * @return Allocated cache or NULL if allocation failed. 182 */ 183 struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops) 184 { 185 struct nl_cache *cache; 186 187 cache = calloc(1, sizeof(*cache)); 188 if (!cache) 189 return NULL; 190 191 nl_init_list_head(&cache->c_items); 192 cache->c_ops = ops; 193 cache->c_flags |= ops->co_flags; 194 cache->c_refcnt = 1; 195 196 /* 197 * If object type provides a hash keygen 198 * functions, allocate a hash table for the 199 * cache objects for faster lookups 200 */ 201 if (ops->co_obj_ops->oo_keygen) { 202 int hashtable_size; 203 204 if (ops->co_hash_size) 205 hashtable_size = ops->co_hash_size; 206 else 207 hashtable_size = NL_MAX_HASH_ENTRIES; 208 209 cache->hashtable = nl_hash_table_alloc(hashtable_size); 210 } 211 212 NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache)); 213 214 return cache; 215 } 216 217 /** 218 * Allocate new cache and fill it 219 * @arg ops Cache operations 220 * @arg sock Netlink socket 221 * @arg result Result pointer 222 * 223 * Allocate new cache and fill it. Equivalent to calling: 224 * @code 225 * cache = nl_cache_alloc(ops); 226 * nl_cache_refill(sock, cache); 227 * @endcode 228 * 229 * @see nl_cache_alloc 230 * 231 * @return 0 on success or a negative error code. 232 */ 233 int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, 234 struct nl_cache **result) 235 { 236 struct nl_cache *cache; 237 int err; 238 239 if (!(cache = nl_cache_alloc(ops))) 240 return -NLE_NOMEM; 241 242 if (sock && (err = nl_cache_refill(sock, cache)) < 0) { 243 nl_cache_free(cache); 244 return err; 245 } 246 247 *result = cache; 248 return 0; 249 } 250 251 /** 252 * Allocate new cache based on type name 253 * @arg kind Name of cache type 254 * @arg result Result pointer 255 * 256 * Lookup cache ops via nl_cache_ops_lookup() and allocate the cache 257 * by calling nl_cache_alloc(). Stores the allocated cache in the 258 * result pointer provided. 259 * 260 * @see nl_cache_alloc 261 * 262 * @return 0 on success or a negative error code. 263 */ 264 int nl_cache_alloc_name(const char *kind, struct nl_cache **result) 265 { 266 struct nl_cache_ops *ops; 267 struct nl_cache *cache; 268 269 ops = nl_cache_ops_lookup_safe(kind); 270 if (!ops) 271 return -NLE_NOCACHE; 272 273 cache = nl_cache_alloc(ops); 274 nl_cache_ops_put(ops); 275 if (!cache) 276 return -NLE_NOMEM; 277 278 *result = cache; 279 return 0; 280 } 281 282 /** 283 * Allocate new cache containing a subset of an existing cache 284 * @arg orig Original cache to base new cache on 285 * @arg filter Filter defining the subset to be filled into the new cache 286 * 287 * Allocates a new cache matching the type of the cache specified by 288 * \p orig. Iterates over the \p orig cache applying the specified 289 * \p filter and copies all objects that match to the new cache. 290 * 291 * The copied objects are clones but do not contain a reference to each 292 * other. Later modifications to objects in the original cache will 293 * not affect objects in the new cache. 294 * 295 * @return A newly allocated cache or NULL. 296 */ 297 struct nl_cache *nl_cache_subset(struct nl_cache *orig, 298 struct nl_object *filter) 299 { 300 struct nl_cache *cache; 301 struct nl_object *obj; 302 303 if (!filter) 304 BUG(); 305 306 cache = nl_cache_alloc(orig->c_ops); 307 if (!cache) 308 return NULL; 309 310 NL_DBG(2, "Filling subset of cache %p <%s> with filter %p into %p\n", 311 orig, nl_cache_name(orig), filter, cache); 312 313 nl_list_for_each_entry(obj, &orig->c_items, ce_list) { 314 if (!nl_object_match_filter(obj, filter)) 315 continue; 316 317 nl_cache_add(cache, obj); 318 } 319 320 return cache; 321 } 322 323 /** 324 * Allocate new cache and copy the contents of an existing cache 325 * @arg cache Original cache to base new cache on 326 * 327 * Allocates a new cache matching the type of the cache specified by 328 * \p cache. Iterates over the \p cache cache and copies all objects 329 * to the new cache. 330 * 331 * The copied objects are clones but do not contain a reference to each 332 * other. Later modifications to objects in the original cache will 333 * not affect objects in the new cache. 334 * 335 * @return A newly allocated cache or NULL. 336 */ 337 struct nl_cache *nl_cache_clone(struct nl_cache *cache) 338 { 339 struct nl_cache_ops *ops = nl_cache_get_ops(cache); 340 struct nl_cache *clone; 341 struct nl_object *obj; 342 343 clone = nl_cache_alloc(ops); 344 if (!clone) 345 return NULL; 346 347 NL_DBG(2, "Cloning %p into %p\n", cache, clone); 348 349 nl_list_for_each_entry(obj, &cache->c_items, ce_list) 350 nl_cache_add(clone, obj); 351 352 return clone; 353 } 354 355 /** 356 * Remove all objects of a cache. 357 * @arg cache Cache to clear 358 * 359 * The objects are unliked/removed from the cache by calling 360 * nl_cache_remove() on each object in the cache. If any of the objects 361 * to not contain any further references to them, those objects will 362 * be freed. 363 * 364 * Unlike with nl_cache_free(), the cache is not freed just emptied. 365 */ 366 void nl_cache_clear(struct nl_cache *cache) 367 { 368 struct nl_object *obj, *tmp; 369 370 NL_DBG(2, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache)); 371 372 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) 373 nl_cache_remove(obj); 374 } 375 376 static void __nl_cache_free(struct nl_cache *cache) 377 { 378 nl_cache_clear(cache); 379 380 if (cache->hashtable) 381 nl_hash_table_free(cache->hashtable); 382 383 NL_DBG(2, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache)); 384 free(cache); 385 } 386 387 /** 388 * Increase reference counter of cache 389 * @arg cache Cache 390 */ 391 void nl_cache_get(struct nl_cache *cache) 392 { 393 cache->c_refcnt++; 394 395 NL_DBG(3, "Incremented cache %p <%s> reference count to %d\n", 396 cache, nl_cache_name(cache), cache->c_refcnt); 397 } 398 399 /** 400 * Free a cache. 401 * @arg cache Cache to free. 402 * 403 * Calls nl_cache_clear() to remove all objects associated with the 404 * cache and frees the cache afterwards. 405 * 406 * @see nl_cache_clear() 407 */ 408 void nl_cache_free(struct nl_cache *cache) 409 { 410 if (!cache) 411 return; 412 413 cache->c_refcnt--; 414 415 NL_DBG(3, "Decremented cache %p <%s> reference count, %d remaining\n", 416 cache, nl_cache_name(cache), cache->c_refcnt); 417 418 if (cache->c_refcnt <= 0) 419 __nl_cache_free(cache); 420 } 421 422 void nl_cache_put(struct nl_cache *cache) 423 { 424 return nl_cache_free(cache); 425 } 426 427 /** @} */ 428 429 /** 430 * @name Cache Modifications 431 * @{ 432 */ 433 434 static int __cache_add(struct nl_cache *cache, struct nl_object *obj) 435 { 436 int ret; 437 438 obj->ce_cache = cache; 439 440 if (cache->hashtable) { 441 ret = nl_hash_table_add(cache->hashtable, obj); 442 if (ret < 0) { 443 obj->ce_cache = NULL; 444 return ret; 445 } 446 } 447 448 nl_list_add_tail(&obj->ce_list, &cache->c_items); 449 cache->c_nitems++; 450 451 NL_DBG(3, "Added object %p to cache %p <%s>, nitems %d\n", 452 obj, cache, nl_cache_name(cache), cache->c_nitems); 453 454 return 0; 455 } 456 457 /** 458 * Add object to cache. 459 * @arg cache Cache 460 * @arg obj Object to be added to the cache 461 * 462 * Adds the object \p obj to the specified \p cache. In case the object 463 * is already associated with another cache, the object is cloned before 464 * adding it to the cache. In this case, the sole reference to the object 465 * will be the one of the cache. Therefore clearing/freeing the cache 466 * will result in the object being freed again. 467 * 468 * If the object has not been associated with a cache yet, the reference 469 * counter of the object is incremented to account for the additional 470 * reference. 471 * 472 * The type of the object and cache must match, otherwise an error is 473 * returned (-NLE_OBJ_MISMATCH). 474 * 475 * @see nl_cache_move() 476 * 477 * @return 0 or a negative error code. 478 */ 479 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) 480 { 481 struct nl_object *new; 482 int ret = 0; 483 484 if (cache->c_ops->co_obj_ops != obj->ce_ops) 485 return -NLE_OBJ_MISMATCH; 486 487 if (!nl_list_empty(&obj->ce_list)) { 488 NL_DBG(3, "Object %p already in cache, cloning new object\n", obj); 489 490 new = nl_object_clone(obj); 491 if (!new) 492 return -NLE_NOMEM; 493 } else { 494 nl_object_get(obj); 495 new = obj; 496 } 497 498 ret = __cache_add(cache, new); 499 if (ret < 0) 500 nl_object_put(new); 501 502 return ret; 503 } 504 505 /** 506 * Move object from one cache to another 507 * @arg cache Cache to move object to. 508 * @arg obj Object subject to be moved 509 * 510 * Removes the the specified object \p obj from its associated cache 511 * and moves it to another cache. 512 * 513 * If the object is not associated with a cache, the function behaves 514 * just like nl_cache_add(). 515 * 516 * The type of the object and cache must match, otherwise an error is 517 * returned (-NLE_OBJ_MISMATCH). 518 * 519 * @see nl_cache_add() 520 * 521 * @return 0 on success or a negative error code. 522 */ 523 int nl_cache_move(struct nl_cache *cache, struct nl_object *obj) 524 { 525 if (cache->c_ops->co_obj_ops != obj->ce_ops) 526 return -NLE_OBJ_MISMATCH; 527 528 NL_DBG(3, "Moving object %p from cache %p to cache %p\n", 529 obj, obj->ce_cache, cache); 530 531 /* Acquire reference, if already in a cache this will be 532 * reverted during removal */ 533 nl_object_get(obj); 534 535 if (!nl_list_empty(&obj->ce_list)) 536 nl_cache_remove(obj); 537 538 return __cache_add(cache, obj); 539 } 540 541 /** 542 * Remove object from cache. 543 * @arg obj Object to remove from cache 544 * 545 * Removes the object \c obj from the cache it is associated with. The 546 * reference counter of the object will be decremented. If the reference 547 * to the object was the only one remaining, the object will be freed. 548 * 549 * If no cache is associated with the object, this function is a NOP. 550 */ 551 void nl_cache_remove(struct nl_object *obj) 552 { 553 int ret; 554 struct nl_cache *cache = obj->ce_cache; 555 556 if (cache == NULL) 557 return; 558 559 if (cache->hashtable) { 560 ret = nl_hash_table_del(cache->hashtable, obj); 561 if (ret < 0) 562 NL_DBG(2, "Failed to delete %p from cache %p <%s>.\n", 563 obj, cache, nl_cache_name(cache)); 564 } 565 566 nl_list_del(&obj->ce_list); 567 obj->ce_cache = NULL; 568 nl_object_put(obj); 569 cache->c_nitems--; 570 571 NL_DBG(2, "Deleted object %p from cache %p <%s>.\n", 572 obj, cache, nl_cache_name(cache)); 573 } 574 575 /** @} */ 576 577 /** 578 * @name Synchronization 579 * @{ 580 */ 581 582 /** 583 * Set synchronization arg1 of cache 584 * @arg cache Cache 585 * @arg arg argument 586 * 587 * Synchronization arguments are used to specify filters when 588 * requesting dumps from the kernel. 589 */ 590 void nl_cache_set_arg1(struct nl_cache *cache, int arg) 591 { 592 cache->c_iarg1 = arg; 593 } 594 595 /** 596 * Set synchronization arg2 of cache 597 * @arg cache Cache 598 * @arg arg argument 599 * 600 * Synchronization arguments are used to specify filters when 601 * requesting dumps from the kernel. 602 */ 603 void nl_cache_set_arg2(struct nl_cache *cache, int arg) 604 { 605 cache->c_iarg2 = arg; 606 } 607 608 /** 609 * Set cache flags 610 * @arg cache Cache 611 * @arg flags Flags 612 */ 613 void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags) 614 { 615 cache->c_flags |= flags; 616 } 617 618 /** 619 * Invoke the request-update operation 620 * @arg sk Netlink socket. 621 * @arg cache Cache 622 * 623 * This function causes the \e request-update function of the cache 624 * operations to be invoked. This usually causes a dump request to 625 * be sent over the netlink socket which triggers the kernel to dump 626 * all objects of a specific type to be dumped onto the netlink 627 * socket for pickup. 628 * 629 * The behaviour of this function depends on the implemenation of 630 * the \e request_update function of each individual type of cache. 631 * 632 * This function will not have any effects on the cache (unless the 633 * request_update implementation of the cache operations does so). 634 * 635 * Use nl_cache_pickup() to pick-up (read) the objects from the socket 636 * and fill them into the cache. 637 * 638 * @see nl_cache_pickup(), nl_cache_resync() 639 * 640 * @return 0 on success or a negative error code. 641 */ 642 static int nl_cache_request_full_dump(struct nl_sock *sk, 643 struct nl_cache *cache) 644 { 645 if (sk->s_proto != cache->c_ops->co_protocol) 646 return -NLE_PROTO_MISMATCH; 647 648 if (cache->c_ops->co_request_update == NULL) 649 return -NLE_OPNOTSUPP; 650 651 NL_DBG(2, "Requesting update from kernel for cache %p <%s>\n", 652 cache, nl_cache_name(cache)); 653 654 return cache->c_ops->co_request_update(cache, sk); 655 } 656 657 /** @cond SKIP */ 658 struct update_xdata { 659 struct nl_cache_ops *ops; 660 struct nl_parser_param *params; 661 }; 662 663 static int update_msg_parser(struct nl_msg *msg, void *arg) 664 { 665 struct update_xdata *x = arg; 666 int ret = 0; 667 668 ret = nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params); 669 if (ret == -NLE_EXIST) 670 return NL_SKIP; 671 else 672 return ret; 673 } 674 /** @endcond */ 675 676 /** 677 * Pick-up a netlink request-update with your own parser 678 * @arg sk Netlink socket 679 * @arg cache Cache 680 * @arg param Parser parameters 681 */ 682 static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache, 683 struct nl_parser_param *param) 684 { 685 int err; 686 struct nl_cb *cb; 687 struct update_xdata x = { 688 .ops = cache->c_ops, 689 .params = param, 690 }; 691 692 NL_DBG(2, "Picking up answer for cache %p <%s>\n", 693 cache, nl_cache_name(cache)); 694 695 cb = nl_cb_clone(sk->s_cb); 696 if (cb == NULL) 697 return -NLE_NOMEM; 698 699 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x); 700 701 err = nl_recvmsgs(sk, cb); 702 if (err < 0) 703 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned %d: %s\n", 704 cache, nl_cache_name(cache), err, nl_geterror(err)); 705 706 nl_cb_put(cb); 707 708 return err; 709 } 710 711 static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) 712 { 713 struct nl_cache *cache = (struct nl_cache *)p->pp_arg; 714 struct nl_object *old; 715 716 old = nl_cache_search(cache, c); 717 if (old) { 718 if (nl_object_update(old, c) == 0) { 719 nl_object_put(old); 720 return 0; 721 } 722 723 nl_cache_remove(old); 724 nl_object_put(old); 725 } 726 727 return nl_cache_add(cache, c); 728 } 729 730 /** 731 * Pickup a netlink dump response and put it into a cache. 732 * @arg sk Netlink socket. 733 * @arg cache Cache to put items into. 734 * 735 * Waits for netlink messages to arrive, parses them and puts them into 736 * the specified cache. If an old object with same key attributes is 737 * present in the cache, it is replaced with the new object. 738 * If the old object type supports an update operation, an update is 739 * attempted before a replace. 740 * 741 * @return 0 on success or a negative error code. 742 */ 743 int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) 744 { 745 struct nl_parser_param p = { 746 .pp_cb = pickup_cb, 747 .pp_arg = cache, 748 }; 749 750 if (sk->s_proto != cache->c_ops->co_protocol) 751 return -NLE_PROTO_MISMATCH; 752 753 return __cache_pickup(sk, cache, &p); 754 } 755 756 static int cache_include(struct nl_cache *cache, struct nl_object *obj, 757 struct nl_msgtype *type, change_func_t cb, void *data) 758 { 759 struct nl_object *old; 760 761 switch (type->mt_act) { 762 case NL_ACT_NEW: 763 case NL_ACT_DEL: 764 old = nl_cache_search(cache, obj); 765 if (old) { 766 /* 767 * Some objects types might support merging the new 768 * object with the old existing cache object. 769 * Handle them first. 770 */ 771 if (nl_object_update(old, obj) == 0) { 772 if (cb) 773 cb(cache, old, NL_ACT_CHANGE, data); 774 nl_object_put(old); 775 return 0; 776 } 777 778 nl_cache_remove(old); 779 if (type->mt_act == NL_ACT_DEL) { 780 if (cb) 781 cb(cache, old, NL_ACT_DEL, data); 782 nl_object_put(old); 783 } 784 } 785 786 if (type->mt_act == NL_ACT_NEW) { 787 nl_cache_move(cache, obj); 788 if (old == NULL && cb) 789 cb(cache, obj, NL_ACT_NEW, data); 790 else if (old) { 791 if (nl_object_diff(old, obj) && cb) 792 cb(cache, obj, NL_ACT_CHANGE, data); 793 794 nl_object_put(old); 795 } 796 } 797 break; 798 default: 799 NL_DBG(2, "Unknown action associated to object %p\n", obj); 800 return 0; 801 } 802 803 return 0; 804 } 805 806 int nl_cache_include(struct nl_cache *cache, struct nl_object *obj, 807 change_func_t change_cb, void *data) 808 { 809 struct nl_cache_ops *ops = cache->c_ops; 810 int i; 811 812 if (ops->co_obj_ops != obj->ce_ops) 813 return -NLE_OBJ_MISMATCH; 814 815 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) 816 if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype) 817 return cache_include(cache, obj, &ops->co_msgtypes[i], 818 change_cb, data); 819 820 NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n", 821 obj, cache, nl_cache_name(cache)); 822 823 return -NLE_MSGTYPE_NOSUPPORT; 824 } 825 826 static int resync_cb(struct nl_object *c, struct nl_parser_param *p) 827 { 828 struct nl_cache_assoc *ca = p->pp_arg; 829 830 return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data); 831 } 832 833 int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache, 834 change_func_t change_cb, void *data) 835 { 836 struct nl_object *obj, *next; 837 struct nl_af_group *grp; 838 struct nl_cache_assoc ca = { 839 .ca_cache = cache, 840 .ca_change = change_cb, 841 .ca_change_data = data, 842 }; 843 struct nl_parser_param p = { 844 .pp_cb = resync_cb, 845 .pp_arg = &ca, 846 }; 847 int err; 848 849 if (sk->s_proto != cache->c_ops->co_protocol) 850 return -NLE_PROTO_MISMATCH; 851 852 NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache)); 853 854 /* Mark all objects so we can see if some of them are obsolete */ 855 nl_cache_mark_all(cache); 856 857 grp = cache->c_ops->co_groups; 858 do { 859 if (grp && grp->ag_group && 860 (cache->c_flags & NL_CACHE_AF_ITER)) 861 nl_cache_set_arg1(cache, grp->ag_family); 862 863 restart: 864 err = nl_cache_request_full_dump(sk, cache); 865 if (err < 0) 866 goto errout; 867 868 err = __cache_pickup(sk, cache, &p); 869 if (err == -NLE_DUMP_INTR) 870 goto restart; 871 else if (err < 0) 872 goto errout; 873 874 if (grp) 875 grp++; 876 } while (grp && grp->ag_group && 877 (cache->c_flags & NL_CACHE_AF_ITER)); 878 879 nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) { 880 if (nl_object_is_marked(obj)) { 881 nl_object_get(obj); 882 nl_cache_remove(obj); 883 if (change_cb) 884 change_cb(cache, obj, NL_ACT_DEL, data); 885 nl_object_put(obj); 886 } 887 } 888 889 NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache)); 890 891 err = 0; 892 errout: 893 return err; 894 } 895 896 /** @} */ 897 898 /** 899 * @name Parsing 900 * @{ 901 */ 902 903 /** @cond SKIP */ 904 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, 905 struct nlmsghdr *nlh, struct nl_parser_param *params) 906 { 907 int i, err; 908 909 if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) 910 return -NLE_MSG_TOOSHORT; 911 912 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) { 913 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) { 914 err = ops->co_msg_parser(ops, who, nlh, params); 915 if (err != -NLE_OPNOTSUPP) 916 goto errout; 917 } 918 } 919 920 921 err = -NLE_MSGTYPE_NOSUPPORT; 922 errout: 923 return err; 924 } 925 /** @endcond */ 926 927 /** 928 * Parse a netlink message and add it to the cache. 929 * @arg cache cache to add element to 930 * @arg msg netlink message 931 * 932 * Parses a netlink message by calling the cache specific message parser 933 * and adds the new element to the cache. If an old object with same key 934 * attributes is present in the cache, it is replaced with the new object. 935 * If the old object type supports an update operation, an update is 936 * attempted before a replace. 937 * 938 * @return 0 or a negative error code. 939 */ 940 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) 941 { 942 struct nl_parser_param p = { 943 .pp_cb = pickup_cb, 944 .pp_arg = cache, 945 }; 946 947 return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p); 948 } 949 950 /** 951 * (Re)fill a cache with the contents in the kernel. 952 * @arg sk Netlink socket. 953 * @arg cache cache to update 954 * 955 * Clears the specified cache and fills it with the current state in 956 * the kernel. 957 * 958 * @return 0 or a negative error code. 959 */ 960 int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) 961 { 962 struct nl_af_group *grp; 963 int err; 964 965 if (sk->s_proto != cache->c_ops->co_protocol) 966 return -NLE_PROTO_MISMATCH; 967 968 nl_cache_clear(cache); 969 grp = cache->c_ops->co_groups; 970 do { 971 if (grp && grp->ag_group && 972 (cache->c_flags & NL_CACHE_AF_ITER)) 973 nl_cache_set_arg1(cache, grp->ag_family); 974 975 restart: 976 err = nl_cache_request_full_dump(sk, cache); 977 if (err < 0) 978 return err; 979 980 NL_DBG(2, "Updating cache %p <%s> for family %u, request sent, waiting for reply\n", 981 cache, nl_cache_name(cache), grp ? grp->ag_family : AF_UNSPEC); 982 983 err = nl_cache_pickup(sk, cache); 984 if (err == -NLE_DUMP_INTR) { 985 NL_DBG(2, "Dump interrupted, restarting!\n"); 986 goto restart; 987 } else if (err < 0) 988 break; 989 990 if (grp) 991 grp++; 992 } while (grp && grp->ag_group && 993 (cache->c_flags & NL_CACHE_AF_ITER)); 994 995 return err; 996 } 997 998 /** @} */ 999 1000 /** 1001 * @name Utillities 1002 * @{ 1003 */ 1004 static struct nl_object *__cache_fast_lookup(struct nl_cache *cache, 1005 struct nl_object *needle) 1006 { 1007 struct nl_object *obj; 1008 1009 obj = nl_hash_table_lookup(cache->hashtable, needle); 1010 if (obj) { 1011 nl_object_get(obj); 1012 return obj; 1013 } 1014 1015 return NULL; 1016 } 1017 1018 /** 1019 * Search object in cache 1020 * @arg cache Cache 1021 * @arg needle Object to look for. 1022 * 1023 * Searches the cache for an object which matches the object \p needle. 1024 * The function nl_object_identical() is used to determine if the 1025 * objects match. If a matching object is found, the reference counter 1026 * is incremented and the object is returned. 1027 * 1028 * Therefore, if an object is returned, the reference to the object 1029 * must be returned by calling nl_object_put() after usage. 1030 * 1031 * @return Reference to object or NULL if not found. 1032 */ 1033 struct nl_object *nl_cache_search(struct nl_cache *cache, 1034 struct nl_object *needle) 1035 { 1036 struct nl_object *obj; 1037 1038 if (cache->hashtable) 1039 return __cache_fast_lookup(cache, needle); 1040 1041 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 1042 if (nl_object_identical(obj, needle)) { 1043 nl_object_get(obj); 1044 return obj; 1045 } 1046 } 1047 1048 return NULL; 1049 } 1050 1051 /** 1052 * Find object in cache 1053 * @arg cache Cache 1054 * @arg filter object acting as a filter 1055 * 1056 * Searches the cache for an object which matches the object filter. 1057 * If the filter attributes matches the object type id attributes, 1058 * and the cache supports hash lookups, a faster hashtable lookup 1059 * is used to return the object. Else, function nl_object_match_filter() is 1060 * used to determine if the objects match. If a matching object is 1061 * found, the reference counter is incremented and the object is returned. 1062 * 1063 * Therefore, if an object is returned, the reference to the object 1064 * must be returned by calling nl_object_put() after usage. 1065 * 1066 * @return Reference to object or NULL if not found. 1067 */ 1068 struct nl_object *nl_cache_find(struct nl_cache *cache, 1069 struct nl_object *filter) 1070 { 1071 struct nl_object *obj; 1072 1073 if (cache->c_ops == NULL) 1074 BUG(); 1075 1076 if ((nl_object_get_id_attrs(filter) == filter->ce_mask) 1077 && cache->hashtable) 1078 return __cache_fast_lookup(cache, filter); 1079 1080 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 1081 if (nl_object_match_filter(obj, filter)) { 1082 nl_object_get(obj); 1083 return obj; 1084 } 1085 } 1086 1087 return NULL; 1088 } 1089 1090 /** 1091 * Mark all objects of a cache 1092 * @arg cache Cache 1093 * 1094 * Marks all objects of a cache by calling nl_object_mark() on each 1095 * object associated with the cache. 1096 */ 1097 void nl_cache_mark_all(struct nl_cache *cache) 1098 { 1099 struct nl_object *obj; 1100 1101 NL_DBG(2, "Marking all objects in cache %p <%s>\n", 1102 cache, nl_cache_name(cache)); 1103 1104 nl_list_for_each_entry(obj, &cache->c_items, ce_list) 1105 nl_object_mark(obj); 1106 } 1107 1108 /** @} */ 1109 1110 /** 1111 * @name Dumping 1112 * @{ 1113 */ 1114 1115 /** 1116 * Dump all elements of a cache. 1117 * @arg cache cache to dump 1118 * @arg params dumping parameters 1119 * 1120 * Dumps all elements of the \a cache to the file descriptor \a fd. 1121 */ 1122 void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params) 1123 { 1124 nl_cache_dump_filter(cache, params, NULL); 1125 } 1126 1127 /** 1128 * Dump all elements of a cache (filtered). 1129 * @arg cache cache to dump 1130 * @arg params dumping parameters (optional) 1131 * @arg filter filter object 1132 * 1133 * Dumps all elements of the \a cache to the file descriptor \a fd 1134 * given they match the given filter \a filter. 1135 */ 1136 void nl_cache_dump_filter(struct nl_cache *cache, 1137 struct nl_dump_params *params, 1138 struct nl_object *filter) 1139 { 1140 int type = params ? params->dp_type : NL_DUMP_DETAILS; 1141 struct nl_object_ops *ops; 1142 struct nl_object *obj; 1143 1144 NL_DBG(2, "Dumping cache %p <%s> with filter %p\n", 1145 cache, nl_cache_name(cache), filter); 1146 1147 if (type > NL_DUMP_MAX || type < 0) 1148 BUG(); 1149 1150 if (cache->c_ops == NULL) 1151 BUG(); 1152 1153 ops = cache->c_ops->co_obj_ops; 1154 if (!ops->oo_dump[type]) 1155 return; 1156 1157 if (params && params->dp_buf) 1158 memset(params->dp_buf, 0, params->dp_buflen); 1159 1160 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 1161 if (filter && !nl_object_match_filter(obj, filter)) 1162 continue; 1163 1164 NL_DBG(4, "Dumping object %p...\n", obj); 1165 dump_from_ops(obj, params); 1166 } 1167 } 1168 1169 /** @} */ 1170 1171 /** 1172 * @name Iterators 1173 * @{ 1174 */ 1175 1176 /** 1177 * Call a callback on each element of the cache. 1178 * @arg cache cache to iterate on 1179 * @arg cb callback function 1180 * @arg arg argument passed to callback function 1181 * 1182 * Calls a callback function \a cb on each element of the \a cache. 1183 * The argument \a arg is passed on the callback function. 1184 */ 1185 void nl_cache_foreach(struct nl_cache *cache, 1186 void (*cb)(struct nl_object *, void *), void *arg) 1187 { 1188 nl_cache_foreach_filter(cache, NULL, cb, arg); 1189 } 1190 1191 /** 1192 * Call a callback on each element of the cache (filtered). 1193 * @arg cache cache to iterate on 1194 * @arg filter filter object 1195 * @arg cb callback function 1196 * @arg arg argument passed to callback function 1197 * 1198 * Calls a callback function \a cb on each element of the \a cache 1199 * that matches the \a filter. The argument \a arg is passed on 1200 * to the callback function. 1201 */ 1202 void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, 1203 void (*cb)(struct nl_object *, void *), void *arg) 1204 { 1205 struct nl_object *obj, *tmp; 1206 1207 if (cache->c_ops == NULL) 1208 BUG(); 1209 1210 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) { 1211 if (filter) { 1212 int diff = nl_object_match_filter(obj, filter); 1213 1214 NL_DBG(3, "%p<->%p object difference: %x\n", 1215 obj, filter, diff); 1216 1217 if (!diff) 1218 continue; 1219 } 1220 1221 /* Caller may hold obj for a long time */ 1222 nl_object_get(obj); 1223 1224 cb(obj, arg); 1225 1226 nl_object_put(obj); 1227 } 1228 } 1229 1230 /** @} */ 1231 1232 /** @} */ 1233