libnl  3.2.28
route_obj.c
1 /*
2  * lib/route/route_obj.c Route Object
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) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup route
14  * @defgroup route_obj Route Object
15  *
16  * @par Attributes
17  * @code
18  * Name Default
19  * -------------------------------------------------------------
20  * routing table RT_TABLE_MAIN
21  * scope RT_SCOPE_NOWHERE
22  * tos 0
23  * protocol RTPROT_STATIC
24  * prio 0
25  * family AF_UNSPEC
26  * type RTN_UNICAST
27  * iif NULL
28  * @endcode
29  *
30  * @{
31  */
32 
33 #include <netlink-private/netlink.h>
34 #include <netlink/netlink.h>
35 #include <netlink/cache.h>
36 #include <netlink/utils.h>
37 #include <netlink/data.h>
38 #include <netlink/hashtable.h>
39 #include <netlink/route/rtnl.h>
40 #include <netlink/route/route.h>
41 #include <netlink/route/link.h>
42 #include <netlink/route/nexthop.h>
43 
44 /** @cond SKIP */
45 #define ROUTE_ATTR_FAMILY 0x000001
46 #define ROUTE_ATTR_TOS 0x000002
47 #define ROUTE_ATTR_TABLE 0x000004
48 #define ROUTE_ATTR_PROTOCOL 0x000008
49 #define ROUTE_ATTR_SCOPE 0x000010
50 #define ROUTE_ATTR_TYPE 0x000020
51 #define ROUTE_ATTR_FLAGS 0x000040
52 #define ROUTE_ATTR_DST 0x000080
53 #define ROUTE_ATTR_SRC 0x000100
54 #define ROUTE_ATTR_IIF 0x000200
55 #define ROUTE_ATTR_OIF 0x000400
56 #define ROUTE_ATTR_GATEWAY 0x000800
57 #define ROUTE_ATTR_PRIO 0x001000
58 #define ROUTE_ATTR_PREF_SRC 0x002000
59 #define ROUTE_ATTR_METRICS 0x004000
60 #define ROUTE_ATTR_MULTIPATH 0x008000
61 #define ROUTE_ATTR_REALMS 0x010000
62 #define ROUTE_ATTR_CACHEINFO 0x020000
63 /** @endcond */
64 
65 static void route_constructor(struct nl_object *c)
66 {
67  struct rtnl_route *r = (struct rtnl_route *) c;
68 
69  r->rt_family = AF_UNSPEC;
70  r->rt_scope = RT_SCOPE_NOWHERE;
71  r->rt_table = RT_TABLE_MAIN;
72  r->rt_protocol = RTPROT_STATIC;
73  r->rt_type = RTN_UNICAST;
74  r->rt_prio = 0;
75 
76  nl_init_list_head(&r->rt_nexthops);
77 }
78 
79 static void route_free_data(struct nl_object *c)
80 {
81  struct rtnl_route *r = (struct rtnl_route *) c;
82  struct rtnl_nexthop *nh, *tmp;
83 
84  if (r == NULL)
85  return;
86 
87  nl_addr_put(r->rt_dst);
88  nl_addr_put(r->rt_src);
89  nl_addr_put(r->rt_pref_src);
90 
91  nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
92  rtnl_route_remove_nexthop(r, nh);
93  rtnl_route_nh_free(nh);
94  }
95 }
96 
97 static int route_clone(struct nl_object *_dst, struct nl_object *_src)
98 {
99  struct rtnl_route *dst = (struct rtnl_route *) _dst;
100  struct rtnl_route *src = (struct rtnl_route *) _src;
101  struct rtnl_nexthop *nh, *new;
102 
103  if (src->rt_dst)
104  if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
105  return -NLE_NOMEM;
106 
107  if (src->rt_src)
108  if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
109  return -NLE_NOMEM;
110 
111  if (src->rt_pref_src)
112  if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
113  return -NLE_NOMEM;
114 
115  /* Will be inc'ed again while adding the nexthops of the source */
116  dst->rt_nr_nh = 0;
117 
118  nl_init_list_head(&dst->rt_nexthops);
119  nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
120  new = rtnl_route_nh_clone(nh);
121  if (!new)
122  return -NLE_NOMEM;
123 
124  rtnl_route_add_nexthop(dst, new);
125  }
126 
127  return 0;
128 }
129 
130 static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
131 {
132  struct rtnl_route *r = (struct rtnl_route *) a;
133  int cache = 0, flags;
134  char buf[64];
135 
136  if (r->rt_flags & RTM_F_CLONED)
137  cache = 1;
138 
139  nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
140 
141  if (cache)
142  nl_dump(p, "cache ");
143 
144  if (!(r->ce_mask & ROUTE_ATTR_DST) ||
145  nl_addr_get_len(r->rt_dst) == 0)
146  nl_dump(p, "default ");
147  else
148  nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
149 
150  if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
151  nl_dump(p, "table %s ",
152  rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
153 
154  if (r->ce_mask & ROUTE_ATTR_TYPE)
155  nl_dump(p, "type %s ",
156  nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
157 
158  if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
159  nl_dump(p, "tos %#x ", r->rt_tos);
160 
161  if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
162  struct rtnl_nexthop *nh;
163 
164  nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
165  p->dp_ivar = NH_DUMP_FROM_ONELINE;
166  rtnl_route_nh_dump(nh, p);
167  }
168  }
169 
170  flags = r->rt_flags & ~(RTM_F_CLONED);
171  if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
172 
173  nl_dump(p, "<");
174 
175 #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
176  flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
177  PRINT_FLAG(DEAD);
178  PRINT_FLAG(ONLINK);
179  PRINT_FLAG(PERVASIVE);
180 #undef PRINT_FLAG
181 
182 #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
183  flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
184  PRINT_FLAG(NOTIFY);
185  PRINT_FLAG(EQUALIZE);
186  PRINT_FLAG(PREFIX);
187 #undef PRINT_FLAG
188 
189 #define PRINT_FLAG(f) if (flags & RTCF_##f) { \
190  flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
191  PRINT_FLAG(NOTIFY);
192  PRINT_FLAG(REDIRECTED);
193  PRINT_FLAG(DOREDIRECT);
194  PRINT_FLAG(DIRECTSRC);
195  PRINT_FLAG(DNAT);
196  PRINT_FLAG(BROADCAST);
197  PRINT_FLAG(MULTICAST);
198  PRINT_FLAG(LOCAL);
199 #undef PRINT_FLAG
200 
201  nl_dump(p, ">");
202  }
203 
204  nl_dump(p, "\n");
205 }
206 
207 static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
208 {
209  struct rtnl_route *r = (struct rtnl_route *) a;
210  struct nl_cache *link_cache;
211  char buf[256];
212  int i;
213 
214  link_cache = nl_cache_mngt_require_safe("route/link");
215 
216  route_dump_line(a, p);
217  nl_dump_line(p, " ");
218 
219  if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
220  nl_dump(p, "preferred-src %s ",
221  nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
222 
223  if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
224  nl_dump(p, "scope %s ",
225  rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
226 
227  if (r->ce_mask & ROUTE_ATTR_PRIO)
228  nl_dump(p, "priority %#x ", r->rt_prio);
229 
230  if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
231  nl_dump(p, "protocol %s ",
232  rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
233 
234  if (r->ce_mask & ROUTE_ATTR_IIF) {
235  if (link_cache) {
236  nl_dump(p, "iif %s ",
237  rtnl_link_i2name(link_cache, r->rt_iif,
238  buf, sizeof(buf)));
239  } else
240  nl_dump(p, "iif %d ", r->rt_iif);
241  }
242 
243  if (r->ce_mask & ROUTE_ATTR_SRC)
244  nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
245 
246  nl_dump(p, "\n");
247 
248  if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
249  struct rtnl_nexthop *nh;
250 
251  nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
252  nl_dump_line(p, " ");
253  p->dp_ivar = NH_DUMP_FROM_DETAILS;
254  rtnl_route_nh_dump(nh, p);
255  nl_dump(p, "\n");
256  }
257  }
258 
259  if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
260  nl_dump_line(p, " cacheinfo error %d (%s)\n",
261  r->rt_cacheinfo.rtci_error,
262  strerror_r(-r->rt_cacheinfo.rtci_error, buf, sizeof(buf)));
263  }
264 
265  if (r->ce_mask & ROUTE_ATTR_METRICS) {
266  nl_dump_line(p, " metrics [");
267  for (i = 0; i < RTAX_MAX; i++)
268  if (r->rt_metrics_mask & (1 << i))
269  nl_dump(p, "%s %u ",
270  rtnl_route_metric2str(i+1,
271  buf, sizeof(buf)),
272  r->rt_metrics[i]);
273  nl_dump(p, "]\n");
274  }
275 
276  if (link_cache)
277  nl_cache_put(link_cache);
278 }
279 
280 static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
281 {
282  struct rtnl_route *route = (struct rtnl_route *) obj;
283 
284  route_dump_details(obj, p);
285 
286  if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
287  struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
288 
289  nl_dump_line(p, " used %u refcnt %u last-use %us "
290  "expires %us\n",
291  ci->rtci_used, ci->rtci_clntref,
292  ci->rtci_last_use / nl_get_user_hz(),
293  ci->rtci_expires / nl_get_user_hz());
294  }
295 }
296 
297 static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
298  uint32_t table_sz)
299 {
300  struct rtnl_route *route = (struct rtnl_route *) obj;
301  unsigned int rkey_sz;
302  struct nl_addr *addr = NULL;
303  struct route_hash_key {
304  uint8_t rt_family;
305  uint8_t rt_tos;
306  uint32_t rt_table;
307  uint32_t rt_prio;
308  char rt_addr[0];
309  } __attribute__((packed)) *rkey;
310 #ifdef NL_DEBUG
311  char buf[INET6_ADDRSTRLEN+5];
312 #endif
313 
314  if (route->rt_dst)
315  addr = route->rt_dst;
316 
317  rkey_sz = sizeof(*rkey);
318  if (addr)
319  rkey_sz += nl_addr_get_len(addr);
320  rkey = calloc(1, rkey_sz);
321  if (!rkey) {
322  NL_DBG(2, "Warning: calloc failed for %d bytes...\n", rkey_sz);
323  *hashkey = 0;
324  return;
325  }
326  rkey->rt_family = route->rt_family;
327  rkey->rt_tos = route->rt_tos;
328  rkey->rt_table = route->rt_table;
329  rkey->rt_prio = route->rt_prio;
330  if (addr)
331  memcpy(rkey->rt_addr, nl_addr_get_binary_addr(addr),
332  nl_addr_get_len(addr));
333 
334  *hashkey = nl_hash(rkey, rkey_sz, 0) % table_sz;
335 
336  NL_DBG(5, "route %p key (fam %d tos %d table %d addr %s) keysz %d "
337  "hash 0x%x\n", route, rkey->rt_family, rkey->rt_tos,
338  rkey->rt_table, nl_addr2str(addr, buf, sizeof(buf)),
339  rkey_sz, *hashkey);
340 
341  free(rkey);
342 
343  return;
344 }
345 
346 static uint64_t route_compare(struct nl_object *_a, struct nl_object *_b,
347  uint64_t attrs, int flags)
348 {
349  struct rtnl_route *a = (struct rtnl_route *) _a;
350  struct rtnl_route *b = (struct rtnl_route *) _b;
351  struct rtnl_nexthop *nh_a, *nh_b;
352  int i, found;
353  uint64_t diff = 0;
354 
355 #define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
356 
357  diff |= ROUTE_DIFF(FAMILY, a->rt_family != b->rt_family);
358  diff |= ROUTE_DIFF(TOS, a->rt_tos != b->rt_tos);
359  diff |= ROUTE_DIFF(TABLE, a->rt_table != b->rt_table);
360  diff |= ROUTE_DIFF(PROTOCOL, a->rt_protocol != b->rt_protocol);
361  diff |= ROUTE_DIFF(SCOPE, a->rt_scope != b->rt_scope);
362  diff |= ROUTE_DIFF(TYPE, a->rt_type != b->rt_type);
363  diff |= ROUTE_DIFF(PRIO, a->rt_prio != b->rt_prio);
364  diff |= ROUTE_DIFF(DST, nl_addr_cmp(a->rt_dst, b->rt_dst));
365  diff |= ROUTE_DIFF(SRC, nl_addr_cmp(a->rt_src, b->rt_src));
366  diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif);
367  diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src,
368  b->rt_pref_src));
369 
370  if (flags & LOOSE_COMPARISON) {
371  nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
372  found = 0;
373  nl_list_for_each_entry(nh_a, &a->rt_nexthops,
374  rtnh_list) {
375  if (!rtnl_route_nh_compare(nh_a, nh_b,
376  nh_b->ce_mask, 1)) {
377  found = 1;
378  break;
379  }
380  }
381 
382  if (!found)
383  goto nh_mismatch;
384  }
385 
386  for (i = 0; i < RTAX_MAX - 1; i++) {
387  if (a->rt_metrics_mask & (1 << i) &&
388  (!(b->rt_metrics_mask & (1 << i)) ||
389  a->rt_metrics[i] != b->rt_metrics[i]))
390  diff |= ROUTE_DIFF(METRICS, 1);
391  }
392 
393  diff |= ROUTE_DIFF(FLAGS,
394  (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
395  } else {
396  if (a->rt_nr_nh != b->rt_nr_nh)
397  goto nh_mismatch;
398 
399  /* search for a dup in each nh of a */
400  nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
401  found = 0;
402  nl_list_for_each_entry(nh_b, &b->rt_nexthops,
403  rtnh_list) {
404  if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) {
405  found = 1;
406  break;
407  }
408  }
409  if (!found)
410  goto nh_mismatch;
411  }
412 
413  /* search for a dup in each nh of b, covers case where a has
414  * dupes itself */
415  nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
416  found = 0;
417  nl_list_for_each_entry(nh_a, &a->rt_nexthops,
418  rtnh_list) {
419  if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) {
420  found = 1;
421  break;
422  }
423  }
424  if (!found)
425  goto nh_mismatch;
426  }
427 
428  for (i = 0; i < RTAX_MAX - 1; i++) {
429  if ((a->rt_metrics_mask & (1 << i)) ^
430  (b->rt_metrics_mask & (1 << i)))
431  diff |= ROUTE_DIFF(METRICS, 1);
432  else
433  diff |= ROUTE_DIFF(METRICS,
434  a->rt_metrics[i] != b->rt_metrics[i]);
435  }
436 
437  diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
438  }
439 
440 out:
441  return diff;
442 
443 nh_mismatch:
444  diff |= ROUTE_DIFF(MULTIPATH, 1);
445  goto out;
446 
447 #undef ROUTE_DIFF
448 }
449 
450 static int route_update(struct nl_object *old_obj, struct nl_object *new_obj)
451 {
452  struct rtnl_route *new_route = (struct rtnl_route *) new_obj;
453  struct rtnl_route *old_route = (struct rtnl_route *) old_obj;
454  struct rtnl_nexthop *new_nh;
455  int action = new_obj->ce_msgtype;
456 #ifdef NL_DEBUG
457  char buf[INET6_ADDRSTRLEN+5];
458 #endif
459 
460  /*
461  * ipv6 ECMP route notifications from the kernel come as
462  * separate notifications, one for every nexthop. This update
463  * function collapses such route msgs into a single
464  * route with multiple nexthops. The resulting object looks
465  * similar to a ipv4 ECMP route
466  */
467  if (new_route->rt_family != AF_INET6 ||
468  new_route->rt_table == RT_TABLE_LOCAL)
469  return -NLE_OPNOTSUPP;
470 
471  /*
472  * For routes that are already multipath,
473  * or dont have a nexthop dont do anything
474  */
475  if (rtnl_route_get_nnexthops(new_route) != 1)
476  return -NLE_OPNOTSUPP;
477 
478  /*
479  * Get the only nexthop entry from the new route. For
480  * IPv6 we always get a route with a 0th NH
481  * filled or nothing at all
482  */
483  new_nh = rtnl_route_nexthop_n(new_route, 0);
484  if (!new_nh || !rtnl_route_nh_get_gateway(new_nh))
485  return -NLE_OPNOTSUPP;
486 
487  switch(action) {
488  case RTM_NEWROUTE : {
489  struct rtnl_nexthop *cloned_nh;
490 
491  /*
492  * Add the nexthop to old route
493  */
494  cloned_nh = rtnl_route_nh_clone(new_nh);
495  if (!cloned_nh)
496  return -NLE_NOMEM;
497  rtnl_route_add_nexthop(old_route, cloned_nh);
498 
499  NL_DBG(2, "Route obj %p updated. Added "
500  "nexthop %p via %s\n", old_route, cloned_nh,
501  nl_addr2str(cloned_nh->rtnh_gateway, buf,
502  sizeof(buf)));
503  }
504  break;
505  case RTM_DELROUTE : {
506  struct rtnl_nexthop *old_nh;
507 
508  /*
509  * Only take care of nexthop deletes and not
510  * route deletes. So, if there is only one nexthop
511  * quite likely we did not update it. So dont do
512  * anything and return
513  */
514  if (rtnl_route_get_nnexthops(old_route) <= 1)
515  return -NLE_OPNOTSUPP;
516 
517  /*
518  * Find the next hop in old route and delete it
519  */
520  nl_list_for_each_entry(old_nh, &old_route->rt_nexthops,
521  rtnh_list) {
522  if (!rtnl_route_nh_compare(old_nh, new_nh, ~0, 0)) {
523 
524  rtnl_route_remove_nexthop(old_route, old_nh);
525 
526  NL_DBG(2, "Route obj %p updated. Removed "
527  "nexthop %p via %s\n", old_route,
528  old_nh,
529  nl_addr2str(old_nh->rtnh_gateway, buf,
530  sizeof(buf)));
531 
532  rtnl_route_nh_free(old_nh);
533  break;
534  }
535  }
536  }
537  break;
538  default:
539  NL_DBG(2, "Unknown action associated "
540  "to object %p during route update\n", new_obj);
541  return -NLE_OPNOTSUPP;
542  }
543 
544  return NLE_SUCCESS;
545 }
546 
547 static const struct trans_tbl route_attrs[] = {
548  __ADD(ROUTE_ATTR_FAMILY, family),
549  __ADD(ROUTE_ATTR_TOS, tos),
550  __ADD(ROUTE_ATTR_TABLE, table),
551  __ADD(ROUTE_ATTR_PROTOCOL, protocol),
552  __ADD(ROUTE_ATTR_SCOPE, scope),
553  __ADD(ROUTE_ATTR_TYPE, type),
554  __ADD(ROUTE_ATTR_FLAGS, flags),
555  __ADD(ROUTE_ATTR_DST, dst),
556  __ADD(ROUTE_ATTR_SRC, src),
557  __ADD(ROUTE_ATTR_IIF, iif),
558  __ADD(ROUTE_ATTR_OIF, oif),
559  __ADD(ROUTE_ATTR_GATEWAY, gateway),
560  __ADD(ROUTE_ATTR_PRIO, prio),
561  __ADD(ROUTE_ATTR_PREF_SRC, pref_src),
562  __ADD(ROUTE_ATTR_METRICS, metrics),
563  __ADD(ROUTE_ATTR_MULTIPATH, multipath),
564  __ADD(ROUTE_ATTR_REALMS, realms),
565  __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo),
566 };
567 
568 static char *route_attrs2str(int attrs, char *buf, size_t len)
569 {
570  return __flags2str(attrs, buf, len, route_attrs,
571  ARRAY_SIZE(route_attrs));
572 }
573 
574 /**
575  * @name Allocation/Freeing
576  * @{
577  */
578 
579 struct rtnl_route *rtnl_route_alloc(void)
580 {
581  return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
582 }
583 
584 void rtnl_route_get(struct rtnl_route *route)
585 {
586  nl_object_get((struct nl_object *) route);
587 }
588 
589 void rtnl_route_put(struct rtnl_route *route)
590 {
591  nl_object_put((struct nl_object *) route);
592 }
593 
594 /** @} */
595 
596 /**
597  * @name Attributes
598  * @{
599  */
600 
601 void rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
602 {
603  route->rt_table = table;
604  route->ce_mask |= ROUTE_ATTR_TABLE;
605 }
606 
607 uint32_t rtnl_route_get_table(struct rtnl_route *route)
608 {
609  return route->rt_table;
610 }
611 
612 void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
613 {
614  route->rt_scope = scope;
615  route->ce_mask |= ROUTE_ATTR_SCOPE;
616 }
617 
618 uint8_t rtnl_route_get_scope(struct rtnl_route *route)
619 {
620  return route->rt_scope;
621 }
622 
623 void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
624 {
625  route->rt_tos = tos;
626  route->ce_mask |= ROUTE_ATTR_TOS;
627 }
628 
629 uint8_t rtnl_route_get_tos(struct rtnl_route *route)
630 {
631  return route->rt_tos;
632 }
633 
634 void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
635 {
636  route->rt_protocol = protocol;
637  route->ce_mask |= ROUTE_ATTR_PROTOCOL;
638 }
639 
640 uint8_t rtnl_route_get_protocol(struct rtnl_route *route)
641 {
642  return route->rt_protocol;
643 }
644 
645 void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
646 {
647  route->rt_prio = prio;
648  route->ce_mask |= ROUTE_ATTR_PRIO;
649 }
650 
651 uint32_t rtnl_route_get_priority(struct rtnl_route *route)
652 {
653  return route->rt_prio;
654 }
655 
656 int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
657 {
658  if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
659  return -NLE_AF_NOSUPPORT;
660 
661  route->rt_family = family;
662  route->ce_mask |= ROUTE_ATTR_FAMILY;
663 
664  return 0;
665 }
666 
667 uint8_t rtnl_route_get_family(struct rtnl_route *route)
668 {
669  return route->rt_family;
670 }
671 
672 int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
673 {
674  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
675  if (addr->a_family != route->rt_family)
676  return -NLE_AF_MISMATCH;
677  } else
678  route->rt_family = addr->a_family;
679 
680  if (route->rt_dst)
681  nl_addr_put(route->rt_dst);
682 
683  nl_addr_get(addr);
684  route->rt_dst = addr;
685 
686  route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
687 
688  return 0;
689 }
690 
691 struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
692 {
693  return route->rt_dst;
694 }
695 
696 int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
697 {
698  if (addr->a_family == AF_INET)
699  return -NLE_SRCRT_NOSUPPORT;
700 
701  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
702  if (addr->a_family != route->rt_family)
703  return -NLE_AF_MISMATCH;
704  } else
705  route->rt_family = addr->a_family;
706 
707  if (route->rt_src)
708  nl_addr_put(route->rt_src);
709 
710  nl_addr_get(addr);
711  route->rt_src = addr;
712  route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
713 
714  return 0;
715 }
716 
717 struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
718 {
719  return route->rt_src;
720 }
721 
722 int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
723 {
724  if (type > RTN_MAX)
725  return -NLE_RANGE;
726 
727  route->rt_type = type;
728  route->ce_mask |= ROUTE_ATTR_TYPE;
729 
730  return 0;
731 }
732 
733 uint8_t rtnl_route_get_type(struct rtnl_route *route)
734 {
735  return route->rt_type;
736 }
737 
738 void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
739 {
740  route->rt_flag_mask |= flags;
741  route->rt_flags |= flags;
742  route->ce_mask |= ROUTE_ATTR_FLAGS;
743 }
744 
745 void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
746 {
747  route->rt_flag_mask |= flags;
748  route->rt_flags &= ~flags;
749  route->ce_mask |= ROUTE_ATTR_FLAGS;
750 }
751 
752 uint32_t rtnl_route_get_flags(struct rtnl_route *route)
753 {
754  return route->rt_flags;
755 }
756 
757 int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
758 {
759  if (metric > RTAX_MAX || metric < 1)
760  return -NLE_RANGE;
761 
762  route->rt_metrics[metric - 1] = value;
763 
764  if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
765  route->rt_nmetrics++;
766  route->rt_metrics_mask |= (1 << (metric - 1));
767  }
768 
769  route->ce_mask |= ROUTE_ATTR_METRICS;
770 
771  return 0;
772 }
773 
774 int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
775 {
776  if (metric > RTAX_MAX || metric < 1)
777  return -NLE_RANGE;
778 
779  if (route->rt_metrics_mask & (1 << (metric - 1))) {
780  route->rt_nmetrics--;
781  route->rt_metrics_mask &= ~(1 << (metric - 1));
782  }
783 
784  return 0;
785 }
786 
787 int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
788 {
789  if (metric > RTAX_MAX || metric < 1)
790  return -NLE_RANGE;
791 
792  if (!(route->rt_metrics_mask & (1 << (metric - 1))))
793  return -NLE_OBJ_NOTFOUND;
794 
795  if (value)
796  *value = route->rt_metrics[metric - 1];
797 
798  return 0;
799 }
800 
801 int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
802 {
803  if (route->ce_mask & ROUTE_ATTR_FAMILY) {
804  if (addr->a_family != route->rt_family)
805  return -NLE_AF_MISMATCH;
806  } else
807  route->rt_family = addr->a_family;
808 
809  if (route->rt_pref_src)
810  nl_addr_put(route->rt_pref_src);
811 
812  nl_addr_get(addr);
813  route->rt_pref_src = addr;
814  route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
815 
816  return 0;
817 }
818 
819 struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
820 {
821  return route->rt_pref_src;
822 }
823 
824 void rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
825 {
826  route->rt_iif = ifindex;
827  route->ce_mask |= ROUTE_ATTR_IIF;
828 }
829 
830 int rtnl_route_get_iif(struct rtnl_route *route)
831 {
832  return route->rt_iif;
833 }
834 
835 void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
836 {
837  nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
838  route->rt_nr_nh++;
839  route->ce_mask |= ROUTE_ATTR_MULTIPATH;
840 }
841 
842 void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
843 {
844  if (route->ce_mask & ROUTE_ATTR_MULTIPATH) {
845  route->rt_nr_nh--;
846  nl_list_del(&nh->rtnh_list);
847  }
848 }
849 
850 struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
851 {
852  if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
853  return &route->rt_nexthops;
854 
855  return NULL;
856 }
857 
858 int rtnl_route_get_nnexthops(struct rtnl_route *route)
859 {
860  if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
861  return route->rt_nr_nh;
862 
863  return 0;
864 }
865 
866 void rtnl_route_foreach_nexthop(struct rtnl_route *r,
867  void (*cb)(struct rtnl_nexthop *, void *),
868  void *arg)
869 {
870  struct rtnl_nexthop *nh;
871 
872  if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
873  nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
874  cb(nh, arg);
875  }
876  }
877 }
878 
879 struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
880 {
881  struct rtnl_nexthop *nh;
882  uint32_t i;
883 
884  if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
885  i = 0;
886  nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
887  if (i == n) return nh;
888  i++;
889  }
890  }
891  return NULL;
892 }
893 
894 /** @} */
895 
896 /**
897  * @name Utilities
898  * @{
899  */
900 
901 /**
902  * Guess scope of a route object.
903  * @arg route Route object.
904  *
905  * Guesses the scope of a route object, based on the following rules:
906  * @code
907  * 1) Local route -> local scope
908  * 2) At least one nexthop not directly connected -> universe scope
909  * 3) All others -> link scope
910  * @endcode
911  *
912  * @return Scope value.
913  */
914 int rtnl_route_guess_scope(struct rtnl_route *route)
915 {
916  if (route->rt_type == RTN_LOCAL)
917  return RT_SCOPE_HOST;
918 
919  if (!nl_list_empty(&route->rt_nexthops)) {
920  struct rtnl_nexthop *nh;
921 
922  /*
923  * Use scope uiniverse if there is at least one nexthop which
924  * is not directly connected
925  */
926  nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
927  if (nh->rtnh_gateway)
928  return RT_SCOPE_UNIVERSE;
929  }
930  }
931 
932  return RT_SCOPE_LINK;
933 }
934 
935 /** @} */
936 
937 static struct nla_policy route_policy[RTA_MAX+1] = {
938  [RTA_IIF] = { .type = NLA_U32 },
939  [RTA_OIF] = { .type = NLA_U32 },
940  [RTA_PRIORITY] = { .type = NLA_U32 },
941  [RTA_FLOW] = { .type = NLA_U32 },
942  [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
943  [RTA_METRICS] = { .type = NLA_NESTED },
944  [RTA_MULTIPATH] = { .type = NLA_NESTED },
945 };
946 
947 static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
948 {
949  struct rtnl_nexthop *nh = NULL;
950  struct rtnexthop *rtnh = nla_data(attr);
951  size_t tlen = nla_len(attr);
952  int err;
953 
954  while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
955  nh = rtnl_route_nh_alloc();
956  if (!nh)
957  return -NLE_NOMEM;
958 
959  rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
960  rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
961  rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
962 
963  if (rtnh->rtnh_len > sizeof(*rtnh)) {
964  struct nlattr *ntb[RTA_MAX + 1];
965 
966  err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
967  RTNH_DATA(rtnh),
968  rtnh->rtnh_len - sizeof(*rtnh),
969  route_policy);
970  if (err < 0)
971  goto errout;
972 
973  if (ntb[RTA_GATEWAY]) {
974  struct nl_addr *addr;
975 
976  addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
977  route->rt_family);
978  if (!addr) {
979  err = -NLE_NOMEM;
980  goto errout;
981  }
982 
983  rtnl_route_nh_set_gateway(nh, addr);
984  nl_addr_put(addr);
985  }
986 
987  if (ntb[RTA_FLOW]) {
988  uint32_t realms;
989 
990  realms = nla_get_u32(ntb[RTA_FLOW]);
991  rtnl_route_nh_set_realms(nh, realms);
992  }
993  }
994 
995  rtnl_route_add_nexthop(route, nh);
996  tlen -= RTNH_ALIGN(rtnh->rtnh_len);
997  rtnh = RTNH_NEXT(rtnh);
998  }
999 
1000  err = 0;
1001 errout:
1002  if (err && nh)
1003  rtnl_route_nh_free(nh);
1004 
1005  return err;
1006 }
1007 
1008 int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
1009 {
1010  struct rtmsg *rtm;
1011  struct rtnl_route *route;
1012  struct nlattr *tb[RTA_MAX + 1];
1013  struct nl_addr *src = NULL, *dst = NULL, *addr;
1014  struct rtnl_nexthop *old_nh = NULL;
1015  int err, family;
1016 
1017  route = rtnl_route_alloc();
1018  if (!route) {
1019  err = -NLE_NOMEM;
1020  goto errout;
1021  }
1022 
1023  route->ce_msgtype = nlh->nlmsg_type;
1024 
1025  err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
1026  if (err < 0)
1027  goto errout;
1028 
1029  rtm = nlmsg_data(nlh);
1030  route->rt_family = family = rtm->rtm_family;
1031  route->rt_tos = rtm->rtm_tos;
1032  route->rt_table = rtm->rtm_table;
1033  route->rt_type = rtm->rtm_type;
1034  route->rt_scope = rtm->rtm_scope;
1035  route->rt_protocol = rtm->rtm_protocol;
1036  route->rt_flags = rtm->rtm_flags;
1037  route->rt_prio = 0;
1038 
1039  route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
1040  ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
1041  ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
1042  ROUTE_ATTR_FLAGS | ROUTE_ATTR_PRIO;
1043 
1044  if (tb[RTA_DST]) {
1045  if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
1046  goto errout_nomem;
1047  } else {
1048  if (!(dst = nl_addr_alloc(0)))
1049  goto errout_nomem;
1050  nl_addr_set_family(dst, rtm->rtm_family);
1051  }
1052 
1053  nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
1054  err = rtnl_route_set_dst(route, dst);
1055  if (err < 0)
1056  goto errout;
1057 
1058  nl_addr_put(dst);
1059 
1060  if (tb[RTA_SRC]) {
1061  if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
1062  goto errout_nomem;
1063  } else if (rtm->rtm_src_len)
1064  if (!(src = nl_addr_alloc(0)))
1065  goto errout_nomem;
1066 
1067  if (src) {
1068  nl_addr_set_prefixlen(src, rtm->rtm_src_len);
1069  rtnl_route_set_src(route, src);
1070  nl_addr_put(src);
1071  }
1072 
1073  if (tb[RTA_TABLE])
1074  rtnl_route_set_table(route, nla_get_u32(tb[RTA_TABLE]));
1075 
1076  if (tb[RTA_IIF])
1077  rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
1078 
1079  if (tb[RTA_PRIORITY])
1080  rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
1081 
1082  if (tb[RTA_PREFSRC]) {
1083  if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
1084  goto errout_nomem;
1085  rtnl_route_set_pref_src(route, addr);
1086  nl_addr_put(addr);
1087  }
1088 
1089  if (tb[RTA_METRICS]) {
1090  struct nlattr *mtb[RTAX_MAX + 1];
1091  int i;
1092 
1093  err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
1094  if (err < 0)
1095  goto errout;
1096 
1097  for (i = 1; i <= RTAX_MAX; i++) {
1098  if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
1099  uint32_t m = nla_get_u32(mtb[i]);
1100  if (rtnl_route_set_metric(route, i, m) < 0)
1101  goto errout;
1102  }
1103  }
1104  }
1105 
1106  if (tb[RTA_MULTIPATH])
1107  if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
1108  goto errout;
1109 
1110  if (tb[RTA_CACHEINFO]) {
1111  nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
1112  sizeof(route->rt_cacheinfo));
1113  route->ce_mask |= ROUTE_ATTR_CACHEINFO;
1114  }
1115 
1116  if (tb[RTA_OIF]) {
1117  if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1118  goto errout;
1119 
1120  rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
1121  }
1122 
1123  if (tb[RTA_GATEWAY]) {
1124  if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1125  goto errout;
1126 
1127  if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
1128  goto errout_nomem;
1129 
1130  rtnl_route_nh_set_gateway(old_nh, addr);
1131  nl_addr_put(addr);
1132  }
1133 
1134  if (tb[RTA_FLOW]) {
1135  if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1136  goto errout;
1137 
1138  rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
1139  }
1140 
1141  if (old_nh) {
1142  rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
1143  if (route->rt_nr_nh == 0) {
1144  /* If no nexthops have been provided via RTA_MULTIPATH
1145  * we add it as regular nexthop to maintain backwards
1146  * compatibility */
1147  rtnl_route_add_nexthop(route, old_nh);
1148  } else {
1149  /* Kernel supports new style nexthop configuration,
1150  * verify that it is a duplicate and discard nexthop. */
1151  struct rtnl_nexthop *first;
1152 
1153  first = nl_list_first_entry(&route->rt_nexthops,
1154  struct rtnl_nexthop,
1155  rtnh_list);
1156  if (!first)
1157  BUG();
1158 
1159  if (rtnl_route_nh_compare(old_nh, first,
1160  old_nh->ce_mask, 0)) {
1161  err = -NLE_INVAL;
1162  goto errout;
1163  }
1164 
1165  rtnl_route_nh_free(old_nh);
1166  }
1167  }
1168 
1169  *result = route;
1170  return 0;
1171 
1172 errout:
1173  rtnl_route_put(route);
1174  return err;
1175 
1176 errout_nomem:
1177  err = -NLE_NOMEM;
1178  goto errout;
1179 }
1180 
1181 int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
1182 {
1183  int i;
1184  struct nlattr *metrics;
1185  struct rtmsg rtmsg = {
1186  .rtm_family = route->rt_family,
1187  .rtm_tos = route->rt_tos,
1188  .rtm_table = route->rt_table,
1189  .rtm_protocol = route->rt_protocol,
1190  .rtm_scope = route->rt_scope,
1191  .rtm_type = route->rt_type,
1192  .rtm_flags = route->rt_flags,
1193  };
1194 
1195  if (route->rt_dst == NULL)
1196  return -NLE_MISSING_ATTR;
1197 
1198  rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
1199  if (route->rt_src)
1200  rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
1201 
1202  if (!(route->ce_mask & ROUTE_ATTR_SCOPE))
1203  rtmsg.rtm_scope = rtnl_route_guess_scope(route);
1204 
1205  if (rtnl_route_get_nnexthops(route) == 1) {
1206  struct rtnl_nexthop *nh;
1207  nh = rtnl_route_nexthop_n(route, 0);
1208  rtmsg.rtm_flags |= nh->rtnh_flags;
1209  }
1210 
1211  if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
1212  goto nla_put_failure;
1213 
1214  /* Additional table attribute replacing the 8bit in the header, was
1215  * required to allow more than 256 tables. */
1216  NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
1217 
1218  if (nl_addr_get_len(route->rt_dst))
1219  NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
1220  NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
1221 
1222  if (route->ce_mask & ROUTE_ATTR_SRC)
1223  NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
1224 
1225  if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
1226  NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
1227 
1228  if (route->ce_mask & ROUTE_ATTR_IIF)
1229  NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
1230 
1231  if (route->rt_nmetrics > 0) {
1232  uint32_t val;
1233 
1234  metrics = nla_nest_start(msg, RTA_METRICS);
1235  if (metrics == NULL)
1236  goto nla_put_failure;
1237 
1238  for (i = 1; i <= RTAX_MAX; i++) {
1239  if (!rtnl_route_get_metric(route, i, &val))
1240  NLA_PUT_U32(msg, i, val);
1241  }
1242 
1243  nla_nest_end(msg, metrics);
1244  }
1245 
1246  if (rtnl_route_get_nnexthops(route) == 1) {
1247  struct rtnl_nexthop *nh;
1248 
1249  nh = rtnl_route_nexthop_n(route, 0);
1250  if (nh->rtnh_gateway)
1251  NLA_PUT_ADDR(msg, RTA_GATEWAY, nh->rtnh_gateway);
1252  if (nh->rtnh_ifindex)
1253  NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex);
1254  if (nh->rtnh_realms)
1255  NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
1256  } else if (rtnl_route_get_nnexthops(route) > 1) {
1257  struct nlattr *multipath;
1258  struct rtnl_nexthop *nh;
1259 
1260  if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
1261  goto nla_put_failure;
1262 
1263  nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
1264  struct rtnexthop *rtnh;
1265 
1266  rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
1267  if (!rtnh)
1268  goto nla_put_failure;
1269 
1270  rtnh->rtnh_flags = nh->rtnh_flags;
1271  rtnh->rtnh_hops = nh->rtnh_weight;
1272  rtnh->rtnh_ifindex = nh->rtnh_ifindex;
1273 
1274  if (nh->rtnh_gateway)
1275  NLA_PUT_ADDR(msg, RTA_GATEWAY,
1276  nh->rtnh_gateway);
1277 
1278  if (nh->rtnh_realms)
1279  NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
1280 
1281  rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
1282  (void *) rtnh;
1283  }
1284 
1285  nla_nest_end(msg, multipath);
1286  }
1287 
1288  return 0;
1289 
1290 nla_put_failure:
1291  return -NLE_MSGSIZE;
1292 }
1293 
1294 /** @cond SKIP */
1295 struct nl_object_ops route_obj_ops = {
1296  .oo_name = "route/route",
1297  .oo_size = sizeof(struct rtnl_route),
1298  .oo_constructor = route_constructor,
1299  .oo_free_data = route_free_data,
1300  .oo_clone = route_clone,
1301  .oo_dump = {
1302  [NL_DUMP_LINE] = route_dump_line,
1303  [NL_DUMP_DETAILS] = route_dump_details,
1304  [NL_DUMP_STATS] = route_dump_stats,
1305  },
1306  .oo_compare = route_compare,
1307  .oo_keygen = route_keygen,
1308  .oo_update = route_update,
1309  .oo_attrs2str = route_attrs2str,
1310  .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
1311  ROUTE_ATTR_TABLE | ROUTE_ATTR_DST |
1312  ROUTE_ATTR_PRIO),
1313 };
1314 /** @endcond */
1315 
1316 /** @} */
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:471
Dump object briefly on one line.
Definition: types.h:22
struct nl_addr * nl_addr_alloc(size_t maxsize)
Allocate empty abstract address.
Definition: addr.c:185
int nl_get_user_hz(void)
Return the value of HZ.
Definition: utils.c:465
void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
Set the prefix length of an abstract address.
Definition: addr.c:917
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition: addr.c:563
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:105
#define NLA_PUT_ADDR(msg, attrtype, addr)
Add address attribute to netlink message.
Definition: attr.h:286
unsigned int nl_addr_get_prefixlen(const struct nl_addr *addr)
Return prefix length of abstract address object.
Definition: addr.c:928
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
void * nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
Reserve room for additional data in a netlink message.
Definition: msg.c:407
Attribute validation policy.
Definition: attr.h:67
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
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
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:213
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:501
void nl_addr_set_family(struct nl_addr *addr, int family)
Set address family.
Definition: addr.c:832
struct nl_addr * nl_addr_alloc_attr(const struct nlattr *nla, int family)
Allocate abstract address based on Netlink attribute.
Definition: addr.c:255
Dump all attributes but no statistics.
Definition: types.h:23
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:917
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:353
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:992
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:120
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:233
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:131
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, struct nla_policy *policy)
Create attribute index based on a stream of attributes.
Definition: attr.c:242
int rtnl_route_guess_scope(struct rtnl_route *route)
Guess scope of a route object.
Definition: route_obj.c:914
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:442
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:215
Nested attributes.
Definition: attr.h:46
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:517
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:69
32 bit integer
Definition: attr.h:41
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:914
unsigned int nl_addr_get_len(const struct nl_addr *addr)
Get length of binary address of abstract address object.
Definition: addr.c:905
int dp_ivar
PRIVATE Owned by the current caller.
Definition: types.h:105
Dump all attributes including statistics.
Definition: types.h:24
void * nl_addr_get_binary_addr(const struct nl_addr *addr)
Get binary address of abstract address object.
Definition: addr.c:893
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:895
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:951