libnl 1.1.4
cache_mngt.c
1/*
2 * lib/cache_mngt.c Cache Management
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @defgroup cache_mngt Caching
14 * @{
15 */
16
17#include <netlink-local.h>
18#include <netlink/netlink.h>
19#include <netlink/cache.h>
20#include <netlink/utils.h>
21
22static struct nl_cache_ops *cache_ops;
23static NL_RW_LOCK(cache_ops_lock);
24
25/**
26 * @name Cache Operations Sets
27 * @{
28 */
29
30struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
31{
32 struct nl_cache_ops *ops;
33
34 for (ops = cache_ops; ops; ops = ops->co_next)
35 if (!strcmp(ops->co_name, name))
36 return ops;
37
38 return NULL;
39}
40
41/**
42 * Increment reference counter
43 * @arg ops Cache operations
44 */
46{
47 ops->co_refcnt++;
48}
49
50/**
51 * Decrement reference counter
52 * @arg ops Cache operations
53 */
55{
56 ops->co_refcnt--;
57}
58
59/**
60 * Lookup cache operations by name
61 * @arg name name of the cache type
62 *
63 * @attention This function is not safe, it does not increment the reference
64 * counter. Please use nl_cache_ops_lookup_safe().
65 *
66 * @return The cache operations or NULL if not found.
67 */
68struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
69{
70 struct nl_cache_ops *ops;
71
72 nl_read_lock(&cache_ops_lock);
73 ops = __nl_cache_ops_lookup(name);
74 nl_read_unlock(&cache_ops_lock);
75
76 return ops;
77}
78
79/**
80 * Lookup cache operations by name
81 * @arg name name of the cache type
82 *
83 * @note The reference counter of the returned cache operation is incremented
84 * and must be decremented after use with nl_cache_ops_put().
85 *
86 * @return The cache operations or NULL if not found.
87 */
88struct nl_cache_ops *nl_cache_ops_lookup_safe(const char *name)
89{
90 struct nl_cache_ops *ops;
91
92 nl_write_lock(&cache_ops_lock);
93 if ((ops = __nl_cache_ops_lookup(name)))
95 nl_write_unlock(&cache_ops_lock);
96
97 return ops;
98}
99
100static struct nl_cache_ops *__cache_ops_associate(int protocol, int msgtype)
101{
102 int i;
103 struct nl_cache_ops *ops;
104
105 for (ops = cache_ops; ops; ops = ops->co_next) {
106 if (ops->co_protocol != protocol)
107 continue;
108
109 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
110 if (ops->co_msgtypes[i].mt_id == msgtype)
111 return ops;
112 }
113
114 return NULL;
115}
116
117/**
118 * Associate protocol and message type to cache operations
119 * @arg protocol netlink protocol
120 * @arg msgtype netlink message type
121 *
122 * @attention This function is not safe, it does not increment the reference
123 * counter. Please use nl_cache_ops_associate_safe().
124 *
125 * @see nl_cache_ops_associate_safe()
126 *
127 * @return The cache operations or NULL if no match found.
128 */
129struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
130{
131 struct nl_cache_ops *ops;
132
133 nl_read_lock(&cache_ops_lock);
134 ops = __cache_ops_associate(protocol, msgtype);
135 nl_read_unlock(&cache_ops_lock);
136
137 return ops;
138}
139
140/**
141 * Associate protocol and message type to cache operations
142 * @arg protocol netlink protocol
143 * @arg msgtype netlink message type
144 *
145 * Searches the registered cache operations for a matching protocol
146 * and message type.
147 *
148 * @note The reference counter of the returned cache operation is incremented
149 * and must be decremented after use with nl_cache_ops_put().
150 *
151 * @return The cache operations or NULL if no no match was found.
152 */
153struct nl_cache_ops *nl_cache_ops_associate_safe(int protocol, int msgtype)
154{
155 struct nl_cache_ops *ops;
156
157 nl_write_lock(&cache_ops_lock);
158 if ((ops = __cache_ops_associate(protocol, msgtype)))
159 nl_cache_ops_get(ops);
160 nl_write_unlock(&cache_ops_lock);
161
162 return ops;
163}
164
165/**
166 * Lookup message type cache association
167 * @arg ops cache operations
168 * @arg msgtype netlink message type
169 *
170 * Searches for a matching message type association ing the specified
171 * cache operations.
172 *
173 * @attention The guranteed lifetime of the returned message type is bound
174 * to the lifetime of the underlying cache operations.
175 *
176 * @return A message type association or NULL.
177 */
178struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
179{
180 int i;
181
182 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
183 if (ops->co_msgtypes[i].mt_id == msgtype)
184 return &ops->co_msgtypes[i];
185
186 return NULL;
187}
188
189/* Must hold cache_ops_lock */
190static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
191{
192 struct nl_cache_ops *ops;
193
194 for (ops = cache_ops; ops; ops = ops->co_next)
195 if (ops->co_obj_ops == obj_ops)
196 return ops;
197
198 return NULL;
199
200}
201
202/**
203 * Call a function for each registered cache operation
204 * @arg cb Callback function to be called
205 * @arg arg User specific argument.
206 */
207void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
208{
209 struct nl_cache_ops *ops;
210
211 nl_read_lock(&cache_ops_lock);
212 for (ops = cache_ops; ops; ops = ops->co_next)
213 cb(ops, arg);
214 nl_read_unlock(&cache_ops_lock);
215}
216
217/**
218 * Register a set of cache operations
219 * @arg ops cache operations
220 *
221 * Called by users of caches to announce the avaibility of
222 * a certain cache type.
223 *
224 * @return 0 on success or a negative error code.
225 */
227{
228 if (!ops->co_name)
229 return nl_error(EINVAL, "No cache name specified");
230
231 if (!ops->co_obj_ops)
232 return nl_error(EINVAL, "No obj cache ops specified");
233
234 nl_write_lock(&cache_ops_lock);
235 if (__nl_cache_ops_lookup(ops->co_name)) {
236 nl_write_unlock(&cache_ops_lock);
237 return nl_error(EEXIST, "Cache operations already exist");
238 }
239
240 ops->co_refcnt = 0;
241 ops->co_next = cache_ops;
242 cache_ops = ops;
243 nl_write_unlock(&cache_ops_lock);
244
245 NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
246
247 return 0;
248}
249
250/**
251 * Unregister a set of cache operations
252 * @arg ops cache operations
253 *
254 * Called by users of caches to announce a set of
255 * cache operations is no longer available. The
256 * specified cache operations must have been registered
257 * previously using nl_cache_mngt_register()
258 *
259 * @return 0 on success or a negative error code
260 */
262{
263 struct nl_cache_ops *t, **tp;
264
265 nl_write_lock(&cache_ops_lock);
266
267 if (ops->co_refcnt > 0) {
268 nl_write_unlock(&cache_ops_lock);
269 return nl_error(EBUSY, "Cache operations busy");
270 }
271
272 for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
273 if (t == ops)
274 break;
275
276 if (!t) {
277 nl_write_unlock(&cache_ops_lock);
278 return nl_error(ENOENT, "No such cache operations");
279 }
280
281 NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
282
283 *tp = t->co_next;
284 nl_write_unlock(&cache_ops_lock);
285
286 return 0;
287}
288
289/** @} */
290
291/**
292 * @name Global Cache Provisioning/Requiring
293 * @{
294 */
295
296/**
297 * Provide a cache for global use
298 * @arg cache cache to provide
299 *
300 * Offers the specified cache to be used by other modules.
301 * Only one cache per type may be shared at a time,
302 * a previsouly provided caches will be overwritten.
303 */
304void nl_cache_mngt_provide(struct nl_cache *cache)
305{
306 struct nl_cache_ops *ops;
307
308 nl_write_lock(&cache_ops_lock);
309
310 ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
311 if (!ops)
312 BUG();
313 else {
314 nl_cache_get(cache);
315 ops->co_major_cache = cache;
316 }
317
318 nl_write_unlock(&cache_ops_lock);
319}
320
321/**
322 * Unprovide a cache for global use
323 * @arg cache cache to unprovide
324 *
325 * Cancels the offer to use a cache globally. The
326 * cache will no longer be returned via lookups but
327 * may still be in use.
328 */
329void nl_cache_mngt_unprovide(struct nl_cache *cache)
330{
331 struct nl_cache_ops *ops;
332
333 nl_write_lock(&cache_ops_lock);
334
335 ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
336 if (!ops)
337 BUG();
338 else if (ops->co_major_cache == cache) {
339 nl_cache_free(ops->co_major_cache);
340 ops->co_major_cache = NULL;
341 }
342
343 nl_write_unlock(&cache_ops_lock);
344}
345
346/**
347 * Demand the use of a global cache
348 * @arg name name of the required object type
349 *
350 * Trys to find a cache of the specified type for global
351 * use.
352 *
353 * @return A cache provided by another subsystem of the
354 * specified type marked to be available.
355 */
356struct nl_cache *nl_cache_mngt_require(const char *name)
357{
358 struct nl_cache_ops *ops;
359
360 ops = nl_cache_ops_lookup(name);
361 if (!ops || !ops->co_major_cache) {
362 fprintf(stderr, "Application BUG: Your application must "
363 "call nl_cache_mngt_provide() and\nprovide a valid "
364 "%s cache to be used for internal lookups.\nSee the "
365 " API documentation for more details.\n", name);
366
367 return NULL;
368 }
369
370 return ops->co_major_cache;
371}
372
373/** @} */
374
375/** @} */
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:261
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:207
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:226
void nl_cache_mngt_unprovide(struct nl_cache *cache)
Unprovide a cache for global use.
Definition: cache_mngt.c:329
struct nl_cache_ops * nl_cache_ops_associate(int protocol, int msgtype)
Associate protocol and message type to cache operations.
Definition: cache_mngt.c:129
struct nl_cache * nl_cache_mngt_require(const char *name)
Demand the use of a global cache.
Definition: cache_mngt.c:356
struct nl_cache_ops * nl_cache_ops_lookup(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:68
void nl_cache_mngt_provide(struct nl_cache *cache)
Provide a cache for global use.
Definition: cache_mngt.c:304
void nl_cache_ops_get(struct nl_cache_ops *ops)
Increment reference counter.
Definition: cache_mngt.c:45
struct nl_msgtype * nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
Lookup message type cache association.
Definition: cache_mngt.c:178
struct nl_cache_ops * nl_cache_ops_lookup_safe(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:88
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:153
void nl_cache_ops_put(struct nl_cache_ops *ops)
Decrement reference counter.
Definition: cache_mngt.c:54
void nl_cache_free(struct nl_cache *cache)
Free a cache.
Definition: cache.c:277
void nl_cache_get(struct nl_cache *cache)
Increase reference counter of cache.
Definition: cache.c:264
Cache Operations.
Definition: cache-api.h:164
unsigned int co_refcnt
Reference counter.
Definition: cache-api.h:193
Message type to cache action association.
Definition: cache-api.h:129
int mt_id
Netlink message type.
Definition: cache-api.h:131
Object Operations.
Definition: object-api.h:255