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