This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.git] / lib / cache.c
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-2006 Thomas Graf <tgraf@suug.ch>
10  */
11
12 /**
13  * @ingroup utils
14  * @defgroup cache Caching
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 static inline char *nl_cache_name(struct nl_cache *cache)
50 {
51         return cache->c_ops ? cache->c_ops->co_name : "unknown";
52 }
53
54 /**
55  * @name Access Functions
56  * @{
57  */
58
59 /**
60  * Return the number of items in the cache
61  * @arg cache           cache handle
62  */
63 int nl_cache_nitems(struct nl_cache *cache)
64 {
65         return cache->c_nitems;
66 }
67
68 /**
69  * Return the number of items matching a filter in the cache
70  * @arg cache           Cache object.
71  * @arg filter          Filter object.
72  */
73 int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
74 {
75         struct nl_cache_ops *ops = cache->c_ops;
76         struct nl_object *obj;
77         int nitems = 0;
78         
79         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
80                 if (filter && ops->co_filter && !ops->co_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  */
94 int 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  */
103 struct 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  */
112 struct 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  */
125 struct 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  */
138 struct 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  */
151 struct 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 of no certain type
169  * 
170  * @return A newly allocated and initialized cache.
171  */
172 struct nl_cache *nl_cache_alloc(void)
173 {
174         struct nl_cache *cache;
175
176         cache = calloc(1, sizeof(*cache));
177         if (!cache) {
178                 nl_errno(ENOMEM);
179                 return NULL;
180         }
181
182         nl_init_list_head(&cache->c_items);
183         NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
184
185         return cache;
186 }
187
188 /**
189  * Allocate an empty cache based on cache operations
190  * @arg ops             cache operations to base the cache on
191  * @return A newly allocated and initialized cache.
192  */
193 struct nl_cache *nl_cache_alloc_from_ops(struct nl_cache_ops *ops)
194 {
195         struct nl_cache *new;
196
197         new = nl_cache_alloc();
198         if (!new)
199                 return NULL;
200
201         new->c_ops = ops;
202
203         return new;
204 }
205
206 /**
207  * Allocate an empty cache based on type name
208  * @arg kind            Name of cache type
209  * @return A newly allocated and initialized cache.
210  */
211 struct nl_cache *nl_cache_alloc_name(const char *kind)
212 {
213         struct nl_cache_ops *ops;
214
215         ops = nl_cache_mngt_lookup(kind);
216         if (!ops) {
217                 nl_error(ENOENT, "Unable to lookup cache \"%s\"", kind);
218                 return NULL;
219         }
220
221         return nl_cache_alloc_from_ops(ops);
222 }
223
224 /**
225  * Clear a cache.
226  * @arg cache           cache to clear
227  *
228  * Removes all elements of a cache.
229  */
230 void nl_cache_clear(struct nl_cache *cache)
231 {
232         struct nl_object *obj, *tmp;
233
234         NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
235
236         nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
237                 nl_cache_delete(cache, obj);
238 }
239
240 /**
241  * Free a cache.
242  * @arg cache           Cache to free.
243  *
244  * Removes all elements of a cache and frees all memory.
245  *
246  * @note Use this function if you are working with allocated caches.
247  */
248 void nl_cache_free(struct nl_cache *cache)
249 {
250         nl_cache_clear(cache);
251         NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
252         free(cache);
253 }
254
255 /** @} */
256
257 /**
258  * @name Cache Modifications
259  * @{
260  */
261
262 /**
263  * Add an element to the cache.
264  * @arg cache           cache to add a element to
265  * @arg obj             Common obj to be added to the cache
266  *
267  * Adds the object \c obj to the tail of the cache \c cache and. The
268  * cache is enlarged as needed.
269  *
270  * @return 0 or a negative error code.
271  */
272 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
273 {
274         struct nl_object *new;
275
276         if (nl_object_shared(obj)) {
277                 new = nl_object_clone(obj);
278                 if (!new)
279                         return nl_errno(ENOMEM);
280
281                 nl_object_put(obj);
282         } else
283                 new = obj;
284
285         new->ce_cache = cache;
286
287         nl_list_add_tail(&new->ce_list, &cache->c_items);
288         cache->c_nitems++;
289
290         NL_DBG(1, "Added %p to cache %p <%s>.\n",
291                new, cache, nl_cache_name(cache));
292
293         return 0;
294 }
295
296 static int subsys_parse_cb(struct nl_object *c, struct nl_parser_param *p)
297 {
298         return nl_cache_add((struct nl_cache *) p->pp_arg, c);
299 }
300
301 /** @cond SKIP */
302 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
303                    struct nlmsghdr *nlh, struct nl_parser_param *params)
304 {
305         int i, len, err, hdrsize;
306
307         hdrsize = ops->co_hdrsize;
308         len = nlh->nlmsg_len - nlmsg_msg_size(hdrsize);
309         if (len < 0) {
310                 err = nl_error(EINVAL, "netlink message too short to "
311                                        "of kind %s", ops->co_name);
312                 goto errout;
313         }
314
315         for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
316                 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type)
317                         return ops->co_msg_parser(who, nlh, params);
318
319         err = nl_error(EINVAL, "Unsupported netlink message type %d",
320                        nlh->nlmsg_type);
321 errout:
322         return err;
323 }
324 /** @endcond */
325
326 /**
327  * Parse a netlink message and add it to the cache.
328  * @arg cache           cache to add element to
329  * @arg msg             netlink message
330  *
331  * Parses a netlink message by calling the cache specific message parser
332  * and adds the new element to the cache.
333  *
334  * @return 0 or a negative error code.
335  */
336 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
337 {
338         struct nl_parser_param p = {
339                 .pp_cb = subsys_parse_cb,
340                 .pp_arg = cache,
341         };
342
343         return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
344 }
345
346 /**
347  * Delete an element from a cache.
348  * @arg cache           cache to delete the element from
349  * @arg obj             Object to delete
350  *
351  * Deletes the object \c obj from the cache \c cache.
352  */
353 void nl_cache_delete(struct nl_cache *cache, struct nl_object *obj)
354 {
355         if (obj->ce_cache != cache)
356                 BUG();
357
358         nl_list_del(&obj->ce_list);
359         obj->ce_cache = NULL;
360         nl_object_put(obj);
361         cache->c_nitems--;
362
363         NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
364                obj, cache, nl_cache_name(cache));
365 }
366
367 /** @cond SKIP */
368 struct update_xdata {
369         struct nl_cache_ops *ops;
370         struct nl_parser_param *params;
371 };
372 /** @endcond */
373
374 static int update_msg_parser(struct nl_msg *msg, void *arg)
375 {
376         struct update_xdata *x = arg;
377         
378         return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
379 }
380
381 /**
382  * Pickup a netlink dump response and put it into a cache.
383  * @arg handle          Netlink handle.
384  * @arg cache           Cache to put items into.
385  *
386  * Waits for netlink messages to arrive, parses them and puts them into
387  * the specified cache.
388  *
389  * @return 0 on success or a negative error code.
390  */
391 int nl_cache_pickup(struct nl_handle *handle, struct nl_cache *cache)
392 {
393         int err;
394         struct nl_cache_ops *ops = cache->c_ops;
395         struct nl_cb *cb;
396         struct nl_parser_param p = {
397                 .pp_cb = subsys_parse_cb,
398                 .pp_arg = cache,
399         };
400         struct update_xdata x = {
401                 .ops = ops,
402                 .params = &p,
403         };
404
405         NL_DBG(1, "Filling cache %p <%s>...\n", cache, nl_cache_name(cache));
406
407         cb = nl_cb_clone(nl_handle_get_cb(handle));
408         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
409
410         err = nl_recvmsgs(handle, cb);
411         if (err < 0)
412                 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
413                        "%d: %s", cache, nl_cache_name(cache),
414                        err, nl_geterror());
415
416         nl_cb_destroy(cb);
417
418         return err;
419 }
420
421 /**
422  * Update (synchronize) a local cache with the kernel.
423  * @arg handle          netlink handle
424  * @arg cache           cache to update
425  *
426  * Updates the local cache \c cache with the state in the kernel. During
427  * this process the cache gets emptied and refilled with the new content
428  * received from the kernel.
429  *
430  * @return 0 or a negative error code.
431  */
432 int nl_cache_update(struct nl_handle *handle, struct nl_cache *cache)
433 {
434         int err;
435         struct nl_cache_ops *ops = cache->c_ops;
436
437         err = ops->co_request_update(cache, handle);
438         if (err < 0)
439                 return err;
440
441         NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
442                cache, nl_cache_name(cache));
443         nl_cache_clear(cache);
444
445         return nl_cache_pickup(handle, cache);
446 }
447
448 /** @} */
449
450 /**
451  * @name Dumping
452  * @{
453  */
454
455 /**
456  * Dump all elements of a cache.
457  * @arg cache           cache to dump
458  * @arg params          dumping parameters
459  *
460  * Dumps all elements of the \a cache to the file descriptor \a fd.
461  */
462 void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
463 {
464         NL_DBG(1, "Dumping cache %p <%s>\n", cache, nl_cache_name(cache));
465         nl_cache_dump_filter(cache, params, NULL);
466 }
467
468 /**
469  * Dump all elements of a cache (filtered).
470  * @arg cache           cache to dump
471  * @arg params          dumping parameters (optional)
472  * @arg filter          filter object
473  *
474  * Dumps all elements of the \a cache to the file descriptor \a fd
475  * given they match the given filter \a filter.
476  */
477 void nl_cache_dump_filter(struct nl_cache *cache,
478                           struct nl_dump_params *params,
479                           struct nl_object *filter)
480 {
481         int type = params ? params->dp_type : NL_DUMP_FULL;
482         struct nl_cache_ops *ops = cache->c_ops;
483         struct nl_object *obj;
484
485         if (type > NL_DUMP_MAX || type < 0)
486                 BUG();
487
488         if (!ops->co_dump[type])
489                 return;
490
491         nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
492                 if (filter && obj->ce_ops != filter->ce_ops)
493                         continue;
494                 
495                 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
496                         continue;
497
498                 dump_from_ops(obj, params);
499         }
500 }
501
502 /** @} */
503
504 /**
505  * @name Iterators
506  * @{
507  */
508
509 /**
510  * Call a callback on each element of the cache.
511  * @arg cache           cache to iterate on
512  * @arg cb              callback function
513  * @arg arg             argument passed to callback function
514  *
515  * Calls a callback function \a cb on each element of the \a cache.
516  * The argument \a arg is passed on the callback function.
517  */
518 void nl_cache_foreach(struct nl_cache *cache,
519                       void (*cb)(struct nl_object *, void *), void *arg)
520 {
521         nl_cache_foreach_filter(cache, NULL, cb, arg);
522 }
523
524 /**
525  * Call a callback on each element of the cache (filtered).
526  * @arg cache           cache to iterate on
527  * @arg filter          filter object
528  * @arg cb              callback function
529  * @arg arg             argument passed to callback function
530  *
531  * Calls a callback function \a cb on each element of the \a cache
532  * that matches the \a filter. The argument \a arg is passed on
533  * to the callback function.
534  */
535 void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
536                              void (*cb)(struct nl_object *, void *), void *arg)
537 {
538         struct nl_object *obj, *tmp;
539         struct nl_cache_ops *ops = cache->c_ops;
540
541         nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
542                 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
543                         continue;
544
545                 cb(obj, arg);
546         }
547 }
548
549 /** @} */
550
551 /** @} */