1 /*
2 * lib/route/link/api.c Link Info API
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 link
14 * @defgroup link_API Link Modules API
15 * @brief API for modules implementing specific link types/semantics.
16 *
17 * @par 1) Registering/Unregistering a new link info type
18 * @code
19 * static struct rtnl_link_info_ops vlan_info_ops = {
20 * .io_name = "vlan",
21 * .io_alloc = vlan_alloc,
22 * .io_parse = vlan_parse,
23 * .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief,
24 * .io_dump[NL_DUMP_FULL] = vlan_dump_full,
25 * .io_free = vlan_free,
26 * };
27 *
28 * static void __init vlan_init(void)
29 * {
30 * rtnl_link_register_info(&vlan_info_ops);
31 * }
32 *
33 * static void __exit vlan_exit(void)
34 * {
35 * rtnl_link_unregister_info(&vlan_info_ops);
36 * }
37 * @endcode
38 *
39 * @{
40 */
41
42 #include <netlink-private/netlink.h>
43 #include <netlink/netlink.h>
44 #include <netlink/utils.h>
45 #include <netlink/route/link.h>
46 #include <netlink-private/route/link/api.h>
47
48 static NL_LIST_HEAD(info_ops);
49
50 /* lock protecting info_ops and af_ops */
51 static NL_RW_LOCK(info_lock);
52
__rtnl_link_info_ops_lookup(const char * name)53 static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
54 {
55 struct rtnl_link_info_ops *ops;
56
57 nl_list_for_each_entry(ops, &info_ops, io_list)
58 if (!strcmp(ops->io_name, name))
59 return ops;
60
61 return NULL;
62 }
63
64 /**
65 * @name Link Info Modules
66 * @{
67 */
68
69 /**
70 * Return operations of a specific link info type
71 * @arg name Name of link info type.
72 *
73 * @note The returned pointer must be given back using rtnl_link_info_ops_put()
74 *
75 * @return Pointer to operations or NULL if unavailable.
76 */
rtnl_link_info_ops_lookup(const char * name)77 struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
78 {
79 struct rtnl_link_info_ops *ops;
80
81 nl_write_lock(&info_lock);
82 if ((ops = __rtnl_link_info_ops_lookup(name)))
83 ops->io_refcnt++;
84 nl_write_unlock(&info_lock);
85
86 return ops;
87 }
88
89 /**
90 * Give back reference to a set of operations.
91 * @arg ops Link info operations.
92 */
rtnl_link_info_ops_put(struct rtnl_link_info_ops * ops)93 void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
94 {
95 if (ops)
96 ops->io_refcnt--;
97 }
98
99 /**
100 * Register operations for a link info type
101 * @arg ops Link info operations
102 *
103 * This function must be called by modules implementing a specific link
104 * info type. It will make the operations implemented by the module
105 * available for everyone else.
106 *
107 * @return 0 on success or a negative error code.
108 * @return -NLE_INVAL Link info name not specified.
109 * @return -NLE_EXIST Operations for address family already registered.
110 */
rtnl_link_register_info(struct rtnl_link_info_ops * ops)111 int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
112 {
113 int err = 0;
114
115 if (ops->io_name == NULL)
116 return -NLE_INVAL;
117
118 nl_write_lock(&info_lock);
119 if (__rtnl_link_info_ops_lookup(ops->io_name)) {
120 err = -NLE_EXIST;
121 goto errout;
122 }
123
124 NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
125
126 nl_list_add_tail(&ops->io_list, &info_ops);
127 errout:
128 nl_write_unlock(&info_lock);
129
130 return err;
131 }
132
133 /**
134 * Unregister operations for a link info type
135 * @arg ops Link info operations
136 *
137 * This function must be called if a module implementing a specific link
138 * info type is unloaded or becomes unavailable. It must provide a
139 * set of operations which have previously been registered using
140 * rtnl_link_register_info().
141 *
142 * @return 0 on success or a negative error code
143 * @return _NLE_OPNOTSUPP Link info operations not registered.
144 * @return -NLE_BUSY Link info operations still in use.
145 */
rtnl_link_unregister_info(struct rtnl_link_info_ops * ops)146 int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
147 {
148 struct rtnl_link_info_ops *t;
149 int err = -NLE_OPNOTSUPP;
150
151 nl_write_lock(&info_lock);
152
153 nl_list_for_each_entry(t, &info_ops, io_list) {
154 if (t == ops) {
155 if (t->io_refcnt > 0) {
156 err = -NLE_BUSY;
157 goto errout;
158 }
159
160 nl_list_del(&t->io_list);
161
162 NL_DBG(1, "Unregistered link info operations %s\n",
163 ops->io_name);
164 err = 0;
165 goto errout;
166 }
167 }
168
169 errout:
170 nl_write_unlock(&info_lock);
171
172 return err;
173 }
174
175 /** @} */
176
177 /**
178 * @name Link Address Family Modules
179 * @{
180 */
181
182 static struct rtnl_link_af_ops *af_ops[AF_MAX];
183
184 /**
185 * Return operations of a specific link address family
186 * @arg family Address family
187 *
188 * @note The returned pointer must be given back using rtnl_link_af_ops_put()
189 *
190 * @return Pointer to operations or NULL if unavailable.
191 */
rtnl_link_af_ops_lookup(const unsigned int family)192 struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
193 {
194 if (family == AF_UNSPEC || family >= AF_MAX)
195 return NULL;
196
197 nl_write_lock(&info_lock);
198 if (af_ops[family])
199 af_ops[family]->ao_refcnt++;
200 nl_write_unlock(&info_lock);
201
202 return af_ops[family];
203 }
204
205 /**
206 * Give back reference to a set of operations.
207 * @arg ops Address family operations.
208 */
rtnl_link_af_ops_put(struct rtnl_link_af_ops * ops)209 void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
210 {
211 if (ops)
212 ops->ao_refcnt--;
213 }
214
215 /**
216 * Allocate and return data buffer for link address family modules
217 * @arg link Link object
218 * @arg ops Address family operations
219 *
220 * This function must be called by link address family modules in all
221 * cases where the API does not provide the data buffer as argument
222 * already. This typically includes set functions the module provides.
223 * Calling this function is strictly required to ensure proper allocation
224 * of the buffer upon first use. Link objects will NOT proactively
225 * allocate a data buffer for each registered link address family.
226 *
227 * @return Pointer to data buffer or NULL on error.
228 */
rtnl_link_af_alloc(struct rtnl_link * link,const struct rtnl_link_af_ops * ops)229 void *rtnl_link_af_alloc(struct rtnl_link *link,
230 const struct rtnl_link_af_ops *ops)
231 {
232 int family;
233
234 if (!link || !ops)
235 BUG();
236
237 family = ops->ao_family;
238
239 if (!link->l_af_data[family]) {
240 if (!ops->ao_alloc)
241 BUG();
242
243 link->l_af_data[family] = ops->ao_alloc(link);
244 if (!link->l_af_data[family])
245 return NULL;
246 }
247
248 return link->l_af_data[family];
249 }
250
251 /**
252 * Return data buffer for link address family modules
253 * @arg link Link object
254 * @arg ops Address family operations
255 *
256 * This function returns a pointer to the data buffer for the specified link
257 * address family module or NULL if the buffer was not allocated yet. This
258 * function is typically used by get functions of modules which are not
259 * interested in having the data buffer allocated if no values have been set
260 * yet.
261 *
262 * @return Pointer to data buffer or NULL on error.
263 */
rtnl_link_af_data(const struct rtnl_link * link,const struct rtnl_link_af_ops * ops)264 void *rtnl_link_af_data(const struct rtnl_link *link,
265 const struct rtnl_link_af_ops *ops)
266 {
267 if (!link || !ops)
268 BUG();
269
270 return link->l_af_data[ops->ao_family];
271 }
272
273 /**
274 * Register operations for a link address family
275 * @arg ops Address family operations
276 *
277 * This function must be called by modules implementing a specific link
278 * address family. It will make the operations implemented by the module
279 * available for everyone else.
280 *
281 * @return 0 on success or a negative error code.
282 * @return -NLE_INVAL Address family is out of range (0..AF_MAX)
283 * @return -NLE_EXIST Operations for address family already registered.
284 */
rtnl_link_af_register(struct rtnl_link_af_ops * ops)285 int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
286 {
287 int err = 0;
288
289 if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
290 return -NLE_INVAL;
291
292 nl_write_lock(&info_lock);
293 if (af_ops[ops->ao_family]) {
294 err = -NLE_EXIST;
295 goto errout;
296 }
297
298 ops->ao_refcnt = 0;
299 af_ops[ops->ao_family] = ops;
300
301 NL_DBG(1, "Registered link address family operations %u\n",
302 ops->ao_family);
303
304 errout:
305 nl_write_unlock(&info_lock);
306
307 return err;
308 }
309
310 /**
311 * Unregister operations for a link address family
312 * @arg ops Address family operations
313 *
314 * This function must be called if a module implementing a specific link
315 * address family is unloaded or becomes unavailable. It must provide a
316 * set of operations which have previously been registered using
317 * rtnl_link_af_register().
318 *
319 * @return 0 on success or a negative error code
320 * @return -NLE_INVAL ops is NULL
321 * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
322 * @return -NLE_BUSY Address family operations still in use.
323 */
rtnl_link_af_unregister(struct rtnl_link_af_ops * ops)324 int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
325 {
326 int err = -NLE_INVAL;
327
328 if (!ops)
329 return err;
330
331 nl_write_lock(&info_lock);
332 if (!af_ops[ops->ao_family]) {
333 err = -NLE_OBJ_NOTFOUND;
334 goto errout;
335 }
336
337 if (ops->ao_refcnt > 0) {
338 err = -NLE_BUSY;
339 goto errout;
340 }
341
342 af_ops[ops->ao_family] = NULL;
343
344 NL_DBG(1, "Unregistered link address family operations %u\n",
345 ops->ao_family);
346
347 errout:
348 nl_write_unlock(&info_lock);
349
350 return err;
351 }
352
353 /**
354 * Compare af data for a link address family
355 * @arg a Link object a
356 * @arg b Link object b
357 * @arg family af data family
358 *
359 * This function will compare af_data between two links
360 * a and b of family given by arg family
361 *
362 * @return 0 if address family specific data matches or is not present
363 * or != 0 if it mismatches.
364 */
rtnl_link_af_data_compare(struct rtnl_link * a,struct rtnl_link * b,int family)365 int rtnl_link_af_data_compare(struct rtnl_link *a, struct rtnl_link *b,
366 int family)
367 {
368 struct rtnl_link_af_ops *af_ops;
369 int ret = 0;
370
371 if (!a->l_af_data[family] && !b->l_af_data[family])
372 return 0;
373
374 if (!a->l_af_data[family] || !b->l_af_data[family])
375 return ~0;
376
377 af_ops = rtnl_link_af_ops_lookup(family);
378 if (!af_ops)
379 return ~0;
380
381 if (af_ops->ao_compare == NULL) {
382 ret = ~0;
383 goto out;
384 }
385
386 ret = af_ops->ao_compare(a, b, family, ~0, 0);
387
388 out:
389 rtnl_link_af_ops_put(af_ops);
390
391 return ret;
392 }
393
394 /** @} */
395
396 /** @} */
397
398