cache_mngt.c revision d36d396fd0ae94aa2269546a02b5973b4ec27775
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;
23
24/**
25 * @name Cache Operations Sets
26 * @{
27 */
28
29/**
30 * Lookup the set cache operations of a certain cache type
31 * @arg name		name of the cache type
32 *
33 * @return The cache operations or NULL if no operations
34 *         have been registered under the specified name.
35 */
36struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
37{
38	struct nl_cache_ops *ops;
39
40	for (ops = cache_ops; ops; ops = ops->co_next)
41		if (!strcmp(ops->co_name, name))
42			return ops;
43
44	return NULL;
45}
46
47/**
48 * Associate a message type to a set of cache operations
49 * @arg protocol		netlink protocol
50 * @arg msgtype			netlink message type
51 *
52 * Associates the specified netlink message type with
53 * a registered set of cache operations.
54 *
55 * @return The cache operations or NULL if no association
56 *         could be made.
57 */
58struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
59{
60	int i;
61	struct nl_cache_ops *ops;
62
63	for (ops = cache_ops; ops; ops = ops->co_next)
64		for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
65			if (ops->co_msgtypes[i].mt_id == msgtype &&
66			    ops->co_protocol == protocol)
67				return ops;
68
69	return NULL;
70}
71
72/**
73 * Lookup message type cache association
74 * @arg ops			cache operations
75 * @arg msgtype			netlink message type
76 *
77 * Searches for a matching message type association ing the specified
78 * cache operations.
79 *
80 * @return A message type association or NULL.
81 */
82struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
83{
84	int i;
85
86	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
87		if (ops->co_msgtypes[i].mt_id == msgtype)
88			return &ops->co_msgtypes[i];
89
90	return NULL;
91}
92
93static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
94{
95	struct nl_cache_ops *ops;
96
97	for (ops = cache_ops; ops; ops = ops->co_next)
98		if (ops->co_obj_ops == obj_ops)
99			return ops;
100
101	return NULL;
102
103}
104
105/**
106 * Call a function for each registered cache operation
107 * @arg cb		Callback function to be called
108 * @arg arg		User specific argument.
109 */
110void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
111{
112	struct nl_cache_ops *ops;
113
114	for (ops = cache_ops; ops; ops = ops->co_next)
115		cb(ops, arg);
116}
117
118/**
119 * Register a set of cache operations
120 * @arg ops		cache operations
121 *
122 * Called by users of caches to announce the avaibility of
123 * a certain cache type.
124 *
125 * @return 0 on success or a negative error code.
126 */
127int nl_cache_mngt_register(struct nl_cache_ops *ops)
128{
129	if (!ops->co_name)
130		return nl_error(EINVAL, "No cache name specified");
131
132	if (!ops->co_obj_ops)
133		return nl_error(EINVAL, "No obj cache ops specified");
134
135	if (nl_cache_ops_lookup(ops->co_name))
136		return nl_error(EEXIST, "Cache operations already exist");
137
138	ops->co_next = cache_ops;
139	cache_ops = ops;
140
141	NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
142
143	return 0;
144}
145
146/**
147 * Unregister a set of cache operations
148 * @arg ops		cache operations
149 *
150 * Called by users of caches to announce a set of
151 * cache operations is no longer available. The
152 * specified cache operations must have been registered
153 * previously using nl_cache_mngt_register()
154 *
155 * @return 0 on success or a negative error code
156 */
157int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
158{
159	struct nl_cache_ops *t, **tp;
160
161	for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
162		if (t == ops)
163			break;
164
165	if (!t)
166		return nl_error(ENOENT, "No such cache operations");
167
168	NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
169
170	*tp = t->co_next;
171	return 0;
172}
173
174/** @} */
175
176/**
177 * @name Global Cache Provisioning/Requiring
178 * @{
179 */
180
181/**
182 * Provide a cache for global use
183 * @arg cache		cache to provide
184 *
185 * Offers the specified cache to be used by other modules.
186 * Only one cache per type may be shared at a time,
187 * a previsouly provided caches will be overwritten.
188 */
189void nl_cache_mngt_provide(struct nl_cache *cache)
190{
191	struct nl_cache_ops *ops;
192
193	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
194	if (!ops)
195		BUG();
196	else
197		ops->co_major_cache = cache;
198}
199
200/**
201 * Unprovide a cache for global use
202 * @arg cache		cache to unprovide
203 *
204 * Cancels the offer to use a cache globally. The
205 * cache will no longer be returned via lookups but
206 * may still be in use.
207 */
208void nl_cache_mngt_unprovide(struct nl_cache *cache)
209{
210	struct nl_cache_ops *ops;
211
212	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
213	if (!ops)
214		BUG();
215	else if (ops->co_major_cache == cache)
216		ops->co_major_cache = NULL;
217}
218
219/**
220 * Demand the use of a global cache
221 * @arg name		name of the required object type
222 *
223 * Trys to find a cache of the specified type for global
224 * use.
225 *
226 * @return A cache provided by another subsystem of the
227 *         specified type marked to be available.
228 */
229struct nl_cache *nl_cache_mngt_require(const char *name)
230{
231	struct nl_cache_ops *ops;
232
233	ops = nl_cache_ops_lookup(name);
234	if (!ops || !ops->co_major_cache) {
235		fprintf(stderr, "Application BUG: Your application must "
236			"call nl_cache_mngt_provide() and\nprovide a valid "
237			"%s cache to be used for internal lookups.\nSee the "
238			" API documentation for more details.\n", name);
239
240		return NULL;
241	}
242
243	return ops->co_major_cache;
244}
245
246/** @} */
247
248/** @} */
249