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