libnl  3.5.0
netconf.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/route/netconf.c netconf
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation version 2.1
8  * of the License.
9  *
10  * Copyright (c) 2017 David Ahern <dsa@cumulusnetworks.com>
11  */
12 
13 /**
14  * @ingroup rtnl
15  * @defgroup netconf Netconf
16  * @brief
17  *
18  * @{
19  */
20 
21 #include <netlink-private/netlink.h>
22 #include <netlink/netlink.h>
23 #include <netlink/utils.h>
24 #include <netlink/route/netconf.h>
25 #include <linux/netconf.h>
26 #include <linux/socket.h>
27 #include <netlink/hashtable.h>
28 
29 /** @cond SKIP */
30 #define NETCONF_ATTR_FAMILY 0x0001
31 #define NETCONF_ATTR_IFINDEX 0x0002
32 #define NETCONF_ATTR_RP_FILTER 0x0004
33 #define NETCONF_ATTR_FWDING 0x0008
34 #define NETCONF_ATTR_MC_FWDING 0x0010
35 #define NETCONF_ATTR_PROXY_NEIGH 0x0020
36 #define NETCONF_ATTR_IGNORE_RT_LINKDWN 0x0040
37 #define NETCONF_ATTR_INPUT 0x0080
38 
39 struct rtnl_netconf
40 {
41  NLHDR_COMMON
42 
43  int family;
44  int ifindex;
45  int rp_filter;
46  int forwarding;
47  int mc_forwarding;
48  int proxy_neigh;
49  int ignore_routes_linkdown;
50  int input;
51 };
52 
53 static struct nl_cache_ops rtnl_netconf_ops;
54 static struct nl_object_ops netconf_obj_ops;
55 /** @endcond */
56 
57 static struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
58  [NETCONFA_IFINDEX] = { .type = NLA_S32 },
59  [NETCONFA_FORWARDING] = { .type = NLA_S32 },
60  [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 },
61  [NETCONFA_RP_FILTER] = { .type = NLA_S32 },
62  [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 },
63  [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 },
64 };
65 
66 static struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
67  [NETCONFA_IFINDEX] = { .type = NLA_S32 },
68  [NETCONFA_FORWARDING] = { .type = NLA_S32 },
69  [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 },
70  [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 },
71  [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 },
72 };
73 
74 static struct nla_policy devconf_mpls_policy[NETCONFA_MAX+1] = {
75  [NETCONFA_IFINDEX] = { .type = NLA_S32 },
76  [NETCONFA_INPUT] = { .type = NLA_S32 },
77 };
78 
79 static struct rtnl_netconf *rtnl_netconf_alloc(void)
80 {
81  return (struct rtnl_netconf *) nl_object_alloc(&netconf_obj_ops);
82 }
83 
84 static int netconf_clone(struct nl_object *_dst, struct nl_object *_src)
85 {
86  struct rtnl_netconf *dst = nl_object_priv(_dst);
87  struct rtnl_netconf *src = nl_object_priv(_src);
88 
89  *dst = *src;
90 
91  return 0;
92 }
93 
94 static int netconf_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
95  struct nlmsghdr *nlh, struct nl_parser_param *pp)
96 {
97  struct nlattr *tb[NETCONFA_MAX+1], *attr;
98  struct rtnl_netconf *nc;
99  struct netconfmsg *ncm;
100  int err;
101 
102  ncm = nlmsg_data(nlh);
103  switch (ncm->ncm_family) {
104  case AF_INET:
105  err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
106  devconf_ipv4_policy);
107  if (err < 0)
108  return err;
109  break;
110  case AF_INET6:
111  err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
112  devconf_ipv6_policy);
113  if (err < 0)
114  return err;
115  break;
116  case AF_MPLS:
117  err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
118  devconf_mpls_policy);
119  if (err < 0)
120  return err;
121  break;
122  default:
123  printf("unexpected netconf family: %d\n", ncm->ncm_family);
124  return -1;
125  }
126 
127  if (!tb[NETCONFA_IFINDEX])
128  return -1;
129 
130  nc = rtnl_netconf_alloc();
131  if (!nc)
132  return -NLE_NOMEM;
133 
134  nc->ce_msgtype = nlh->nlmsg_type;
135  nc->family = ncm->ncm_family;
136  nc->ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
137 
138  nc->ce_mask = NETCONF_ATTR_FAMILY | NETCONF_ATTR_IFINDEX;
139 
140 
141  if (tb[NETCONFA_RP_FILTER]) {
142  attr = tb[NETCONFA_RP_FILTER];
143  nc->rp_filter = nla_get_s32(attr);
144  nc->ce_mask |= NETCONF_ATTR_RP_FILTER;
145  }
146 
147  if (tb[NETCONFA_FORWARDING]) {
148  attr = tb[NETCONFA_FORWARDING];
149  nc->forwarding = nla_get_s32(attr);
150  nc->ce_mask |= NETCONF_ATTR_FWDING;
151  }
152 
153  if (tb[NETCONFA_MC_FORWARDING]) {
154  attr = tb[NETCONFA_MC_FORWARDING];
155  nc->mc_forwarding = nla_get_s32(attr);
156  nc->ce_mask |= NETCONF_ATTR_MC_FWDING;
157  }
158 
159  if (tb[NETCONFA_PROXY_NEIGH]) {
160  attr = tb[NETCONFA_PROXY_NEIGH];
161  nc->proxy_neigh = nla_get_s32(attr);
162  nc->ce_mask |= NETCONF_ATTR_PROXY_NEIGH;
163  }
164 
165  if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) {
166  attr = tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN];
167  nc->ignore_routes_linkdown = nla_get_s32(attr);
168  nc->ce_mask |= NETCONF_ATTR_IGNORE_RT_LINKDWN;
169  }
170 
171  if (tb[NETCONFA_INPUT]) {
172  attr = tb[NETCONFA_INPUT];
173  nc->input = nla_get_s32(attr);
174  nc->ce_mask |= NETCONF_ATTR_INPUT;
175  }
176 
177  err = pp->pp_cb((struct nl_object *) nc, pp);
178 
179  rtnl_netconf_put(nc);
180  return err;
181 }
182 
183 static int netconf_request_update(struct nl_cache *cache, struct nl_sock *sk)
184 {
185  struct netconfmsg nc = {
186  .ncm_family = cache->c_iarg1,
187  };
188 
189  return nl_send_simple(sk, RTM_GETNETCONF, NLM_F_DUMP, &nc, sizeof(nc));
190 }
191 
192 static void netconf_dump_line(struct nl_object *obj, struct nl_dump_params *p)
193 {
194  struct rtnl_netconf *nc = (struct rtnl_netconf *) obj;
195  struct nl_cache *link_cache;
196  char buf[64];
197 
198  switch(nc->family) {
199  case AF_INET:
200  nl_dump(p, "ipv4 ");
201  break;
202  case AF_INET6:
203  nl_dump(p, "ipv6 ");
204  break;
205  case AF_MPLS:
206  nl_dump(p, "mpls ");
207  break;
208  default:
209  return;
210  }
211 
212  switch(nc->ifindex) {
213  case NETCONFA_IFINDEX_ALL:
214  nl_dump(p, "all ");
215  break;
216  case NETCONFA_IFINDEX_DEFAULT:
217  nl_dump(p, "default ");
218  break;
219  default:
220  link_cache = nl_cache_mngt_require_safe("route/link");
221  if (link_cache) {
222  nl_dump(p, "dev %s ",
223  rtnl_link_i2name(link_cache, nc->ifindex,
224  buf, sizeof(buf)));
225  nl_cache_put(link_cache);
226  } else
227  nl_dump(p, "dev %d ", nc->ifindex);
228  }
229 
230  if (nc->ce_mask & NETCONF_ATTR_FWDING) {
231  nl_dump(p, "forwarding %s ",
232  nc->forwarding ? "on" : "off");
233  }
234 
235  if (nc->ce_mask & NETCONF_ATTR_RP_FILTER) {
236  if (nc->rp_filter == 0)
237  nl_dump(p, "rp_filter off ");
238  else if (nc->rp_filter == 1)
239  nl_dump(p, "rp_filter strict ");
240  else if (nc->rp_filter == 2)
241  nl_dump(p, "rp_filter loose ");
242  else
243  nl_dump(p, "rp_filter unknown-mode ");
244  }
245 
246  if (nc->ce_mask & NETCONF_ATTR_MC_FWDING) {
247  nl_dump(p, "mc_forwarding %s ",
248  nc->mc_forwarding ? "on" : "off");
249  }
250 
251  if (nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)
252  nl_dump(p, "proxy_neigh %d ", nc->proxy_neigh);
253 
254  if (nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN) {
255  nl_dump(p, "ignore_routes_with_linkdown %s ",
256  nc->ignore_routes_linkdown ? "on" : "off");
257  }
258 
259  if (nc->ce_mask & NETCONF_ATTR_INPUT)
260  nl_dump(p, "input %s ", nc->input ? "on" : "off");
261 
262  nl_dump(p, "\n");
263 }
264 
265 static const struct trans_tbl netconf_attrs[] = {
266  __ADD(NETCONF_ATTR_FAMILY, family),
267  __ADD(NETCONF_ATTR_IFINDEX, ifindex),
268  __ADD(NETCONF_ATTR_RP_FILTER, rp_filter),
269  __ADD(NETCONF_ATTR_FWDING, forwarding),
270  __ADD(NETCONF_ATTR_MC_FWDING, mc_forwarding),
271  __ADD(NETCONF_ATTR_PROXY_NEIGH, proxy_neigh),
272  __ADD(NETCONF_ATTR_IGNORE_RT_LINKDWN, ignore_routes_with_linkdown),
273  __ADD(NETCONF_ATTR_INPUT, input),
274 };
275 
276 static char *netconf_attrs2str(int attrs, char *buf, size_t len)
277 {
278  return __flags2str(attrs, buf, len, netconf_attrs,
279  ARRAY_SIZE(netconf_attrs));
280 }
281 
282 static void netconf_keygen(struct nl_object *obj, uint32_t *hashkey,
283  uint32_t table_sz)
284 {
285  struct rtnl_netconf *nc = (struct rtnl_netconf *) obj;
286  unsigned int nckey_sz;
287  struct nc_hash_key {
288  int nc_family;
289  int nc_index;
290  } __attribute__((packed)) nckey;
291 
292  nckey_sz = sizeof(nckey);
293  nckey.nc_family = nc->family;
294  nckey.nc_index = nc->ifindex;
295 
296  *hashkey = nl_hash(&nckey, nckey_sz, 0) % table_sz;
297 
298  NL_DBG(5, "netconf %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
299  nc, nckey.nc_index, nckey.nc_family, nckey_sz, *hashkey);
300 }
301 
302 static uint64_t netconf_compare(struct nl_object *_a, struct nl_object *_b,
303  uint64_t attrs, int flags)
304 {
305  struct rtnl_netconf *a = (struct rtnl_netconf *) _a;
306  struct rtnl_netconf *b = (struct rtnl_netconf *) _b;
307  uint64_t diff = 0;
308 
309 #define NETCONF_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NETCONF_ATTR_##ATTR, a, b, EXPR)
310 
311  diff |= NETCONF_DIFF(FAMILY, a->family != b->family);
312  diff |= NETCONF_DIFF(IFINDEX, a->ifindex != b->ifindex);
313  diff |= NETCONF_DIFF(RP_FILTER, a->rp_filter != b->rp_filter);
314  diff |= NETCONF_DIFF(FWDING, a->forwarding != b->forwarding);
315  diff |= NETCONF_DIFF(MC_FWDING, a->mc_forwarding != b->mc_forwarding);
316  diff |= NETCONF_DIFF(PROXY_NEIGH, a->proxy_neigh != b->proxy_neigh);
317  diff |= NETCONF_DIFF(IGNORE_RT_LINKDWN,
318  a->ignore_routes_linkdown != b->ignore_routes_linkdown);
319  diff |= NETCONF_DIFF(INPUT, a->input != b->input);
320 
321 #undef NETCONF_DIFF
322 
323  return diff;
324 }
325 
326 static int netconf_update(struct nl_object *old_obj, struct nl_object *new_obj)
327 {
328  struct rtnl_netconf *new_nc = (struct rtnl_netconf *) new_obj;
329  struct rtnl_netconf *old_nc = (struct rtnl_netconf *) old_obj;
330  int action = new_obj->ce_msgtype;
331 
332  switch(action) {
333  case RTM_NEWNETCONF:
334  if (new_nc->family != old_nc->family ||
335  new_nc->ifindex != old_nc->ifindex)
336  return -NLE_OPNOTSUPP;
337 
338  if (new_nc->ce_mask & NETCONF_ATTR_RP_FILTER)
339  old_nc->rp_filter = new_nc->rp_filter;
340  if (new_nc->ce_mask & NETCONF_ATTR_FWDING)
341  old_nc->forwarding = new_nc->forwarding;
342  if (new_nc->ce_mask & NETCONF_ATTR_MC_FWDING)
343  old_nc->mc_forwarding = new_nc->mc_forwarding;
344  if (new_nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)
345  old_nc->proxy_neigh = new_nc->proxy_neigh;
346  if (new_nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN)
347  old_nc->ignore_routes_linkdown = new_nc->ignore_routes_linkdown;
348 
349  break;
350  default:
351  return -NLE_OPNOTSUPP;
352  }
353 
354  return NLE_SUCCESS;
355 }
356 
357 /**
358  * @name Cache Management
359  * @{
360  */
361 
362 int rtnl_netconf_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
363 {
364  return nl_cache_alloc_and_fill(&rtnl_netconf_ops, sk, result);
365 }
366 
367 /**
368  * Search netconf in cache
369  * @arg cache netconf cache
370  * @arg family Address family of interest
371  * @arg ifindex Interface index of interest
372  *
373  * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache()
374  * for given index and family
375  *
376  * The reference counter is incremented before returning the netconf entry,
377  * therefore the reference must be given back with rtnl_netconf_put() after
378  * usage.
379  *
380  * @return netconf object or NULL if no match was found.
381  */
382 struct rtnl_netconf *rtnl_netconf_get_by_idx(struct nl_cache *cache, int family,
383  int ifindex)
384 {
385  struct rtnl_netconf *nc;
386 
387  if (!ifindex || !family || cache->c_ops != &rtnl_netconf_ops)
388  return NULL;
389 
390  nl_list_for_each_entry(nc, &cache->c_items, ce_list) {
391  if (nc->ifindex == ifindex &&
392  nc->family == family) {
393  nl_object_get((struct nl_object *) nc);
394  return nc;
395  }
396  }
397 
398  return NULL;
399 }
400 
401 void rtnl_netconf_put(struct rtnl_netconf *nc)
402 {
403  nl_object_put((struct nl_object *) nc);
404 }
405 
406 /**
407  * Search netconf in cache
408  * @arg cache netconf cache
409  * @arg family Address family of interest
410  *
411  * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache()
412  * for "all" netconf settings for given family
413  *
414  * The reference counter is incremented before returning the netconf entry,
415  * therefore the reference must be given back with rtnl_netconf_put() after
416  * usage.
417  *
418  * @return netconf object or NULL if no match was found.
419  */
420 struct rtnl_netconf *rtnl_netconf_get_all(struct nl_cache *cache, int family)
421 {
422  return rtnl_netconf_get_by_idx(cache, family, NETCONFA_IFINDEX_ALL);
423 }
424 
425 /**
426  * Search netconf in cache
427  * @arg cache netconf cache
428  * @arg family Address family of interest
429  *
430  * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache()
431  * for "default" netconf settings for given family
432  *
433  * The reference counter is incremented before returning the netconf entry,
434  * therefore the reference must be given back with rtnl_netconf_put() after
435  * usage.
436  *
437  * @return netconf object or NULL if no match was found.
438  */
439 struct rtnl_netconf *rtnl_netconf_get_default(struct nl_cache *cache, int family)
440 {
441  return rtnl_netconf_get_by_idx(cache, family, NETCONFA_IFINDEX_DEFAULT);
442 }
443 
444 /** @} */
445 
446 /**
447  * @name Attributes
448  * @{
449  */
450 
451 int rtnl_netconf_get_family(struct rtnl_netconf *nc, int *val)
452 {
453  if (!nc)
454  return -NLE_INVAL;
455  if (!(nc->ce_mask & NETCONF_ATTR_FAMILY))
456  return -NLE_MISSING_ATTR;
457  if (val)
458  *val = nc->family;
459  return 0;
460 }
461 int rtnl_netconf_get_ifindex(struct rtnl_netconf *nc, int *val)
462 {
463  if (!nc)
464  return -NLE_INVAL;
465  if (!(nc->ce_mask & NETCONF_ATTR_IFINDEX))
466  return -NLE_MISSING_ATTR;
467  if (val)
468  *val = nc->ifindex;
469  return 0;
470 }
471 int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc, int *val)
472 {
473  if (!nc)
474  return -NLE_INVAL;
475  if (!(nc->ce_mask & NETCONF_ATTR_FWDING))
476  return -NLE_MISSING_ATTR;
477  if (val)
478  *val = nc->forwarding;
479  return 0;
480 }
481 int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc, int *val)
482 {
483  if (!nc)
484  return -NLE_INVAL;
485  if (!(nc->ce_mask & NETCONF_ATTR_MC_FWDING))
486  return -NLE_MISSING_ATTR;
487  if (val)
488  *val = nc->mc_forwarding;
489  return 0;
490 }
491 int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc, int *val)
492 {
493  if (!nc)
494  return -NLE_INVAL;
495  if (!(nc->ce_mask & NETCONF_ATTR_RP_FILTER))
496  return -NLE_MISSING_ATTR;
497  if (val)
498  *val = nc->rp_filter;
499  return 0;
500 }
501 int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc, int *val)
502 {
503  if (!nc)
504  return -NLE_INVAL;
505  if (!(nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH))
506  return -NLE_MISSING_ATTR;
507  if (val)
508  *val = nc->proxy_neigh;
509  return 0;
510 }
511 int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc, int *val)
512 {
513  if (!nc)
514  return -NLE_INVAL;
515  if (!(nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN))
516  return -NLE_MISSING_ATTR;
517  if (val)
518  *val = nc->ignore_routes_linkdown;
519  return 0;
520 }
521 int rtnl_netconf_get_input(struct rtnl_netconf *nc, int *val)
522 {
523  if (!nc)
524  return -NLE_INVAL;
525  if (!(nc->ce_mask & NETCONF_ATTR_INPUT))
526  return -NLE_MISSING_ATTR;
527  if (val)
528  *val = nc->input;
529  return 0;
530 }
531 
532 
533 /** @} */
534 
535 static struct nl_object_ops netconf_obj_ops = {
536  .oo_name = "route/netconf",
537  .oo_size = sizeof(struct rtnl_netconf),
538  .oo_clone = netconf_clone,
539  .oo_dump = {
540  [NL_DUMP_LINE] = netconf_dump_line,
541  [NL_DUMP_DETAILS] = netconf_dump_line,
542  },
543  .oo_compare = netconf_compare,
544  .oo_keygen = netconf_keygen,
545  .oo_update = netconf_update,
546  .oo_attrs2str = netconf_attrs2str,
547  .oo_id_attrs = (NETCONF_ATTR_FAMILY |
548  NETCONF_ATTR_IFINDEX)
549 };
550 
551 static struct nl_af_group netconf_groups[] = {
552  { AF_INET, RTNLGRP_IPV4_NETCONF },
553  { AF_INET6, RTNLGRP_IPV6_NETCONF },
554  { AF_MPLS, RTNLGRP_MPLS_NETCONF },
555  { END_OF_GROUP_LIST },
556 };
557 
558 static struct nl_cache_ops rtnl_netconf_ops = {
559  .co_name = "route/netconf",
560  .co_hdrsize = sizeof(struct netconfmsg),
561  .co_msgtypes = {
562  { RTM_NEWNETCONF, NL_ACT_NEW, "new" },
563  { RTM_DELNETCONF, NL_ACT_DEL, "del" },
564  { RTM_GETNETCONF, NL_ACT_GET, "get" },
565  END_OF_MSGTYPES_LIST,
566  },
567  .co_protocol = NETLINK_ROUTE,
568  .co_groups = netconf_groups,
569  .co_request_update = netconf_request_update,
570  .co_msg_parser = netconf_msg_parser,
571  .co_obj_ops = &netconf_obj_ops,
572 };
573 
574 static void __init netconf_init(void)
575 {
576  nl_cache_mngt_register(&rtnl_netconf_ops);
577 }
578 
579 static void __exit netconf_exit(void)
580 {
581  nl_cache_mngt_unregister(&rtnl_netconf_ops);
582 }
583 
584 /** @} */
Dump object briefly on one line.
Definition: types.h:22
int32_t nla_get_s32(const struct nlattr *nla)
Return payload of 32 bit signed integer attribute.
Definition: attr.c:682
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:215
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:107
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
Definition: object.c:55
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:288
Attribute validation policy.
Definition: attr.h:69
struct nl_cache * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
Definition: cache_mngt.c:431
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:205
struct rtnl_netconf * rtnl_netconf_get_by_idx(struct nl_cache *cache, int family, int ifindex)
Search netconf in cache.
Definition: netconf.c:382
Dump all attributes but no statistics.
Definition: types.h:23
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:253
struct rtnl_netconf * rtnl_netconf_get_all(struct nl_cache *cache, int family)
Search netconf in cache.
Definition: netconf.c:420
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size)
Construct and transmit a Netlink message.
Definition: nl.c:581
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:216
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:71
Dumping parameters.
Definition: types.h:33
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:962
struct rtnl_netconf * rtnl_netconf_get_default(struct nl_cache *cache, int family)
Search netconf in cache.
Definition: netconf.c:439
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, struct nl_cache **result)
Allocate new cache and fill it.
Definition: cache.c:234