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 
22 static struct nl_cache_ops *cache_ops;
23 static NL_RW_LOCK(cache_ops_lock);
24 
25 /**
26  * @name Cache Operations Sets
27  * @{
28  */
29 
30 struct 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  */
45 void nl_cache_ops_get(struct nl_cache_ops *ops)
46 {
47  ops->co_refcnt++;
48 }
49 
50 /**
51  * Decrement reference counter
52  * @arg ops Cache operations
53  */
54 void nl_cache_ops_put(struct nl_cache_ops *ops)
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  */
68 struct 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  */
88 struct 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)))
94  nl_cache_ops_get(ops);
95  nl_write_unlock(&cache_ops_lock);
96 
97  return ops;
98 }
99 
100 static 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  */
129 struct 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  */
153 struct 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  */
178 struct 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 */
190 static 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  */
207 void 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  */
304 void 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  */
329 void 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  */
356 struct 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 /** @} */