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