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 
42 static NL_LIST_HEAD(info_ops);
43 
44 /* lock protecting info_ops and af_ops */
45 static NL_RW_LOCK(info_lock);
46 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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