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