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
__nl_cache_ops_lookup(const char * name)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 */
nl_cache_ops_get(struct nl_cache_ops * ops)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 */
nl_cache_ops_put(struct nl_cache_ops * ops)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 */
nl_cache_ops_lookup(const char * name)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 */
nl_cache_ops_lookup_safe(const char * name)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
__cache_ops_associate(int protocol,int msgtype)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 */
nl_cache_ops_associate(int protocol,int msgtype)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 */
nl_cache_ops_associate_safe(int protocol,int msgtype)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 */
nl_msgtype_lookup(struct nl_cache_ops * ops,int msgtype)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 */
cache_ops_lookup_for_obj(struct nl_object_ops * obj_ops)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 */
nl_cache_ops_foreach(void (* cb)(struct nl_cache_ops *,void *),void * arg)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 */
nl_cache_ops_set_flags(struct nl_cache_ops * ops,unsigned int flags)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 */
nl_cache_mngt_register(struct nl_cache_ops * ops)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 */
nl_cache_mngt_unregister(struct nl_cache_ops * ops)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 */
nl_cache_mngt_provide(struct nl_cache * cache)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 */
nl_cache_mngt_unprovide(struct nl_cache * cache)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
__nl_cache_mngt_require(const char * name)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 */
nl_cache_mngt_require(const char * name)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 */
nl_cache_mngt_require_safe(const char * name)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 /** @} */
437