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