libnl  3.6.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  ops->ao_refcnt--;
227 }
228 
229 /**
230  * Allocate and return data buffer for link address family modules
231  * @arg link Link object
232  * @arg ops Address family operations
233  *
234  * This function must be called by link address family modules in all
235  * cases where the API does not provide the data buffer as argument
236  * already. This typically includes set functions the module provides.
237  * Calling this function is strictly required to ensure proper allocation
238  * of the buffer upon first use. Link objects will NOT proactively
239  * allocate a data buffer for each registered link address family.
240  *
241  * @return Pointer to data buffer or NULL on error.
242  */
243 void *rtnl_link_af_alloc(struct rtnl_link *link,
244  const struct rtnl_link_af_ops *ops)
245 {
246  int family;
247 
248  if (!link || !ops)
249  BUG();
250 
251  family = ops->ao_family;
252 
253  if (!link->l_af_data[family]) {
254  if (!ops->ao_alloc)
255  BUG();
256 
257  link->l_af_data[family] = ops->ao_alloc(link);
258  if (!link->l_af_data[family])
259  return NULL;
260  }
261 
262  return link->l_af_data[family];
263 }
264 
265 /**
266  * Return data buffer for link address family modules
267  * @arg link Link object
268  * @arg ops Address family operations
269  *
270  * This function returns a pointer to the data buffer for the specified link
271  * address family module or NULL if the buffer was not allocated yet. This
272  * function is typically used by get functions of modules which are not
273  * interested in having the data buffer allocated if no values have been set
274  * yet.
275  *
276  * @return Pointer to data buffer or NULL on error.
277  */
278 void *rtnl_link_af_data(const struct rtnl_link *link,
279  const struct rtnl_link_af_ops *ops)
280 {
281  if (!link || !ops)
282  BUG();
283 
284  return link->l_af_data[ops->ao_family];
285 }
286 
287 /**
288  * Register operations for a link address family
289  * @arg ops Address family operations
290  *
291  * This function must be called by modules implementing a specific link
292  * address family. It will make the operations implemented by the module
293  * available for everyone else.
294  *
295  * @return 0 on success or a negative error code.
296  * @return -NLE_INVAL Address family is out of range (0..AF_MAX)
297  * @return -NLE_EXIST Operations for address family already registered.
298  */
299 int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
300 {
301  int err = 0;
302 
303  if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
304  return -NLE_INVAL;
305 
306  nl_write_lock(&info_lock);
307  if (af_ops[ops->ao_family]) {
308  err = -NLE_EXIST;
309  goto errout;
310  }
311 
312  ops->ao_refcnt = 0;
313  af_ops[ops->ao_family] = ops;
314 
315  NL_DBG(1, "Registered link address family operations %u\n",
316  ops->ao_family);
317 
318 errout:
319  nl_write_unlock(&info_lock);
320 
321  return err;
322 }
323 
324 /**
325  * Unregister operations for a link address family
326  * @arg ops Address family operations
327  *
328  * This function must be called if a module implementing a specific link
329  * address family is unloaded or becomes unavailable. It must provide a
330  * set of operations which have previously been registered using
331  * rtnl_link_af_register().
332  *
333  * @return 0 on success or a negative error code
334  * @return -NLE_INVAL ops is NULL
335  * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
336  * @return -NLE_BUSY Address family operations still in use.
337  */
338 int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
339 {
340  int err = -NLE_INVAL;
341 
342  if (!ops)
343  return err;
344 
345  nl_write_lock(&info_lock);
346  if (!af_ops[ops->ao_family]) {
347  err = -NLE_OBJ_NOTFOUND;
348  goto errout;
349  }
350 
351  if (ops->ao_refcnt > 0) {
352  err = -NLE_BUSY;
353  goto errout;
354  }
355 
356  af_ops[ops->ao_family] = NULL;
357 
358  NL_DBG(1, "Unregistered link address family operations %u\n",
359  ops->ao_family);
360 
361 errout:
362  nl_write_unlock(&info_lock);
363 
364  return err;
365 }
366 
367 /**
368  * Compare af data for a link address family
369  * @arg a Link object a
370  * @arg b Link object b
371  * @arg family af data family
372  *
373  * This function will compare af_data between two links
374  * a and b of family given by arg family
375  *
376  * @return 0 if address family specific data matches or is not present
377  * or != 0 if it mismatches.
378  */
380  int family)
381 {
382  struct rtnl_link_af_ops *af_ops;
383  int ret = 0;
384 
385  if (!a->l_af_data[family] && !b->l_af_data[family])
386  return 0;
387 
388  if (!a->l_af_data[family] || !b->l_af_data[family])
389  return ~0;
390 
391  af_ops = rtnl_link_af_ops_lookup(family);
392  if (!af_ops)
393  return ~0;
394 
395  if (af_ops->ao_compare == NULL) {
396  ret = ~0;
397  goto out;
398  }
399 
400  ret = af_ops->ao_compare(a, b, family, ~0, 0);
401 
402 out:
403  rtnl_link_af_ops_put(af_ops);
404 
405  return ret;
406 }
407 
408 /**
409  * Compare link info data
410  * @arg a Link object a
411  * @arg b Link object b
412  *
413  * This function will compare link_info data between two links
414  * a and b
415  *
416  * @return 0 if link_info data matches or is not present
417  * or != 0 if it mismatches.
418  */
419 int rtnl_link_info_data_compare(struct rtnl_link *a, struct rtnl_link *b, int flags)
420 {
421  if (a->l_info_ops != b->l_info_ops)
422  return ~0;
423 
424  if (!a->l_info_ops || !a->l_info_ops->io_compare)
425  return 0;
426 
427  return a->l_info_ops->io_compare(a, b, flags);
428 }
429 
430 /** @} */
431 
432 /** @} */
433