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