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-2008 Thomas Graf <tgraf@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 * @{ 41 */ 42 43#include <netlink-local.h> 44#include <netlink/netlink.h> 45#include <netlink/cache.h> 46#include <netlink/object.h> 47#include <netlink/utils.h> 48 49/** 50 * @name Access Functions 51 * @{ 52 */ 53 54/** 55 * Return the number of items in the cache 56 * @arg cache cache handle 57 */ 58int nl_cache_nitems(struct nl_cache *cache) 59{ 60 return cache->c_nitems; 61} 62 63/** 64 * Return the number of items matching a filter in the cache 65 * @arg cache Cache object. 66 * @arg filter Filter object. 67 */ 68int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter) 69{ 70 struct nl_object_ops *ops; 71 struct nl_object *obj; 72 int nitems = 0; 73 74 if (cache->c_ops == NULL) 75 BUG(); 76 77 ops = cache->c_ops->co_obj_ops; 78 79 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 80 if (filter && !nl_object_match_filter(obj, filter)) 81 continue; 82 83 nitems++; 84 } 85 86 return nitems; 87} 88 89/** 90 * Returns \b true if the cache is empty. 91 * @arg cache Cache to check 92 * @return \a true if the cache is empty, otherwise \b false is returned. 93 */ 94int nl_cache_is_empty(struct nl_cache *cache) 95{ 96 return nl_list_empty(&cache->c_items); 97} 98 99/** 100 * Return the operations set of the cache 101 * @arg cache cache handle 102 */ 103struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache) 104{ 105 return cache->c_ops; 106} 107 108/** 109 * Return the first element in the cache 110 * @arg cache cache handle 111 */ 112struct nl_object *nl_cache_get_first(struct nl_cache *cache) 113{ 114 if (nl_list_empty(&cache->c_items)) 115 return NULL; 116 117 return nl_list_entry(cache->c_items.next, 118 struct nl_object, ce_list); 119} 120 121/** 122 * Return the last element in the cache 123 * @arg cache cache handle 124 */ 125struct nl_object *nl_cache_get_last(struct nl_cache *cache) 126{ 127 if (nl_list_empty(&cache->c_items)) 128 return NULL; 129 130 return nl_list_entry(cache->c_items.prev, 131 struct nl_object, ce_list); 132} 133 134/** 135 * Return the next element in the cache 136 * @arg obj current object 137 */ 138struct nl_object *nl_cache_get_next(struct nl_object *obj) 139{ 140 if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list)) 141 return NULL; 142 else 143 return nl_list_entry(obj->ce_list.next, 144 struct nl_object, ce_list); 145} 146 147/** 148 * Return the previous element in the cache 149 * @arg obj current object 150 */ 151struct nl_object *nl_cache_get_prev(struct nl_object *obj) 152{ 153 if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list)) 154 return NULL; 155 else 156 return nl_list_entry(obj->ce_list.prev, 157 struct nl_object, ce_list); 158} 159 160/** @} */ 161 162/** 163 * @name Cache Creation/Deletion 164 * @{ 165 */ 166 167/** 168 * Allocate an empty cache 169 * @arg ops cache operations to base the cache on 170 * 171 * @return A newly allocated and initialized cache. 172 */ 173struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops) 174{ 175 struct nl_cache *cache; 176 177 cache = calloc(1, sizeof(*cache)); 178 if (!cache) 179 return NULL; 180 181 nl_init_list_head(&cache->c_items); 182 cache->c_ops = ops; 183 184 NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache)); 185 186 return cache; 187} 188 189int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, 190 struct nl_cache **result) 191{ 192 struct nl_cache *cache; 193 int err; 194 195 if (!(cache = nl_cache_alloc(ops))) 196 return -NLE_NOMEM; 197 198 if (sock && (err = nl_cache_refill(sock, cache)) < 0) { 199 nl_cache_free(cache); 200 return err; 201 } 202 203 *result = cache; 204 return 0; 205} 206 207/** 208 * Allocate an empty cache based on type name 209 * @arg kind Name of cache type 210 * @return A newly allocated and initialized cache. 211 */ 212int nl_cache_alloc_name(const char *kind, struct nl_cache **result) 213{ 214 struct nl_cache_ops *ops; 215 struct nl_cache *cache; 216 217 ops = nl_cache_ops_lookup(kind); 218 if (!ops) 219 return -NLE_NOCACHE; 220 221 if (!(cache = nl_cache_alloc(ops))) 222 return -NLE_NOMEM; 223 224 *result = cache; 225 return 0; 226} 227 228/** 229 * Allocate a new cache containing a subset of a cache 230 * @arg orig Original cache to be based on 231 * @arg filter Filter defining the subset to be filled into new cache 232 * @return A newly allocated cache or NULL. 233 */ 234struct nl_cache *nl_cache_subset(struct nl_cache *orig, 235 struct nl_object *filter) 236{ 237 struct nl_cache *cache; 238 struct nl_object_ops *ops; 239 struct nl_object *obj; 240 241 if (!filter) 242 BUG(); 243 244 cache = nl_cache_alloc(orig->c_ops); 245 if (!cache) 246 return NULL; 247 248 ops = orig->c_ops->co_obj_ops; 249 250 nl_list_for_each_entry(obj, &orig->c_items, ce_list) { 251 if (!nl_object_match_filter(obj, filter)) 252 continue; 253 254 nl_cache_add(cache, obj); 255 } 256 257 return cache; 258} 259 260/** 261 * Clear a cache. 262 * @arg cache cache to clear 263 * 264 * Removes all elements of a cache. 265 */ 266void nl_cache_clear(struct nl_cache *cache) 267{ 268 struct nl_object *obj, *tmp; 269 270 NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache)); 271 272 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) 273 nl_cache_remove(obj); 274} 275 276/** 277 * Free a cache. 278 * @arg cache Cache to free. 279 * 280 * Removes all elements of a cache and frees all memory. 281 * 282 * @note Use this function if you are working with allocated caches. 283 */ 284void nl_cache_free(struct nl_cache *cache) 285{ 286 if (!cache) 287 return; 288 289 nl_cache_clear(cache); 290 NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache)); 291 free(cache); 292} 293 294/** @} */ 295 296/** 297 * @name Cache Modifications 298 * @{ 299 */ 300 301static int __cache_add(struct nl_cache *cache, struct nl_object *obj) 302{ 303 obj->ce_cache = cache; 304 305 nl_list_add_tail(&obj->ce_list, &cache->c_items); 306 cache->c_nitems++; 307 308 NL_DBG(1, "Added %p to cache %p <%s>.\n", 309 obj, cache, nl_cache_name(cache)); 310 311 return 0; 312} 313 314/** 315 * Add object to a cache. 316 * @arg cache Cache to add object to 317 * @arg obj Object to be added to the cache 318 * 319 * Adds the given object to the specified cache. The object is cloned 320 * if it has been added to another cache already. 321 * 322 * @return 0 or a negative error code. 323 */ 324int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) 325{ 326 struct nl_object *new; 327 328 if (cache->c_ops->co_obj_ops != obj->ce_ops) 329 return -NLE_OBJ_MISMATCH; 330 331 if (!nl_list_empty(&obj->ce_list)) { 332 new = nl_object_clone(obj); 333 if (!new) 334 return -NLE_NOMEM; 335 } else { 336 nl_object_get(obj); 337 new = obj; 338 } 339 340 return __cache_add(cache, new); 341} 342 343/** 344 * Move object from one cache to another 345 * @arg cache Cache to move object to. 346 * @arg obj Object subject to be moved 347 * 348 * Removes the given object from its associated cache if needed 349 * and adds it to the new cache. 350 * 351 * @return 0 on success or a negative error code. 352 */ 353int nl_cache_move(struct nl_cache *cache, struct nl_object *obj) 354{ 355 if (cache->c_ops->co_obj_ops != obj->ce_ops) 356 return -NLE_OBJ_MISMATCH; 357 358 NL_DBG(3, "Moving object %p to cache %p\n", obj, cache); 359 360 /* Acquire reference, if already in a cache this will be 361 * reverted during removal */ 362 nl_object_get(obj); 363 364 if (!nl_list_empty(&obj->ce_list)) 365 nl_cache_remove(obj); 366 367 return __cache_add(cache, obj); 368} 369 370/** 371 * Removes an object from a cache. 372 * @arg obj Object to remove from its cache 373 * 374 * Removes the object \c obj from the cache it is assigned to, since 375 * an object can only be assigned to one cache at a time, the cache 376 * must ne be passed along with it. 377 */ 378void nl_cache_remove(struct nl_object *obj) 379{ 380 struct nl_cache *cache = obj->ce_cache; 381 382 if (cache == NULL) 383 return; 384 385 nl_list_del(&obj->ce_list); 386 obj->ce_cache = NULL; 387 nl_object_put(obj); 388 cache->c_nitems--; 389 390 NL_DBG(1, "Deleted %p from cache %p <%s>.\n", 391 obj, cache, nl_cache_name(cache)); 392} 393 394/** 395 * Search for an object in a cache 396 * @arg cache Cache to search in. 397 * @arg needle Object to look for. 398 * 399 * Iterates over the cache and looks for an object with identical 400 * identifiers as the needle. 401 * 402 * @return Reference to object or NULL if not found. 403 * @note The returned object must be returned via nl_object_put(). 404 */ 405struct nl_object *nl_cache_search(struct nl_cache *cache, 406 struct nl_object *needle) 407{ 408 struct nl_object *obj; 409 410 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 411 if (nl_object_identical(obj, needle)) { 412 nl_object_get(obj); 413 return obj; 414 } 415 } 416 417 return NULL; 418} 419 420 421/** @} */ 422 423/** 424 * @name Synchronization 425 * @{ 426 */ 427 428/** 429 * Request a full dump from the kernel to fill a cache 430 * @arg sk Netlink socket. 431 * @arg cache Cache subjected to be filled. 432 * 433 * Send a dumping request to the kernel causing it to dump all objects 434 * related to the specified cache to the netlink socket. 435 * 436 * Use nl_cache_pickup() to read the objects from the socket and fill them 437 * into a cache. 438 */ 439int nl_cache_request_full_dump(struct nl_sock *sk, struct nl_cache *cache) 440{ 441 NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n", 442 cache, nl_cache_name(cache)); 443 444 if (cache->c_ops->co_request_update == NULL) 445 return -NLE_OPNOTSUPP; 446 447 return cache->c_ops->co_request_update(cache, sk); 448} 449 450/** @cond SKIP */ 451struct update_xdata { 452 struct nl_cache_ops *ops; 453 struct nl_parser_param *params; 454}; 455 456static int update_msg_parser(struct nl_msg *msg, void *arg) 457{ 458 struct update_xdata *x = arg; 459 460 return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params); 461} 462/** @endcond */ 463 464int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache, 465 struct nl_parser_param *param) 466{ 467 int err; 468 struct nl_cb *cb; 469 struct update_xdata x = { 470 .ops = cache->c_ops, 471 .params = param, 472 }; 473 474 NL_DBG(1, "Picking up answer for cache %p <%s>...\n", 475 cache, nl_cache_name(cache)); 476 477 cb = nl_cb_clone(sk->s_cb); 478 if (cb == NULL) 479 return -NLE_NOMEM; 480 481 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x); 482 483 err = nl_recvmsgs(sk, cb); 484 if (err < 0) 485 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \ 486 "%d: %s", cache, nl_cache_name(cache), 487 err, nl_geterror(err)); 488 489 nl_cb_put(cb); 490 491 return err; 492} 493 494static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) 495{ 496 return nl_cache_add((struct nl_cache *) p->pp_arg, c); 497} 498 499/** 500 * Pickup a netlink dump response and put it into a cache. 501 * @arg sk Netlink socket. 502 * @arg cache Cache to put items into. 503 * 504 * Waits for netlink messages to arrive, parses them and puts them into 505 * the specified cache. 506 * 507 * @return 0 on success or a negative error code. 508 */ 509int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) 510{ 511 struct nl_parser_param p = { 512 .pp_cb = pickup_cb, 513 .pp_arg = cache, 514 }; 515 516 return __cache_pickup(sk, cache, &p); 517} 518 519static int cache_include(struct nl_cache *cache, struct nl_object *obj, 520 struct nl_msgtype *type, change_func_t cb, void *data) 521{ 522 struct nl_object *old; 523 524 switch (type->mt_act) { 525 case NL_ACT_NEW: 526 case NL_ACT_DEL: 527 old = nl_cache_search(cache, obj); 528 if (old) { 529 nl_cache_remove(old); 530 if (type->mt_act == NL_ACT_DEL) { 531 if (cb) 532 cb(cache, old, NL_ACT_DEL, data); 533 nl_object_put(old); 534 } 535 } 536 537 if (type->mt_act == NL_ACT_NEW) { 538 nl_cache_move(cache, obj); 539 if (old == NULL && cb) 540 cb(cache, obj, NL_ACT_NEW, data); 541 else if (old) { 542 if (nl_object_diff(old, obj) && cb) 543 cb(cache, obj, NL_ACT_CHANGE, data); 544 545 nl_object_put(old); 546 } 547 } 548 break; 549 default: 550 NL_DBG(2, "Unknown action associated to object %p\n", obj); 551 return 0; 552 } 553 554 return 0; 555} 556 557int nl_cache_include(struct nl_cache *cache, struct nl_object *obj, 558 change_func_t change_cb, void *data) 559{ 560 struct nl_cache_ops *ops = cache->c_ops; 561 int i; 562 563 if (ops->co_obj_ops != obj->ce_ops) 564 return -NLE_OBJ_MISMATCH; 565 566 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) 567 if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype) 568 return cache_include(cache, obj, &ops->co_msgtypes[i], 569 change_cb, data); 570 571 return -NLE_MSGTYPE_NOSUPPORT; 572} 573 574static int resync_cb(struct nl_object *c, struct nl_parser_param *p) 575{ 576 struct nl_cache_assoc *ca = p->pp_arg; 577 578 return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data); 579} 580 581int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache, 582 change_func_t change_cb, void *data) 583{ 584 struct nl_object *obj, *next; 585 struct nl_cache_assoc ca = { 586 .ca_cache = cache, 587 .ca_change = change_cb, 588 .ca_change_data = data, 589 }; 590 struct nl_parser_param p = { 591 .pp_cb = resync_cb, 592 .pp_arg = &ca, 593 }; 594 int err; 595 596 NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache)); 597 598 /* Mark all objects so we can see if some of them are obsolete */ 599 nl_cache_mark_all(cache); 600 601 err = nl_cache_request_full_dump(sk, cache); 602 if (err < 0) 603 goto errout; 604 605 err = __cache_pickup(sk, cache, &p); 606 if (err < 0) 607 goto errout; 608 609 nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) { 610 if (nl_object_is_marked(obj)) { 611 nl_object_get(obj); 612 nl_cache_remove(obj); 613 if (change_cb) 614 change_cb(cache, obj, NL_ACT_DEL, data); 615 nl_object_put(obj); 616 } 617 } 618 619 NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache)); 620 621 err = 0; 622errout: 623 return err; 624} 625 626/** @} */ 627 628/** 629 * @name Parsing 630 * @{ 631 */ 632 633/** @cond SKIP */ 634int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, 635 struct nlmsghdr *nlh, struct nl_parser_param *params) 636{ 637 int i, err; 638 639 if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) 640 return -NLE_MSG_TOOSHORT; 641 642 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) { 643 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) { 644 err = ops->co_msg_parser(ops, who, nlh, params); 645 if (err != -NLE_OPNOTSUPP) 646 goto errout; 647 } 648 } 649 650 651 err = -NLE_MSGTYPE_NOSUPPORT; 652errout: 653 return err; 654} 655/** @endcond */ 656 657/** 658 * Parse a netlink message and add it to the cache. 659 * @arg cache cache to add element to 660 * @arg msg netlink message 661 * 662 * Parses a netlink message by calling the cache specific message parser 663 * and adds the new element to the cache. 664 * 665 * @return 0 or a negative error code. 666 */ 667int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) 668{ 669 struct nl_parser_param p = { 670 .pp_cb = pickup_cb, 671 .pp_arg = cache, 672 }; 673 674 return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p); 675} 676 677/** 678 * (Re)fill a cache with the contents in the kernel. 679 * @arg sk Netlink socket. 680 * @arg cache cache to update 681 * 682 * Clears the specified cache and fills it with the current state in 683 * the kernel. 684 * 685 * @return 0 or a negative error code. 686 */ 687int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) 688{ 689 int err; 690 691 err = nl_cache_request_full_dump(sk, cache); 692 if (err < 0) 693 return err; 694 695 NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n", 696 cache, nl_cache_name(cache)); 697 nl_cache_clear(cache); 698 699 return nl_cache_pickup(sk, cache); 700} 701 702/** @} */ 703 704/** 705 * @name Utillities 706 * @{ 707 */ 708 709/** 710 * Mark all objects in a cache 711 * @arg cache Cache to mark all objects in 712 */ 713void nl_cache_mark_all(struct nl_cache *cache) 714{ 715 struct nl_object *obj; 716 717 NL_DBG(2, "Marking all objects in cache %p <%s>...\n", 718 cache, nl_cache_name(cache)); 719 720 nl_list_for_each_entry(obj, &cache->c_items, ce_list) 721 nl_object_mark(obj); 722} 723 724/** @} */ 725 726/** 727 * @name Dumping 728 * @{ 729 */ 730 731/** 732 * Dump all elements of a cache. 733 * @arg cache cache to dump 734 * @arg params dumping parameters 735 * 736 * Dumps all elements of the \a cache to the file descriptor \a fd. 737 */ 738void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params) 739{ 740 nl_cache_dump_filter(cache, params, NULL); 741} 742 743/** 744 * Dump all elements of a cache (filtered). 745 * @arg cache cache to dump 746 * @arg params dumping parameters (optional) 747 * @arg filter filter object 748 * 749 * Dumps all elements of the \a cache to the file descriptor \a fd 750 * given they match the given filter \a filter. 751 */ 752void nl_cache_dump_filter(struct nl_cache *cache, 753 struct nl_dump_params *params, 754 struct nl_object *filter) 755{ 756 int type = params ? params->dp_type : NL_DUMP_DETAILS; 757 struct nl_object_ops *ops; 758 struct nl_object *obj; 759 760 NL_DBG(2, "Dumping cache %p <%s> filter %p\n", 761 cache, nl_cache_name(cache), filter); 762 763 if (type > NL_DUMP_MAX || type < 0) 764 BUG(); 765 766 if (cache->c_ops == NULL) 767 BUG(); 768 769 ops = cache->c_ops->co_obj_ops; 770 if (!ops->oo_dump[type]) 771 return; 772 773 nl_list_for_each_entry(obj, &cache->c_items, ce_list) { 774 if (filter && !nl_object_match_filter(obj, filter)) 775 continue; 776 777 NL_DBG(4, "Dumping object %p...\n", obj); 778 dump_from_ops(obj, params); 779 } 780} 781 782/** @} */ 783 784/** 785 * @name Iterators 786 * @{ 787 */ 788 789/** 790 * Call a callback on each element of the cache. 791 * @arg cache cache to iterate on 792 * @arg cb callback function 793 * @arg arg argument passed to callback function 794 * 795 * Calls a callback function \a cb on each element of the \a cache. 796 * The argument \a arg is passed on the callback function. 797 */ 798void nl_cache_foreach(struct nl_cache *cache, 799 void (*cb)(struct nl_object *, void *), void *arg) 800{ 801 nl_cache_foreach_filter(cache, NULL, cb, arg); 802} 803 804/** 805 * Call a callback on each element of the cache (filtered). 806 * @arg cache cache to iterate on 807 * @arg filter filter object 808 * @arg cb callback function 809 * @arg arg argument passed to callback function 810 * 811 * Calls a callback function \a cb on each element of the \a cache 812 * that matches the \a filter. The argument \a arg is passed on 813 * to the callback function. 814 */ 815void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, 816 void (*cb)(struct nl_object *, void *), void *arg) 817{ 818 struct nl_object *obj, *tmp; 819 struct nl_object_ops *ops; 820 821 if (cache->c_ops == NULL) 822 BUG(); 823 824 ops = cache->c_ops->co_obj_ops; 825 826 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) { 827 if (filter && !nl_object_match_filter(obj, filter)) 828 continue; 829 830 cb(obj, arg); 831 } 832} 833 834/** @} */ 835 836/** @} */ 837