libnl 3.10.0
api.c
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 _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
45static NL_LIST_HEAD(info_ops);
46
47/* lock protecting info_ops and af_ops */
48static NL_RW_LOCK(info_lock);
49
50static 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 */
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 */
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 */
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 */
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);
143errout:
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 */
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
186errout:
187 nl_write_unlock(&info_lock);
188
189 return err;
190}
191
192/** @} */
193
194/**
195 * @name Link Address Family Modules
196 * @{
197 */
198
199static 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 */
209struct 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 */
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 */
249void *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 */
284void *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 */
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
324errout:
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 */
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
367errout:
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 */
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
408out:
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 */
425int 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