2 * lib/cache.c Caching Module
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
9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
14 * @defgroup cache Cache
17 * Cache Management | | Type Specific Cache Operations
19 * | | +----------------+ +------------+
20 * | request update | | msg_parser |
21 * | | +----------------+ +------------+
22 * +- - - - -^- - - - - - - -^- -|- - - -
23 * nl_cache_update: | | | |
24 * 1) --------- co_request_update ------+ | |
26 * 2) destroy old cache +----------- pp_cb ---------|---+
28 * 3) ---------- nl_recvmsgs ----------+ +- cb_valid -+
29 * +--------------+ | | | |
30 * | nl_cache_add |<-----+ + - - -v- -|- - - - - - - - - - -
31 * +--------------+ | | +-------------+
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>
50 * @name Access Functions
56 * Return the number of items in the cache
57 * @arg cache cache handle
59 int nl_cache_nitems(struct nl_cache
*cache
)
61 return cache
->c_nitems
;
65 * Return the number of items matching a filter in the cache
66 * @arg cache Cache object.
67 * @arg filter Filter object.
69 int nl_cache_nitems_filter(struct nl_cache
*cache
, struct nl_object
*filter
)
71 struct nl_object_ops
*ops
;
72 struct nl_object
*obj
;
75 if (cache
->c_ops
== NULL
)
78 ops
= cache
->c_ops
->co_obj_ops
;
80 nl_list_for_each_entry(obj
, &cache
->c_items
, ce_list
) {
81 if (filter
&& !nl_object_match_filter(obj
, filter
))
91 * Returns \b true if the cache is empty.
92 * @arg cache Cache to check
93 * @return \a true if the cache is empty, otherwise \b false is returned.
95 int nl_cache_is_empty(struct nl_cache
*cache
)
97 return nl_list_empty(&cache
->c_items
);
101 * Return the operations set of the cache
102 * @arg cache cache handle
104 struct nl_cache_ops
*nl_cache_get_ops(struct nl_cache
*cache
)
110 * Return the first element in the cache
111 * @arg cache cache handle
113 struct nl_object
*nl_cache_get_first(struct nl_cache
*cache
)
115 if (nl_list_empty(&cache
->c_items
))
118 return nl_list_entry(cache
->c_items
.next
,
119 struct nl_object
, ce_list
);
123 * Return the last element in the cache
124 * @arg cache cache handle
126 struct nl_object
*nl_cache_get_last(struct nl_cache
*cache
)
128 if (nl_list_empty(&cache
->c_items
))
131 return nl_list_entry(cache
->c_items
.prev
,
132 struct nl_object
, ce_list
);
136 * Return the next element in the cache
137 * @arg obj current object
139 struct nl_object
*nl_cache_get_next(struct nl_object
*obj
)
141 if (nl_list_at_tail(obj
, &obj
->ce_cache
->c_items
, ce_list
))
144 return nl_list_entry(obj
->ce_list
.next
,
145 struct nl_object
, ce_list
);
149 * Return the previous element in the cache
150 * @arg obj current object
152 struct nl_object
*nl_cache_get_prev(struct nl_object
*obj
)
154 if (nl_list_at_head(obj
, &obj
->ce_cache
->c_items
, ce_list
))
157 return nl_list_entry(obj
->ce_list
.prev
,
158 struct nl_object
, ce_list
);
165 * @name Cache Creation/Deletion
170 * Allocate an empty cache
171 * @arg ops cache operations to base the cache on
173 * @return A newly allocated and initialized cache.
175 struct nl_cache
*nl_cache_alloc(struct nl_cache_ops
*ops
)
177 struct nl_cache
*cache
;
179 cache
= calloc(1, sizeof(*cache
));
183 nl_init_list_head(&cache
->c_items
);
186 NL_DBG(2, "Allocated cache %p <%s>.\n", cache
, nl_cache_name(cache
));
191 int nl_cache_alloc_and_fill(struct nl_cache_ops
*ops
, struct nl_sock
*sock
,
192 struct nl_cache
**result
)
194 struct nl_cache
*cache
;
197 if (!(cache
= nl_cache_alloc(ops
)))
200 if (sock
&& (err
= nl_cache_refill(sock
, cache
)) < 0) {
201 nl_cache_free(cache
);
211 * Allocate an empty cache based on type name
212 * @arg kind Name of cache type
213 * @return A newly allocated and initialized cache.
215 int nl_cache_alloc_name(const char *kind
, struct nl_cache
**result
)
217 struct nl_cache_ops
*ops
;
218 struct nl_cache
*cache
;
220 ops
= nl_cache_ops_lookup(kind
);
224 if (!(cache
= nl_cache_alloc(ops
)))
232 * Allocate a new cache containing a subset of a cache
233 * @arg orig Original cache to be based on
234 * @arg filter Filter defining the subset to be filled into new cache
235 * @return A newly allocated cache or NULL.
237 struct nl_cache
*nl_cache_subset(struct nl_cache
*orig
,
238 struct nl_object
*filter
)
240 struct nl_cache
*cache
;
241 struct nl_object_ops
*ops
;
242 struct nl_object
*obj
;
247 cache
= nl_cache_alloc(orig
->c_ops
);
251 ops
= orig
->c_ops
->co_obj_ops
;
253 nl_list_for_each_entry(obj
, &orig
->c_items
, ce_list
) {
254 if (!nl_object_match_filter(obj
, filter
))
257 nl_cache_add(cache
, obj
);
266 * @arg cache cache to clear
268 * Removes all elements of a cache.
270 void nl_cache_clear(struct nl_cache
*cache
)
272 struct nl_object
*obj
, *tmp
;
274 NL_DBG(1, "Clearing cache %p <%s>...\n", cache
, nl_cache_name(cache
));
276 nl_list_for_each_entry_safe(obj
, tmp
, &cache
->c_items
, ce_list
)
277 nl_cache_remove(obj
);
282 * @arg cache Cache to free.
284 * Removes all elements of a cache and frees all memory.
286 * @note Use this function if you are working with allocated caches.
288 void nl_cache_free(struct nl_cache
*cache
)
293 nl_cache_clear(cache
);
294 NL_DBG(1, "Freeing cache %p <%s>...\n", cache
, nl_cache_name(cache
));
301 * @name Cache Modifications
305 static int __cache_add(struct nl_cache
*cache
, struct nl_object
*obj
)
307 obj
->ce_cache
= cache
;
309 nl_list_add_tail(&obj
->ce_list
, &cache
->c_items
);
312 NL_DBG(1, "Added %p to cache %p <%s>.\n",
313 obj
, cache
, nl_cache_name(cache
));
319 * Add object to a cache.
320 * @arg cache Cache to add object to
321 * @arg obj Object to be added to the cache
323 * Adds the given object to the specified cache. The object is cloned
324 * if it has been added to another cache already.
326 * @return 0 or a negative error code.
328 int nl_cache_add(struct nl_cache
*cache
, struct nl_object
*obj
)
330 struct nl_object
*new;
332 if (cache
->c_ops
->co_obj_ops
!= obj
->ce_ops
)
333 return -NLE_OBJ_MISMATCH
;
335 if (!nl_list_empty(&obj
->ce_list
)) {
336 new = nl_object_clone(obj
);
344 return __cache_add(cache
, new);
349 * Move object from one cache to another
350 * @arg cache Cache to move object to.
351 * @arg obj Object subject to be moved
353 * Removes the given object from its associated cache if needed
354 * and adds it to the new cache.
356 * @return 0 on success or a negative error code.
358 int nl_cache_move(struct nl_cache
*cache
, struct nl_object
*obj
)
360 if (cache
->c_ops
->co_obj_ops
!= obj
->ce_ops
)
361 return -NLE_OBJ_MISMATCH
;
363 NL_DBG(3, "Moving object %p to cache %p\n", obj
, cache
);
365 /* Acquire reference, if already in a cache this will be
366 * reverted during removal */
369 if (!nl_list_empty(&obj
->ce_list
))
370 nl_cache_remove(obj
);
372 return __cache_add(cache
, obj
);
377 * Removes an object from a cache.
378 * @arg obj Object to remove from its cache
380 * Removes the object \c obj from the cache it is assigned to, since
381 * an object can only be assigned to one cache at a time, the cache
382 * must ne be passed along with it.
384 void nl_cache_remove(struct nl_object
*obj
)
386 struct nl_cache
*cache
= obj
->ce_cache
;
391 nl_list_del(&obj
->ce_list
);
392 obj
->ce_cache
= NULL
;
396 NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
397 obj
, cache
, nl_cache_name(cache
));
402 * Search for an object in a cache
403 * @arg cache Cache to search in.
404 * @arg needle Object to look for.
406 * Iterates over the cache and looks for an object with identical
407 * identifiers as the needle.
409 * @return Reference to object or NULL if not found.
410 * @note The returned object must be returned via nl_object_put().
412 struct nl_object
*nl_cache_search(struct nl_cache
*cache
,
413 struct nl_object
*needle
)
415 struct nl_object
*obj
;
417 nl_list_for_each_entry(obj
, &cache
->c_items
, ce_list
) {
418 if (nl_object_identical(obj
, needle
)) {
431 * @name Synchronization
436 * Request a full dump from the kernel to fill a cache
437 * @arg sk Netlink socket.
438 * @arg cache Cache subjected to be filled.
440 * Send a dumping request to the kernel causing it to dump all objects
441 * related to the specified cache to the netlink socket.
443 * Use nl_cache_pickup() to read the objects from the socket and fill them
446 int nl_cache_request_full_dump(struct nl_sock
*sk
, struct nl_cache
*cache
)
448 NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n",
449 cache
, nl_cache_name(cache
));
451 if (cache
->c_ops
->co_request_update
== NULL
)
452 return -NLE_OPNOTSUPP
;
454 return cache
->c_ops
->co_request_update(cache
, sk
);
458 struct update_xdata
{
459 struct nl_cache_ops
*ops
;
460 struct nl_parser_param
*params
;
463 static int update_msg_parser(struct nl_msg
*msg
, void *arg
)
465 struct update_xdata
*x
= arg
;
467 return nl_cache_parse(x
->ops
, &msg
->nm_src
, msg
->nm_nlh
, x
->params
);
471 int __cache_pickup(struct nl_sock
*sk
, struct nl_cache
*cache
,
472 struct nl_parser_param
*param
)
476 struct update_xdata x
= {
481 NL_DBG(1, "Picking up answer for cache %p <%s>...\n",
482 cache
, nl_cache_name(cache
));
484 cb
= nl_cb_clone(sk
->s_cb
);
488 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, update_msg_parser
, &x
);
490 err
= nl_recvmsgs(sk
, cb
);
492 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
493 "%d: %s", cache
, nl_cache_name(cache
),
494 err
, nl_geterror(err
));
501 static int pickup_cb(struct nl_object
*c
, struct nl_parser_param
*p
)
503 return nl_cache_add((struct nl_cache
*) p
->pp_arg
, c
);
507 * Pickup a netlink dump response and put it into a cache.
508 * @arg sk Netlink socket.
509 * @arg cache Cache to put items into.
511 * Waits for netlink messages to arrive, parses them and puts them into
512 * the specified cache.
514 * @return 0 on success or a negative error code.
516 int nl_cache_pickup(struct nl_sock
*sk
, struct nl_cache
*cache
)
518 struct nl_parser_param p
= {
523 return __cache_pickup(sk
, cache
, &p
);
527 static int cache_include(struct nl_cache
*cache
, struct nl_object
*obj
,
528 struct nl_msgtype
*type
, change_func_t cb
)
530 struct nl_object
*old
;
532 switch (type
->mt_act
) {
535 old
= nl_cache_search(cache
, obj
);
537 nl_cache_remove(old
);
538 if (type
->mt_act
== NL_ACT_DEL
) {
540 cb(cache
, old
, NL_ACT_DEL
);
545 if (type
->mt_act
== NL_ACT_NEW
) {
546 nl_cache_move(cache
, obj
);
547 if (old
== NULL
&& cb
)
548 cb(cache
, obj
, NL_ACT_NEW
);
550 if (nl_object_diff(old
, obj
) && cb
)
551 cb(cache
, obj
, NL_ACT_CHANGE
);
558 NL_DBG(2, "Unknown action associated to object %p\n", obj
);
565 int nl_cache_include(struct nl_cache
*cache
, struct nl_object
*obj
,
566 change_func_t change_cb
)
568 struct nl_cache_ops
*ops
= cache
->c_ops
;
571 if (ops
->co_obj_ops
!= obj
->ce_ops
)
572 return -NLE_OBJ_MISMATCH
;
574 for (i
= 0; ops
->co_msgtypes
[i
].mt_id
>= 0; i
++)
575 if (ops
->co_msgtypes
[i
].mt_id
== obj
->ce_msgtype
)
576 return cache_include(cache
, obj
, &ops
->co_msgtypes
[i
],
579 return -NLE_MSGTYPE_NOSUPPORT
;
582 static int resync_cb(struct nl_object
*c
, struct nl_parser_param
*p
)
584 struct nl_cache_assoc
*ca
= p
->pp_arg
;
586 return nl_cache_include(ca
->ca_cache
, c
, ca
->ca_change
);
589 int nl_cache_resync(struct nl_sock
*sk
, struct nl_cache
*cache
,
590 change_func_t change_cb
)
592 struct nl_object
*obj
, *next
;
593 struct nl_cache_assoc ca
= {
595 .ca_change
= change_cb
,
597 struct nl_parser_param p
= {
603 NL_DBG(1, "Resyncing cache %p <%s>...\n", cache
, nl_cache_name(cache
));
605 /* Mark all objects so we can see if some of them are obsolete */
606 nl_cache_mark_all(cache
);
608 err
= nl_cache_request_full_dump(sk
, cache
);
612 err
= __cache_pickup(sk
, cache
, &p
);
616 nl_list_for_each_entry_safe(obj
, next
, &cache
->c_items
, ce_list
)
617 if (nl_object_is_marked(obj
))
618 nl_cache_remove(obj
);
620 NL_DBG(1, "Finished resyncing %p <%s>\n", cache
, nl_cache_name(cache
));
636 int nl_cache_parse(struct nl_cache_ops
*ops
, struct sockaddr_nl
*who
,
637 struct nlmsghdr
*nlh
, struct nl_parser_param
*params
)
641 if (!nlmsg_valid_hdr(nlh
, ops
->co_hdrsize
))
642 return -NLE_MSG_TOOSHORT
;
644 for (i
= 0; ops
->co_msgtypes
[i
].mt_id
>= 0; i
++) {
645 if (ops
->co_msgtypes
[i
].mt_id
== nlh
->nlmsg_type
) {
646 err
= ops
->co_msg_parser(ops
, who
, nlh
, params
);
647 if (err
!= -NLE_OPNOTSUPP
)
653 err
= -NLE_MSGTYPE_NOSUPPORT
;
660 * Parse a netlink message and add it to the cache.
661 * @arg cache cache to add element to
662 * @arg msg netlink message
664 * Parses a netlink message by calling the cache specific message parser
665 * and adds the new element to the cache.
667 * @return 0 or a negative error code.
669 int nl_cache_parse_and_add(struct nl_cache
*cache
, struct nl_msg
*msg
)
671 struct nl_parser_param p
= {
676 return nl_cache_parse(cache
->c_ops
, NULL
, nlmsg_hdr(msg
), &p
);
680 * (Re)fill a cache with the contents in the kernel.
681 * @arg sk Netlink socket.
682 * @arg cache cache to update
684 * Clears the specified cache and fills it with the current state in
687 * @return 0 or a negative error code.
689 int nl_cache_refill(struct nl_sock
*sk
, struct nl_cache
*cache
)
693 err
= nl_cache_request_full_dump(sk
, cache
);
697 NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
698 cache
, nl_cache_name(cache
));
699 nl_cache_clear(cache
);
701 return nl_cache_pickup(sk
, cache
);
713 * Mark all objects in a cache
714 * @arg cache Cache to mark all objects in
716 void nl_cache_mark_all(struct nl_cache
*cache
)
718 struct nl_object
*obj
;
720 NL_DBG(2, "Marking all objects in cache %p <%s>...\n",
721 cache
, nl_cache_name(cache
));
723 nl_list_for_each_entry(obj
, &cache
->c_items
, ce_list
)
735 * Dump all elements of a cache.
736 * @arg cache cache to dump
737 * @arg params dumping parameters
739 * Dumps all elements of the \a cache to the file descriptor \a fd.
741 void nl_cache_dump(struct nl_cache
*cache
, struct nl_dump_params
*params
)
743 nl_cache_dump_filter(cache
, params
, NULL
);
747 * Dump all elements of a cache (filtered).
748 * @arg cache cache to dump
749 * @arg params dumping parameters (optional)
750 * @arg filter filter object
752 * Dumps all elements of the \a cache to the file descriptor \a fd
753 * given they match the given filter \a filter.
755 void nl_cache_dump_filter(struct nl_cache
*cache
,
756 struct nl_dump_params
*params
,
757 struct nl_object
*filter
)
759 int type
= params
? params
->dp_type
: NL_DUMP_DETAILS
;
760 struct nl_object_ops
*ops
;
761 struct nl_object
*obj
;
763 NL_DBG(2, "Dumping cache %p <%s> filter %p\n",
764 cache
, nl_cache_name(cache
), filter
);
766 if (type
> NL_DUMP_MAX
|| type
< 0)
769 if (cache
->c_ops
== NULL
)
772 ops
= cache
->c_ops
->co_obj_ops
;
773 if (!ops
->oo_dump
[type
])
776 nl_list_for_each_entry(obj
, &cache
->c_items
, ce_list
) {
777 if (filter
&& !nl_object_match_filter(obj
, filter
))
780 NL_DBG(4, "Dumping object %p...\n", obj
);
781 dump_from_ops(obj
, params
);
794 * Call a callback on each element of the cache.
795 * @arg cache cache to iterate on
796 * @arg cb callback function
797 * @arg arg argument passed to callback function
799 * Calls a callback function \a cb on each element of the \a cache.
800 * The argument \a arg is passed on the callback function.
802 void nl_cache_foreach(struct nl_cache
*cache
,
803 void (*cb
)(struct nl_object
*, void *), void *arg
)
805 nl_cache_foreach_filter(cache
, NULL
, cb
, arg
);
809 * Call a callback on each element of the cache (filtered).
810 * @arg cache cache to iterate on
811 * @arg filter filter object
812 * @arg cb callback function
813 * @arg arg argument passed to callback function
815 * Calls a callback function \a cb on each element of the \a cache
816 * that matches the \a filter. The argument \a arg is passed on
817 * to the callback function.
819 void nl_cache_foreach_filter(struct nl_cache
*cache
, struct nl_object
*filter
,
820 void (*cb
)(struct nl_object
*, void *), void *arg
)
822 struct nl_object
*obj
, *tmp
;
823 struct nl_object_ops
*ops
;
825 if (cache
->c_ops
== NULL
)
828 ops
= cache
->c_ops
->co_obj_ops
;
830 nl_list_for_each_entry_safe(obj
, tmp
, &cache
->c_items
, ce_list
) {
831 if (filter
&& !nl_object_match_filter(obj
, filter
))
This page took 0.100489 seconds and 5 git commands to generate.