libnl 3.7.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 __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
42static NL_LIST_HEAD(info_ops);
43
44/* lock protecting info_ops and af_ops */
45static NL_RW_LOCK(info_lock);
46
47static 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 */
71struct 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 */
87void 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 */
101void 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 */
124int 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);
140errout:
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 */
159int 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
183errout:
184 nl_write_unlock(&info_lock);
185
186 return err;
187}
188
189/** @} */
190
191/**
192 * @name Link Address Family Modules
193 * @{
194 */
195
196static 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 */
206struct 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 */
223void 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 */
246void *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 */
281void *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 */
302int 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
321errout:
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 */
341int 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
364errout:
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 */
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
405out:
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 */
422int 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