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