libnl  3.5.0
cache_mngt.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/cache_mngt.c Cache Management
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation version 2.1
8  * of the License.
9  *
10  * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
11  */
12 
13 /**
14  * @ingroup core
15  * @defgroup cache_mngt Caching System
16  *
17  * Related sections in the development guide:
18  * - @core_doc{core_cache, Caching System}
19  *
20  * @{
21  *
22  * Header
23  * ------
24  * ~~~~{.c}
25  * #include <netlink/cache.h>
26  * ~~~~
27  */
28 
29 #include <netlink-private/netlink.h>
30 #include <netlink/netlink.h>
31 #include <netlink/cache.h>
32 #include <netlink/utils.h>
33 
34 static struct nl_cache_ops *cache_ops;
35 static NL_RW_LOCK(cache_ops_lock);
36 
37 /**
38  * @name Cache Operations Sets
39  * @{
40  */
41 
42 static struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
43 {
44  struct nl_cache_ops *ops;
45 
46  for (ops = cache_ops; ops; ops = ops->co_next)
47  if (!strcmp(ops->co_name, name))
48  return ops;
49 
50  return NULL;
51 }
52 
53 /**
54  * Increment reference counter
55  * @arg ops Cache operations
56  */
57 void nl_cache_ops_get(struct nl_cache_ops *ops)
58 {
59  ops->co_refcnt++;
60 }
61 
62 /**
63  * Decrement reference counter
64  * @arg ops Cache operations
65  */
66 void nl_cache_ops_put(struct nl_cache_ops *ops)
67 {
68  ops->co_refcnt--;
69 }
70 
71 /**
72  * Lookup cache operations by name
73  * @arg name name of the cache type
74  *
75  * @attention This function is not safe, it does not increment the reference
76  * counter. Please use nl_cache_ops_lookup_safe().
77  *
78  * @return The cache operations or NULL if not found.
79  */
80 struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
81 {
82  struct nl_cache_ops *ops;
83 
84  nl_read_lock(&cache_ops_lock);
85  ops = __nl_cache_ops_lookup(name);
86  nl_read_unlock(&cache_ops_lock);
87 
88  return ops;
89 }
90 
91 /**
92  * Lookup cache operations by name
93  * @arg name name of the cache type
94  *
95  * @note The reference counter of the returned cache operation is incremented
96  * and must be decremented after use with nl_cache_ops_put().
97  *
98  * @return The cache operations or NULL if not found.
99  */
100 struct nl_cache_ops *nl_cache_ops_lookup_safe(const char *name)
101 {
102  struct nl_cache_ops *ops;
103 
104  nl_write_lock(&cache_ops_lock);
105  if ((ops = __nl_cache_ops_lookup(name)))
106  nl_cache_ops_get(ops);
107  nl_write_unlock(&cache_ops_lock);
108 
109  return ops;
110 }
111 
112 static struct nl_cache_ops *__cache_ops_associate(int protocol, int msgtype)
113 {
114  int i;
115  struct nl_cache_ops *ops;
116 
117  for (ops = cache_ops; ops; ops = ops->co_next) {
118  if (ops->co_protocol != protocol)
119  continue;
120 
121  for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
122  if (ops->co_msgtypes[i].mt_id == msgtype)
123  return ops;
124  }
125 
126  return NULL;
127 }
128 
129 /**
130  * Associate protocol and message type to cache operations
131  * @arg protocol netlink protocol
132  * @arg msgtype netlink message type
133  *
134  * @attention This function is not safe, it does not increment the reference
135  * counter. Please use nl_cache_ops_associate_safe().
136  *
137  * @see nl_cache_ops_associate_safe()
138  *
139  * @return The cache operations or NULL if no match found.
140  */
141 struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
142 {
143  struct nl_cache_ops *ops;
144 
145  nl_read_lock(&cache_ops_lock);
146  ops = __cache_ops_associate(protocol, msgtype);
147  nl_read_unlock(&cache_ops_lock);
148 
149  return ops;
150 }
151 
152 /**
153  * Associate protocol and message type to cache operations
154  * @arg protocol netlink protocol
155  * @arg msgtype netlink message type
156  *
157  * Searches the registered cache operations for a matching protocol
158  * and message type.
159  *
160  * @note The reference counter of the returned cache operation is incremented
161  * and must be decremented after use with nl_cache_ops_put().
162  *
163  * @return The cache operations or NULL if no no match was found.
164  */
165 struct nl_cache_ops *nl_cache_ops_associate_safe(int protocol, int msgtype)
166 {
167  struct nl_cache_ops *ops;
168 
169  nl_write_lock(&cache_ops_lock);
170  if ((ops = __cache_ops_associate(protocol, msgtype)))
171  nl_cache_ops_get(ops);
172  nl_write_unlock(&cache_ops_lock);
173 
174  return ops;
175 }
176 
177 /**
178  * Lookup message type cache association
179  * @arg ops cache operations
180  * @arg msgtype netlink message type
181  *
182  * Searches for a matching message type association ing the specified
183  * cache operations.
184  *
185  * @attention The guranteed lifetime of the returned message type is bound
186  * to the lifetime of the underlying cache operations.
187  *
188  * @return A message type association or NULL.
189  */
190 struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
191 {
192  int i;
193 
194  for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
195  if (ops->co_msgtypes[i].mt_id == msgtype)
196  return &ops->co_msgtypes[i];
197 
198  return NULL;
199 }
200 
201 /* Must hold cache_ops_lock */
202 static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
203 {
204  struct nl_cache_ops *ops;
205 
206  for (ops = cache_ops; ops; ops = ops->co_next)
207  if (ops->co_obj_ops == obj_ops)
208  return ops;
209 
210  return NULL;
211 
212 }
213 
214 /**
215  * Call a function for each registered cache operation
216  * @arg cb Callback function to be called
217  * @arg arg User specific argument.
218  */
219 void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
220 {
221  struct nl_cache_ops *ops;
222 
223  nl_read_lock(&cache_ops_lock);
224  for (ops = cache_ops; ops; ops = ops->co_next)
225  cb(ops, arg);
226  nl_read_unlock(&cache_ops_lock);
227 }
228 
229 /**
230  * Set default flags for caches of this type
231  * @arg ops Cache ops
232  * @arg flags Flags to set
233  *
234  * The cache operation flags will be derived to all caches allocates
235  * based on this set of cache operations.
236  */
237 void nl_cache_ops_set_flags(struct nl_cache_ops *ops, unsigned int flags)
238 {
239  nl_write_lock(&cache_ops_lock);
240  ops->co_flags |= flags;
241  nl_write_unlock(&cache_ops_lock);
242 }
243 
244 /**
245  * Register a set of cache operations
246  * @arg ops cache operations
247  *
248  * Called by users of caches to announce the avaibility of
249  * a certain cache type.
250  *
251  * @return 0 on success or a negative error code.
252  */
253 int nl_cache_mngt_register(struct nl_cache_ops *ops)
254 {
255  if (!ops->co_name || !ops->co_obj_ops)
256  return -NLE_INVAL;
257 
258  /* oo_keygen() also needs oo_compare() */
259  BUG_ON (ops->co_obj_ops->oo_keygen && !ops->co_obj_ops->oo_compare);
260 
261  nl_write_lock(&cache_ops_lock);
262  if (__nl_cache_ops_lookup(ops->co_name)) {
263  nl_write_unlock(&cache_ops_lock);
264  return -NLE_EXIST;
265  }
266 
267  ops->co_refcnt = 0;
268  ops->co_next = cache_ops;
269  cache_ops = ops;
270  nl_write_unlock(&cache_ops_lock);
271 
272  NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
273 
274  return 0;
275 }
276 
277 /**
278  * Unregister a set of cache operations
279  * @arg ops cache operations
280  *
281  * Called by users of caches to announce a set of
282  * cache operations is no longer available. The
283  * specified cache operations must have been registered
284  * previously using nl_cache_mngt_register()
285  *
286  * @return 0 on success or a negative error code
287  */
288 int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
289 {
290  struct nl_cache_ops *t, **tp;
291  int err = 0;
292 
293  nl_write_lock(&cache_ops_lock);
294 
295  if (ops->co_refcnt > 0) {
296  err = -NLE_BUSY;
297  goto errout;
298  }
299 
300  for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
301  if (t == ops)
302  break;
303 
304  if (!t) {
305  err = -NLE_NOCACHE;
306  goto errout;
307  }
308 
309  NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
310 
311  *tp = t->co_next;
312 errout:
313  nl_write_unlock(&cache_ops_lock);
314 
315  return err;
316 }
317 
318 /** @} */
319 
320 /**
321  * @name Global Cache Provisioning/Requiring
322  * @{
323  */
324 
325 /**
326  * Provide a cache for global use
327  * @arg cache cache to provide
328  *
329  * Offers the specified cache to be used by other modules.
330  * Only one cache per type may be shared at a time,
331  * a previsouly provided caches will be overwritten.
332  */
333 void nl_cache_mngt_provide(struct nl_cache *cache)
334 {
335  struct nl_cache_ops *ops;
336 
337  nl_write_lock(&cache_ops_lock);
338 
339  ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
340  if (!ops)
341  BUG();
342  else {
343  nl_cache_get(cache);
344 
345  /*
346  * Hold a reference to the cache operations to ensure the
347  * ops don't go away while we use it to store the cache pointer.
348  */
349  if (!ops->co_major_cache)
350  nl_cache_ops_get(ops);
351 
352  ops->co_major_cache = cache;
353  }
354 
355  nl_write_unlock(&cache_ops_lock);
356 }
357 
358 /**
359  * Unprovide a cache for global use
360  * @arg cache cache to unprovide
361  *
362  * Cancels the offer to use a cache globally. The
363  * cache will no longer be returned via lookups but
364  * may still be in use.
365  */
366 void nl_cache_mngt_unprovide(struct nl_cache *cache)
367 {
368  struct nl_cache_ops *ops;
369 
370  nl_write_lock(&cache_ops_lock);
371 
372  ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
373  if (!ops)
374  BUG();
375  else if (ops->co_major_cache == cache) {
376  nl_cache_free(ops->co_major_cache);
377  nl_cache_ops_put(ops);
378  ops->co_major_cache = NULL;
379  }
380 
381  nl_write_unlock(&cache_ops_lock);
382 }
383 
384 struct nl_cache *__nl_cache_mngt_require(const char *name)
385 {
386  struct nl_cache_ops *ops;
387  struct nl_cache *cache = NULL;
388 
389  ops = nl_cache_ops_lookup_safe(name);
390  if (ops) {
391  cache = ops->co_major_cache;
392  nl_cache_ops_put(ops);
393  }
394 
395  return cache;
396 }
397 
398 /**
399  * Return cache previously provided via nl_cache_mngt_provide()
400  * @arg name Name of cache to lookup
401  *
402  * @attention This function is not safe, it does not increment the reference
403  * counter. Please use nl_cache_mngt_require_safe().
404  *
405  * @see nl_cache_mngt_require_safe()
406  *
407  * @return Pointer to cache or NULL if none registered
408  */
409 struct nl_cache *nl_cache_mngt_require(const char *name)
410 {
411  struct nl_cache *cache;
412 
413  if (!(cache = __nl_cache_mngt_require(name)))
414  NL_DBG(1, "Application BUG: Your application must "
415  "call nl_cache_mngt_provide() and\nprovide a valid "
416  "%s cache to be used for internal lookups.\nSee the "
417  " API documentation for more details.\n", name);
418 
419  return cache;
420 }
421 
422 /**
423  * Return cache previously provided via nl_cache_mngt_provide()
424  * @arg name Name of cache to lookup
425  *
426  * @note The reference counter of the returned cache is incremented
427  * and must be decremented after use with nl_cache_put().
428  *
429  * @return Pointer to cache or NULL if none registered
430  */
431 struct nl_cache *nl_cache_mngt_require_safe(const char *name)
432 {
433  struct nl_cache *cache;
434 
435  if ((cache = nl_cache_mngt_require(name)))
436  nl_cache_get(cache);
437 
438  return cache;
439 }
440 
441 /** @} */
442 
443 /** @} */
void nl_cache_mngt_provide(struct nl_cache *cache)
Provide a cache for global use.
Definition: cache_mngt.c:333
void nl_cache_ops_put(struct nl_cache_ops *ops)
Decrement reference counter.
Definition: cache_mngt.c:66
void nl_cache_ops_get(struct nl_cache_ops *ops)
Increment reference counter.
Definition: cache_mngt.c:57
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:288
struct nl_cache * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
Definition: cache_mngt.c:431
void nl_cache_get(struct nl_cache *cache)
Increase reference counter of cache.
Definition: cache.c:392
struct nl_cache_ops * nl_cache_ops_lookup(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:80
void nl_cache_free(struct nl_cache *cache)
Free a cache.
Definition: cache.c:409
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:253
struct nl_cache * nl_cache_mngt_require(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
Definition: cache_mngt.c:409
struct nl_cache_ops * nl_cache_ops_lookup_safe(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:100
void nl_cache_mngt_unprovide(struct nl_cache *cache)
Unprovide a cache for global use.
Definition: cache_mngt.c:366
void nl_cache_ops_set_flags(struct nl_cache_ops *ops, unsigned int flags)
Set default flags for caches of this type.
Definition: cache_mngt.c:237
void nl_cache_ops_foreach(void(*cb)(struct nl_cache_ops *, void *), void *arg)
Call a function for each registered cache operation.
Definition: cache_mngt.c:219
struct nl_cache_ops * nl_cache_ops_associate(int protocol, int msgtype)
Associate protocol and message type to cache operations.
Definition: cache_mngt.c:141
struct nl_msgtype * nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
Lookup message type cache association.
Definition: cache_mngt.c:190
struct nl_cache_ops * nl_cache_ops_associate_safe(int protocol, int msgtype)
Associate protocol and message type to cache operations.
Definition: cache_mngt.c:165