• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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