libnl 3.7.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
27static struct nl_cache_ops *cache_ops;
28static NL_RW_LOCK(cache_ops_lock);
29
30/**
31 * @name Cache Operations Sets
32 * @{
33 */
34
35static 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 */
50void 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 */
59void 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 */
73struct 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 */
93struct 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)))
100 nl_write_unlock(&cache_ops_lock);
101
102 return ops;
103}
104
105static 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 */
134struct 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 */
158struct 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 */
183struct 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 */
195static 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 */
212void 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 */
230void 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 */
246int 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 */
281int 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;
305errout:
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 */
326void 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 */
359void 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
377struct 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 */
402struct 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 */
424struct 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
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
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 * nl_cache_mngt_require(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
Definition: cache_mngt.c:402
struct nl_cache_ops * nl_cache_ops_lookup(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:73
void nl_cache_mngt_provide(struct nl_cache *cache)
Provide a cache for global use.
Definition: cache_mngt.c:326
void nl_cache_ops_get(struct nl_cache_ops *ops)
Increment reference counter.
Definition: cache_mngt.c:50
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 * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
Definition: cache_mngt.c:424
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_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_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