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