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